修改点:

1. decode('gbk')修改为decode('gbk','replace'),在遇到不能识别的字符时直接用?替换

2. 将原来的单线程变为多线程,现在处理速度快了好多

  1 #! /bin/python
  2 # -*- coding:utf-8 -*-
  3
  4 # --------------------------------------------
  5 #     程序:【23hh小说网】爬虫
  6 #     版本:0.2.2
  7 #     作者:Silence
  8 #     日期:2014-04-08
  9 #     功能:1. 提供一个目录页,把这个小说的全部章节都抓取下来,保存为一个文件
 10 #         2. 提供一个正在看的目录页,把这个章节及以后的所有章节都抓取下来,
 11 #          3. 增加错误时的重试机制
 12 # ---------------------------------------------
 13 import threading
 14 import urllib2
 15 import re
 16 import os
 17 from Queue import Queue
 18
 19 class Spider_Thread(threading.Thread):
 20     """单进程的爬网页很耗时的,所以考虑做成多进程的
 21         参数通过queue来传递"""
 22
 23     def __init__(self, t_name,queue):
 24         threading.Thread.__init__(self ,name = t_name)
 25         self.data = queue
 26         self.errorInfo = {}
 27
 28     def run(self):
 29         while self.data.qsize() > 0:
 30             pageInfo = self.data.get()
 31             print '线程%s正在爬第%d个页面'%(self.getName(),pageInfo.keys()[0])
 32             try:
 33                 self.novel = Novel_Tool(pageInfo.values()[0]['pageurl'],'N')
 34                 decodePageResp = self.novel.getDecodePage(pageInfo.values()[0]['pageurl'])
 35                 pageContent = self.novel.getPageContent(decodePageResp)
 36                 self.novel.writeToFile(pageContent,pageInfo.values()[0]['pagename'])
 37             except Exception,e:
 38                 print '爬第%d个页面时出错了' %pageInfo.keys()[0]
 39                 self.errorInfo[pageInfo.keys()[0]] = pageInfo.values()
 40                 pass
 41         if self.errorInfo.__len__() > 0:
 42             print '出错的页面信息有:\n',self.errorInfo
 43         self.novel = None
 44
 45
 46 # 主要是用来提供一些公用的方法,不作为主函数调用
 47 class Novel_Tool():
 48
 49     def __init__(self,weburl,saveAsOne):
 50         self.url = weburl
 51         self.headers = {
 52             'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'
 53         }
 54         self.saveAsOne = saveAsOne
 55         self.pagesInfo = {}
 56         self.errorPage = []
 57
 58     #获取当前页面的编码格式,现在某些小说网喜欢用gbk来编码
 59     # 但是,也有一些不厚道的网站,他们的实际编码格式不是在页面中charset中定义的格式,暂时先忽略了
 60     def getPageType(self,content):
 61         pattern = re.compile('charset=.*?"')
 62         pagetype = pattern.search(content).group()
 63         pagetype = pagetype[8:len(pagetype) - 1]
 64         return pagetype
 65
 66     def start(self):
 67         if novelUrl.find('html') > 0:
 68             self.spiderPagesFromCurrent()
 69         else:
 70             pageInfos = self.getAllUrlsAndNames()
 71             self.spiderAllPagesFromOne(pageInfos)
 72         self.doStat()
 73
 74     def doStat(self):
 75         print '本次共尝试爬章节 %d,其中爬成功章节数 %d' %(self.pageInfos.__len__(),self.pageInfos.__len__() - self.errorPage.__len__())
 76         print '失败的章节信息为:',errorPage
 77
 78     def retryErroePage(self,errorPages):
 79         print '准备重试错误页面中....'
 80         self.spiderAllPagesFromOne(errorPages)
 81
 82     def spiderPagesFromCurrent(self):
 83         pageurl = self.url
 84         index = 1
 85         while pageurl.find('index.html') == -1:
 86             try:
 87                 decodePageResp = self.getDecodePage(pageurl)
 88                 pageContent = self.getPageContent(decodePageResp)
 89
 90                 self.writeToFile(pageContent,self.getPageTitle(decodePageResp))
 91                 pageurl = self.getNextPage(decodePageResp)
 92             except Exception,e:
 93                 print '爬第%d个页面时出错了' %index
 94                 self.errorPage = {index:pageInfo['pageurl']}
 95                 pass
 96             finally:
 97                 index = index + 1
 98
 99     # 依次遍历所有的章节,并爬下来
100     def spiderAllPagesFromOne(self,pageInfo):
101         for index,pageInfo in pageInfo.items():
102             print '正在爬第%d个页面……'%index
103             try:
104                 decodePageResp = self.getDecodePage(pageInfo['pageurl'])
105                 pageContent = self.getPageContent(decodePageResp)
106                 self.writeToFile(pageContent,pageInfo['pagename'])
107             except Exception,e:
108                 print '爬第%d个页面时出错了' %index
109                 self.errorPage = {index:pageInfo['pageurl']}
110                 pass
111
112     # 获取正文的标题
113     def getPageTitle(self,content):
114         charToTitleRex = re.compile('h1>(.|\s)*?</h1')
115         pageTitle = charToTitleRex.search(content).group()
116         pageTitle = pageTitle[3:len(pageTitle)-4]
117         return pageTitle
118
119     def writeToFile(self,content,filename):
120         if os.path.exists(os.getcwd() + '/Novels'):
121             if not os.path.isdir(os.getcwd() + '/Novels'):
122                 os.rename('Novels','Novels.bak')
123                 os.mkdir(os.getcwd() + '/Novels')
124         else:
125             os.mkdir(os.getcwd() + '/Novels')
126
127         if self.saveAsOne == 'N':
128             ofile = open(os.getcwd() + '/Novels/' + filename,'w')
129         else:
130             ofile = open(os.getcwd() + '/Novels/novel.txt','a')
131
132         try:
133             ofile.write(content)
134         except Exception, e:
135             print '存储网页',filename,'出错!'
136             pass
137         finally:
138             ofile.close()
139
140     def getDecodePage(self,pageurl):
141         req = urllib2.Request(
142             url = pageurl,
143             headers = self.headers
144             )
145         # print pageInfo['pageurl']
146         pageResponse = urllib2.urlopen(req).read()
147         decodePageResp = pageResponse.decode(self.getPageType(pageResponse),'replace').encode('utf-8')
148         return decodePageResp
149
150         # 章节内容
151
152     def getPageContent(self,decodePageResp):
153         contentPattern = re.compile('(<dd id="contents">)((.|\s)*?)(</dd>)')
154         content = contentPattern.search(decodePageResp).group(2)
155         content = self.replaceWebTag(content)
156         return content
157
158     # 获取下一页的地址
159     def getNextPage(self,content):
160         # 先获取到下一页的位置
161         footlinkRex = re.compile('(footlink">)(.*?)</dd>')
162         foot = footlinkRex.search(content).group(2)
163         pattern = re.compile(r'(返回目录.*?(<a.*?">下一页))')
164         m = pattern.search(foot).groups()
165         nextUrl = m[len(m)-1][9:m[len(m)-1].find('">')]
166
167         return self.url[0:self.url.rfind('/')+1] + nextUrl
168
169     def getAllUrlsAndNames(self):
170         # 先请求目录页,获取所有的目录章节和链接
171         req = urllib2.Request(
172             url = self.url,
173             headers = self.headers
174         )
175         myResponse = urllib2.urlopen(req).read()
176         decodeResp = myResponse.decode(self.getPageType(myResponse)).encode('utf-8')
177
178         print '正在分析目录页面,请稍后…………'
179         pageRex = re.compile('<a href=".*?</td>') #定义获取所有章节页面链接的正则
180         pageUrlRex = re.compile('".*?"')    #获取章节url的正则
181         pageNameRex = re.compile('>.*?<')    #获取章节名字的正则
182
183         pages = pageRex.findall(decodeResp)
184         index = 1
185         for page in pages:
186             pageurl = pageUrlRex.search(page).group()
187             pageurl = pageurl[1:len(pageurl) - 1]
188             pageurl = self.url + pageurl
189
190             pagename = pageNameRex.search(page).group()
191             pagename = pagename[1:len(pagename) - 1]
192
193             # print pagename + '     ' + pageurl
194             self.pagesInfo[index] = {
195                 'pagename' : pagename,
196                 'pageurl' : pageurl
197             }
198             index = index + 1
199         print '目录页分析完成!该小说共有%d个章节'%index
200         return self.pagesInfo
201
202     def getNovelName(self,content):
203         titleRex = re.compile('<h1>.*?</h1>')
204         title = titleRex.search(content).group()
205         return title[4:len(title) - 5]
206
207     def replaceWebTag(self,content):
208         charToNoneRex = re.compile(r'&nbsp;')
209         charToNewLineRex = re.compile("<br />|<br>|<br/>")
210
211         content = charToNoneRex.sub("",content)
212         content = charToNewLineRex.sub("\n",content)
213         return content
214
215 if __name__ == '__main__':
216     print u"""
217 # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * #
218 #     程序:【23hh小说网】爬虫                                                        #
219 #     版本:1.0                                                                    #
220 #     作者:Silence                                                                #
221 #     日期:2014-04-08                                                                #
222 #     操作:启动后输入要爬得小说目录页地址,就可以自动爬了                                #
223 #     功能:1. 提供一个目录页,把目录页中所有的目录章节都抓出来(默认是:23hh的争霸天下);    #
224 #         2. 提供一个正在看的目录页,把这个章节及以后的所有章节都抓取下来,                #
225 #         分章节保存在启动脚本目录下的Novels目录下;                                    #
226 #         如果该目录下已经有一个Novels,则把这个Novels改名为Novels.bak                    #
227 # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * # * #"""
228
229     novelUrl = raw_input('请输入要爬的小说地址(默认是:23hh的争霸天下章节目录)\n')
230     if novelUrl == '':
231         novelUrl = 'http://www.23hh.com/book/43/43957/'
232     elif novelUrl.find('html') > 0:
233         novelUrl = novelUrl
234
235     saveAsOne = raw_input('是否保存为一个文件?是为Y,否为N\n')
236     if saveAsOne not in ['Y','N']:
237         saveAsOne = 'N'
238
239     Novel = Novel_Tool(novelUrl,saveAsOne)
240
241     if not novelUrl.find('html') > 0:
242         queue = Queue()
243         pageInfos = Novel.getAllUrlsAndNames()
244         for key,value in pageInfos.items():
245             queue.put({key:value})
246
247         thread1 = Spider_Thread('thread1',queue)
248         thread2 = Spider_Thread('thread2',queue)
249         thread3 = Spider_Thread('thread3',queue)
250         thread4 = Spider_Thread('thread4',queue)
251         thread1.start()
252         thread2.start()
253         thread3.start()
254         thread4.start()
255     else:
256         Novel.start()

转载于:https://www.cnblogs.com/SilenceCity/p/3653248.html

23hh小说网——爬虫1.0python相关推荐

  1. 23hh小说网——爬虫python

    1 #! /bin/python 2 # -*- coding:utf-8 -*- 3 4 # -------------------------------------------- 5 # 程序: ...

  2. pthon爬虫笔记--名著小说网

    Python爬虫笔记一--名著小说网的爬取 @阿乐今天敲代码没 import requests #导入requests库 import sys #python自带模块,联系python解释器 from ...

  3. Scrapy爬虫框架,爬取小说网的所有小说

    Scrapy入门教程请看 目录 1.思路清理 2.创建爬虫项目 3. 爬虫架构构思 4.爬虫程序具体分析 5.效果展示 6.待优化的地方 1.思路清理 我们的目的是把某个小说网的所有小说给拿下,这就涉 ...

  4. python爬虫简单实例-爬取17K小说网小说

    什么是网络爬虫? 网络爬虫(Web Spider),又被称为网页蜘蛛,是一种按照一定的规则,自动地抓取网站信息的程序或者脚本. 爬虫流程 先由urllib的request打开Url得到网页html文档 ...

  5. 使用scrapy爬虫,爬取17k小说网的案例-方法一

    无意间看到17小说网里面有一些小说小故事,于是决定用爬虫爬取下来自己看着玩,下图这个页面就是要爬取的来源. a 这个页面一共有125个标题,每个标题里面对应一个内容,如下图所示 下面直接看最核心spi ...

  6. python爬虫17K小说网资料

    python爬虫17K小说网资料 爬虫作业要求:抓取小说网站为例,必须抓取一系列小说(不是一部小说)的篇名.作者.出版单位(或首发网站).出版时间(或网上发布时间).内容简介.小说封面图画.价格.读者 ...

  7. 爬虫起点小说网所有小说基本信息

    爬虫起点小说网所有小说基本信息 第一篇博客,先试试水.爬虫你们懂的,三小时5万条数据: 多线程 失败再爬取机制 多次失败链接储存再爬取 自定义数据量 代码块 导入需要的包 # -*- coding: ...

  8. Python爬虫期末作业 | 爬取起点小说网作者和书名,并以Excel形式存储

    使用Python爬虫技术爬取起点小说网作者及书名,并且以xlsx形式保存 前言 随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容. 一. ...

  9. scrapy-redis分布式爬虫全站爬取顶点小说网

    scrapy-redis是一个基于redis的scrapy组件,通过它可以快速实现简单分布式爬虫程序,该组件本质上提供了三大功能: scheduler - 调度器 dupefilter - URL去重 ...

最新文章

  1. 【Java并发编程】一、为什么需要学习并发编程?
  2. Mysql字符串字段判断是否包含某个字符串的3种方法
  3. Halcon初学者知识【19】带paint_的系列算子
  4. java每秒向mysql写一条记录_【Java】mysql一条记录在高并发场景下读写?
  5. onMeasure onLayout用法,区别
  6. vs.net 中编译链接vc工程时的LNK171@mspdb140.dll错误处理
  7. Java新手造假_老板居然让我在Java项目中“造假”
  8. JAVA单向链表实现
  9. 计算机组装过程英文版,计算机组装与维护试题及答案(国外英文资料).doc
  10. python的ctypes模块详解数组_python ctypes结构数组
  11. response php,HttpResponse.php
  12. BitCoin Gloom系列
  13. 拓端tecdat|Python信贷风控模型:梯度提升Adaboost,XGBoost,SGD, GBOOST, SVC,随机森林, KNN预测金融信贷违约支付和模型优化
  14. 115网盘android使用方法,115网盘Android新版五项主要特点评测
  15. enym在此计算机运行是灰色,Win10重建引导记录mbr为灰色
  16. 产品的思维与技术的思维差异
  17. 时间序列(ARIMA)模型
  18. idea使用技巧总结,超实用(2年mac idea使用经验)
  19. HDL4SE:软件工程师学习Verilog语言(十)
  20. android修改渠道,Android 多渠道定制化打包

热门文章

  1. MATLAB学习笔记:行列式及其应用
  2. Java中Type接口与Class类的区别联系
  3. python控制nao机器人_python 程序控制NAO机器人行走
  4. 南加大计算机本科学费,留学南加州大学学费多少一年
  5. 深度学习的坎坷六十年
  6. windows 8 照片详解
  7. kindle运行linux命令,Kindle4: 编译并运行官方linux kernel – v2.6.31
  8. [系列] - go-gin-api 规划目录和参数验证(二)
  9. doom主程序员相关文章
  10. Linux时间子系统之Tick模拟层(Tick Sched)