python爬虫,多线程批量爬取多部小说

  • 欢迎阅读
    • 环境
    • 获取排行榜top上的所有小说地址
    • 分析排行榜top100页面的html,获取所有小说的url
    • 遍历小说列表url到生成txt
    • 多线程启动爬取任务
    • 完整代码
  • 写在最后

欢迎阅读

忽然有兴趣想试试把某网络小说网站上所有的小说都给爬下来。就拿17K小说网开刀,先把这个网站免费排行榜上的所有小说都弄下来。
之前发过贴,如何将一本小说爬取出来,以及简单规避网站安全系统。这次爬取多本的话,无非是在最外层再加一个循环,然后以多线程的方式启动,对每一部小说进行爬取,就不描述的太具体了。
完整代码在最后。

环境

依然是python3+pycharm,安装第三方库requests、threading

import os
import requests
import re
import time
import random
import threading

获取排行榜top上的所有小说地址

17K小说免费排行榜地址:
https://www.17k.com/top/refactor/top100/06_vipclick/06_click_freeBook_top_100_pc.html.
依然是先写好方法,获取html。最好是将html打印到本地,便于观察html,找出小说url的正则规律

#获取网页html
def get_htmlcode(url):try:urlhtml = requests.get(url)htmlcode = urlhtml.content# path = open('Txt/html.txt','wb')# path.write(htmlcode)# path.close()except:htmlcode = 'error'return htmlcode

加一个try是为了避免网站服务出现问题导致程序跑不过。

分析排行榜top100页面的html,获取所有小说的url

通过对html进行分析,以 <a class=“red” href=" 开头、 " title=’ 结尾,中间的部分就是各小说的url。
对正则后的列表进行统计数量,发现爬取出了900个小说url。当时很震惊,明明是top100 ,为什么爬了900个?开始还以为是自己正则的规律选错了。后来对网站进行审查,发现这个top 100分男生、女生、全站三大类,每个大类里又细分了周榜、月榜、总榜。3乘以3,正好是900。只不过这个时候就需要对爬取的900个url进行去重了,最后获得了408个小说地址。
但是此时的url还不是完整url,缺少了https前缀。
同时还需要将每个小说url中的book替换成list,这样就是每个小说的章节目录地址了。

#获取所有免费top榜的txt地址,去重,再完善地址路径
def get_topfree_list(htmlcode):reg = '</a></td><td><a class="red" href="(.+?)" title='reg_msg = re.compile(reg)list_all = reg_msg.findall(htmlcode.decode())#去重list_temp = list(set(list_all))list_top = []#完善地址,加上https前缀,并将book替换成listfor i in list_temp:i = 'https:'+ ii = i.replace('book','list')list_top.append(i)return list_top

遍历小说列表url到生成txt

上一部获取了所有小说的章节目录地址了,并存在了一个列表中。我们只要对这个列表进行遍历,再从章节目录地址的html中去获取每一章的地址,最后再遍历每一章的地址,从html中去得到小说的正文。这样就对得上了。
这一步的具体过程在上个帖子中已经具体介绍过了,就不细说了。

另这个网站很奇怪,虽说是免费榜,但是有的小说的部分章节又被锁住了,导致咱们在按照正则去获取章节名和小说正文时,因为匹配不到而报错。好在绝大部分锁住的章节html中规律还是比较明显的,就是会出现"该章节已被锁定"这些字眼,于是加了这么个方法:

#判断是否被锁定
def insert_lock(htmlcode):str1 =htmlcode.decode()str2 ='<h1>该章节已被锁定</h1>'temp = str1.find(str2)return temp

当返回的值不为-1时,则证明没有被锁定。
此步骤完整代码

#从小说章节列表地址到爬取完成
def get_novel_all(chapter_url):# 章节列表网站的htmlHtmlcode_chapter_list = get_htmlcode(chapter_url)if Htmlcode_chapter_list == 'error':print('~~~~~~~~~~~~~17K小说地址出错了:%s,请稍后再试~~~~~~~~~~~~~'%chapter_url)else:# 获取小说名称Novel_name = get_novel_name(Htmlcode_chapter_list)Novel_name_str = str(Novel_name)# 从源码中匹配出所有章节的地址Chapter_list = get_chapter_list(Htmlcode_chapter_list)# 创建TXT文件并打开path = open('17k/' + Novel_name_str + '.txt', 'a',encoding='utf-8')# 写入小说名称path.write('~~~~~~%s~~~~~~' % Novel_name_str)path.write('\n\n\n')flag = 0# 循环处理每个章节地址for l in Chapter_list:# 逐一处理章节地址,加上前缀url_chapter = 'https://www.17k.com/chapter/'+l+'.html'flag += 1print(url_chapter)# 获取具体章节的htmlHtmlcode = get_htmlcode(url_chapter)# 从章节的html中得到章节名Subject = get_subject(Htmlcode)Temp = insert_lock(Htmlcode)if Temp == -1:# 从html中得到小说Novel = get_novel(Htmlcode)# 输入到最终TXT中path.write(str(Subject))path.write('\n')for j in Novel:path.write('   ')path.write(j)path.write('\n')path.write('\n\n')# 加一个提示信息print('章节%s %s打印结束' % (Novel_name_str, Subject))# 短暂随机休息,防止被网站后台封禁time.sleep(round(random.uniform(0.2, 0.5), 2))else:print('章节%s爬取失败'%Subject)path.write('\n')path.write(str(Subject))path.write('\n')path.close()print('小说%s爬取完成' % Novel_name_str)

这其中有一些调用的自定义方法和上一个帖子中的基本一致,因为爬取的是不同的小说网站,所以无非是正则表达式的写法会不同而已。相信跟着一起做过的同学都是没问题的。

多线程启动爬取任务

使用了threading中的Thread方法启动多线程。
在考虑启动多少个线程时,我纠结了一会。一方面是担心线程数太多的话,会被网站封禁,并且本机的网络和性能都会收到影响;另一方面又担心线程数太少的话,效率不高。
想多了之后,心里也把不住个结果。总共就500部小说不到,干脆就遍历列表,有多少元素就启动多少个线程。于是试运行了下,发现效果挺好的。
正好也合了那句话:重剑无锋,大巧不工。顺其自然,别打磨的太繁琐。

if __name__ =='__main__':Htmlcode_Freetop = get_htmlcode(url_list)#获取免费榜单所有小说的urlTopfree_List = get_topfree_list(Htmlcode_Freetop)#循环启动多进程,设置间隔时间for i in Topfree_List:threading.Thread(target=get_novel_all, args=(i,)).start()time.sleep(0.5)print('免费榜单上的所有txt已爬取完成')

完整代码

import os
import requests
import re
import time
import random
import threading#创建目录
if not os.path.exists('Txt'):os.mkdir('Txt')#获取网页html
def get_htmlcode(url):try:urlhtml = requests.get(url)htmlcode = urlhtml.content# path = open('Txt/html.txt','wb')# path.write(htmlcode)# path.close()except:htmlcode = 'error'return htmlcode#获取所有免费top榜的txt地址,去重,再完善地址路径
def get_topfree_list(htmlcode):reg = '</a></td><td><a class="red" href="(.+?)" title='reg_msg = re.compile(reg)list_all = reg_msg.findall(htmlcode.decode())#去重list_temp = list(set(list_all))list_top = []#完善地址,加上https前缀,并将book替换成listfor i in list_temp:i = 'https:'+ ii = i.replace('book','list')list_top.append(i)return list_top#获取小说名称
def get_novel_name(htmlcode):reg = '<h1 class="Title">(.+?)</h1>'reg_msg = re.compile(reg)novel_name = reg_msg.findall(htmlcode.decode())return novel_name#获取章节地址列表(无https:前缀)
def get_chapter_list(htmlcode):htmldecode = htmlcode.decode()reg = r'href="/chapter/(.+?).html'reg_msg = re.compile(reg)chapter_list = reg_msg.findall(htmldecode)return chapter_list#获取章节名称
def get_subject(htmlcode):reg = '<h1>(.+?)</h1>'reg_msg = re.compile(reg)subject = reg_msg.findall(htmlcode.decode())return subject#获取正文,需要先切割再正则
def get_novel(htmlcode):htmldecode = htmlcode.decode()a = htmldecode.index('<div class="p">')b = htmldecode.index('<p class="copy ">')htmldecode_final = htmldecode[a:b]reg = '<p>(.+?)</p>'reg_msg = re.compile(reg)novel = reg_msg.findall(htmldecode_final)return novel#判断是否被锁定
def insert_lock(htmlcode):str1 =htmlcode.decode()str2 ='<h1>该章节已被锁定</h1>'temp = str1.find(str2)return temp#从小说章节列表地址到爬取完成
def get_novel_all(chapter_url):# 章节列表网站的htmlHtmlcode_chapter_list = get_htmlcode(chapter_url)if Htmlcode_chapter_list == 'error':print('~~~~~~~~~~~~~17K小说地址出错了:%s,请稍后再试~~~~~~~~~~~~~'%chapter_url)else:# 获取小说名称Novel_name = get_novel_name(Htmlcode_chapter_list)Novel_name_str = str(Novel_name)# 从源码中匹配出所有章节的地址Chapter_list = get_chapter_list(Htmlcode_chapter_list)# 创建TXT文件并打开path = open('17k/' + Novel_name_str + '.txt', 'a',encoding='utf-8')# 写入小说名称path.write('~~~~~~%s~~~~~~' % Novel_name_str)path.write('\n\n\n')flag = 0# 循环处理每个章节地址for l in Chapter_list:# 逐一处理章节地址,加上前缀url_chapter = 'https://www.17k.com/chapter/'+l+'.html'flag += 1print(url_chapter)# 获取具体章节的htmlHtmlcode = get_htmlcode(url_chapter)# 从章节的html中得到章节名Subject = get_subject(Htmlcode)Temp = insert_lock(Htmlcode)if Temp == -1:# 从html中得到小说Novel = get_novel(Htmlcode)# 输入到最终TXT中path.write(str(Subject))path.write('\n')for j in Novel:path.write('   ')path.write(j)path.write('\n')path.write('\n\n')# 加一个提示信息print('章节%s %s打印结束' % (Novel_name_str, Subject))# 短暂随机休息,防止被网站后台封禁time.sleep(round(random.uniform(0.2, 0.5), 2))else:print('章节%s爬取失败'%Subject)path.write('\n')path.write(str(Subject))path.write('\n')path.close()print('小说%s爬取完成' % Novel_name_str)url_list = 'https://www.17k.com/top/refactor/top100/06_vipclick/06_click_freeBook_top_100_pc.html'if __name__ =='__main__':Htmlcode_Freetop = get_htmlcode(url_list)#获取免费榜单所有小说的urlTopfree_List = get_topfree_list(Htmlcode_Freetop)#循环启动多进程,设置间隔时间for i in Topfree_List:threading.Thread(target=get_novel_all, args=(i,)).start()time.sleep(0.5)print('免费榜单上的所有txt已爬取完成')

总共407部小说,脚本跑大概15分钟后,爬完了405部,总共有300M。有两部因为章节数太多,一个是快5千章,另一个是接近上万章,所以提前结束了进程,没跑完。最后剩下的那部小说是正则表达式没有找到章节名,线程报错而停止了,可能是又有一个类似锁定的其他结构吧。(只不过我也懒得再去纠结了,哈哈哈~)至少从整体正确性和效率性上来看,爬虫工具的任务完成得还算及格。

写在最后

想起前不久,有个朋友开玩笑要不要把抖音APP上小姐姐的视频爬下来。我想了下思路,可能是得先用fiddler类似的代理工具抓一下APP访问的地址,然后后面的事情就大同小异了。我这样一说可能似乎是很简单,其实真要做的话,还是会遇到不少困难。
只不过那又有什么好担心的呢?在研究的道路上,摸着石头过河并不可笑,可笑的是连水都不愿意下。

祝各位码农同志:钱多事少离家近,位高权重责任轻。

Author
zhengyi
(解决问题的方法从来都不只有一种。这种做不到,就换下一种。没有做不到,只有想不到。)

python爬虫 多线程 爬取网站排行榜上的所有小说相关推荐

  1. Pycharm + python 爬虫简单爬取网站数据

    本文主要介绍简单的写一个爬取网站图片并将图片下载的python爬虫示例. 首先,python爬虫爬取数据,需要先了解工具包requests以及BeautifulSoup requests中文文档:ht ...

  2. python爬虫之爬取网站小说

    继上次的使用类的方法爬取的单页单章小说后,在准备爬取整部小说,遇到点困难,先用函数式编程试试结果. 代码如下: ''' 函数式编程 17K小说网爬取龙井迷案小说 '''# 导入第三方库 import ...

  3. 【python爬虫】爬取网站数据,整理三句半语料数据集

    因为目前没有公开的三句半语料库,所以在网络上爬取一些网站上公开的三句半数据. 主要分为两部分: 目录 爬取数据 清洗数据 爬取数据 以爬取 http://p.onegreen.net/JuBen 上的 ...

  4. Python爬虫(1)------爬取网站图片

    初学爬虫的学习流程 环境 python 3.6 使用 urlib库进行爬取内容 熟悉爬虫 首先对百度进行爬取 # -*- coding: utf-8 -*- import urllib.request ...

  5. Python 爬虫多线程爬取美女图片保存到本地

    Wanning 我们不是生产者,我们只是搬运工 资源来至于qiubaichengren ,代码基于Python 3.5.2 友情提醒:血气方刚的骚年.请 谨慎 阅图 !!! 谨慎 阅图 !!! 谨慎 ...

  6. python爬取慕课视频-python爬虫:爬取网站视频

    新建一个py文件,代码如下: #!/usr/bin/python # -*- coding: UTF-8 -*- import urllib,re,requests import sys reload ...

  7. python慕课视频-python爬虫:爬取网站视频

    新建一个py文件,代码如下: #!/usr/bin/python # -*- coding: UTF-8 -*- import urllib,re,requests import sys reload ...

  8. python爬虫第二弹-多线程爬取网站歌曲

    python爬虫第二弹-多线程爬取网站歌曲 一.简介 二.使用的环境 三.网页解析 1.获取网页的最大页数 2.获取每一页的url形式 3.获取每首歌曲的相关信息 4.获取下载的链接 四.代码实现 一 ...

  9. Python爬虫实战爬取租房网站2w+数据-链家上海区域信息(超详细)

    Python爬虫实战爬取租房网站-链家上海区域信息(过程超详细) 内容可能有点啰嗦 大佬们请见谅 后面会贴代码 带火们有需求的话就用吧 正好这几天做的实验报告就直接拿过来了,我想后面应该会有人用的到吧 ...

最新文章

  1. Oracle RAC环境下如何更新patch(Rolling Patch)
  2. 解决安装DEB包时报错
  3. javascript对下拉列表框(select)的操作
  4. Qt的QStyle类的标准图标汇总
  5. 我敢说,这是最全的常用设计模式汇总
  6. radiobutton 设置单选项目标
  7. Django使用python-docx-template,并根据模板来生成有数据的word文档
  8. Symbol'' has different size in shared object,consider re-linking
  9. 例解 autoconf 和 automake 生成 Makefile 文件[转+个人修改]
  10. java xml注释多行_如何在XML中注释单行?
  11. StorageManager获取U盘挂载状态
  12. 教师计算机excel培训教案,信息技术教案:Excel中的函数
  13. 分仓软件是什么?资管分仓的作用
  14. zebradesigner2教程_ZebraDesigner快速使用说明
  15. 芒种时节,某地为何无人收割小麦?
  16. 202101汇率换算
  17. Redis源码阅读笔记(二)list双向链表结构
  18. 如何正确获得Android内外SD卡路径
  19. 几个在线文档接口生成工具
  20. 思维工具1: SCAMPER

热门文章

  1. TensorFlow实战之Softmax Regression识别手写数字
  2. FIDDLER的使用方法及技巧总结
  3. 《吹小号的天鹅|寻找C站宝藏》
  4. 季节性ARIMA:时间序列预测
  5. (五)【虚拟仿真】基于光学平台的迈克尔孙干涉仪实验
  6. 局域网理论上的小常识(组网必备)
  7. 省市县三级联动 javascript 原生实现实例
  8. Visio与Word中的字体对应关系
  9. 【12月13日】A股ROE最高排名
  10. 国内发达的OCR识别发票扫描仪