支持正版,一切只为学习

之前写的笔趣阁爬虫有不少同学说不能爬了,我后来发现是网站改版的缘故,前些日子把书里的爬虫项目都整的差不多了,现在又有些不知道爬什么好了,刚好在这段时间把笔趣阁爬虫代码重写一下。
(PS:我看自己之前写的代码感觉写的好丑哦,官方吐槽,最为致命,以前的链接)

做了以下改进:

  1. 将爬虫代码写入对象中,把用户选择判断的语句写在外部,使得爬虫本身更加简洁;
  2. 优化互动的相关代码,操作更舒适;
  3. 采用多进程爬取小说各章节的内容,速度更快;
  4. 加入UA代理,尽可能反反爬虫,安全性更高 。

目录

  • 一、基本思路
  • 二、构建爬虫
    • 1、借东风,借用网站搜索书籍的功能
    • 2、遇明主,用户确认下载小说
    • 3、取荆州,下载小说内容,保存到docx文档中
  • 三、运行测试
  • 四、总结
  • 五、完整代码

前期准备,需要在cmd里下载安装以下第三方库:
pip install requests
pip install python-docx

一、基本思路

以下是爬取笔趣阁小说的主体思路,爬虫代码在这个思路上扩展构建。

Created with Raphaël 2.2.0开始输入书名查询小说是否存在跳转页面至小说主页获取小说目录URL解析小说内容并保存至word结束yesno

二、构建爬虫

笔趣阁的网站众多,这是我爬取的笔趣阁网址:http://www.biquge.tv/
我将爬虫写到 biqugeCrawl 类中。

1、借东风,借用网站搜索书籍的功能

以搜索圣墟为例,网站的搜索是靠这个searchkey这个参数。在biqugeCrawl类中定义一个search_book() 函数专用于查找小说功能。

1.1、 大家看到这个%什么的或许会很陌生,这是因为URL 只允许一部分 ASCII 字符(数字字母和部分符号),其他的字符(如汉字)是不符合 URL 标准的,所以我们这里使用 urllib库parse.quote() 将其转换为URL编码。

转换后还是不符合要求,怀疑是编码格式的问题,去网页的源码中查看,如下显示为GBK编码,所以我们输入的书名还要先转换为GBK格式。

name = input("请输入书名:")
name = parse.quote(name.encode('gbk'))

1.2、 接下来我们拼接搜索的url,并请求它,得到相应的搜索结果的html网页。

__random_ua()是随机返回user-agent的函数,这样在一定程度上可以避免被反爬。代码很简单,自己看一下。

serach_url = "http://www.biquge.tv/modules/article/search.php?searchkey={}"
url = serach_url.format(name)
response = requests.get(url=url, headers=self.__random_ua())

1.3、 如果搜到了书籍,也不直接下载,因为好多小说名字相似趁热度的,所以我这里获取第一个小说名及作者名返回让用户确认是否下载。另外,因为搜索不当,可能没有书籍,也可能是关键字太短了,我用try-except 另行处理,返回None值,并提示没有该书。

# 搜索书籍
root = etree.HTML(response.content)try:book_name = root.xpath('//*[@id="nr"]/td[1]/a/text()')[0]book_author = root.xpath('//*[@id="nr"]/td[3]/text()')[0]book_url = root.xpath('//*[@id="nr"]/td[1]/a/@href')[0]return [book_name, book_author, book_url]except:return None
# 用户确认
book = biquge.search_book()
if book is not None:flag = input("搜索到的书名为《{}》,作者名为{},请确认是否下载【Y/N】".format(book[0], book[1]))while 1:if flag == 'Y' or flag == 'y':biquge.download(book[0], book[2])breakelif flag == 'N' or flag == 'n':breakelse:flag = input("请正确输入【Y/N】!")
else:print("查无此书")



2、遇明主,用户确认下载小说

上一步写得search_book() 函数在搜到小说得情况下返回了三个数据:小说名、作者名、小说得url,经由用户确认,调用biqugeCrawl.download() ,获取小说章节链接,并采用多线程下载内容。

2.1、 请求网页,获取链接,因为它有九个最新章节得在里面,所以我们使用xpath解析出来得列表要略去这九个,直接用切片切掉。

response = requests.get(url=url, headers=self.__random_ua())
root = etree.HTML(response.content)# 拼接完整得章节url
content_urls = list(map(lambda x: "http://www.biquge.tv/" + x, root.xpath('//*[@id="list"]/dl/dd/a/@href')[9:]))
content_names = root.xpath('//*[@id="list"]/dl/dd/a/text()')[9:]# 创建以书名命名的文件夹
path = '《' + book_name + '》'
if not os.path.exists(path):os.mkdir(path)

2.2、 有了相应得链接,这里就要使用多进程了,速度大大的增加。

utls_names = [i for i in zip(content_urls, content_names)]# 同时进行得进程数量
pool = Pool(processes=5)# 将utls_names中得元素分配给parse()函数
pool.map(self.parse, utls_names)

3、取荆州,下载小说内容,保存到docx文档中

上面一步是获取到了小说章节的目录,并采用多进程的方法调用了biqugeCrawl.parse() 函数,这个函数的作用就是下载并保存小说内容。
3.1、 解析出小说的主体内容,观察网页源码,可以发现,小说的内容都在<div id="content"></div>html标签中,我用正则表达式将其解析出来,并对文本做了一些处理。

response = requests.get(url=url, headers=self.__random_ua())
html = response.content.decode('gbk')
content = "".join(re.findall('<div id="content">(.*?)</div>', html, re.S))
content = re.sub("<.*?>", "", re.sub("&nbsp;&nbsp;", " ", content))

3.2、 获取到的小说内容肯定是要保存起来的,我这里保存到了docx文档文件中。这里又用xapth解析出了小说名,作为文本保存路径的一部分。

我后面想想那小说章节名也可以不传进来,在这里解析就是了,算了,无伤大雅

root = etree.HTML(response.content)
book_name = root.xpath('//div[@class="con_top"]/a[2]/text()')[0]# 创建document对象
document = Document()# 将文本写入文档
document.add_paragraph(content)document.save("《{}》/《{}》.docx".format(book_name, name))print('《' + name + '》已下载完成')

爬虫的思路都理清楚了,还有一些旁支末节详见完整代码,有什么不清楚也可以直接来问我。

三、运行测试

做了一些简单的测试,按照提示来操作都是没问题的,就算不按照提示来,整些奇奇怪怪的操作也是没问题的,很舒服,而且速度也快,我爬取《圣墟》一千五百多章大概耗时三分钟,也可以更快,不过我们只是学习爬虫的技术又不是搞破坏,太快的话对服务器的压力也很大的,还有被封IP的可能,可以参考【构建简单IP代理池】,使用代理ip,这样更安全。

IP代理池我自己是改了好几版了,用起来还是很舒服的,不用担心被封ip的事情了,把ip数据存到数据库中,上手简单,建议学习搭建。

四、总结

这爬取笔趣阁本来就是个小爬虫,我感觉很适合让刚入爬虫的同学学习的,虽然相比那种只爬取单个网页的入门学习方式要多些困难,不过克服困难后还是会有很大的进步的,这是我整理的【爬虫实战项目集合】,有兴趣的可以看看,由浅入深的学习爬虫,最简单的和较为复杂的都有。

对于这个爬笔趣阁的项目,我认为有一个很大的槽点,它是多进程爬取出来的,文件按时间排序不行,按名称排序又是下面这样,emm,太难看了,还是之前老版本的非多进程好看,但就是慢些,没有思路解决这个问题,求教。

另外,我想在爬虫里加上暂定下载的功能,以及断网处理的功能(这两个功能是一个原理,搞一个任务队列),这爬取笔趣阁小爬虫是小爬虫,但小事情多做几次,就会越发的精细,好了,也没啥讲的了,祝大家写程序没有bug,天天开心。

啊,对啦对啦,点个赞,点个关注吧,蟹蟹支持。

五、完整代码

import os
from urllib import parse
import requests
from docx import Document
from lxml import etree
import re
import random
from multiprocessing import Poolimport timeclass biqugeCrawl():m_url = "http://www.biquge.tv/"# 查询书籍函数def search_book(self):serach_url = "http://www.biquge.tv/modules/article/search.php?searchkey={}"name = input("请输入书名:")name = parse.quote(name.encode('gbk'))url = serach_url.format(name)response = requests.get(url=url, headers=self.__random_ua())root = etree.HTML(response.content)try:book_name = root.xpath('//*[@id="nr"]/td[1]/a/text()')[0]book_author = root.xpath('//*[@id="nr"]/td[3]/text()')[0]book_url = root.xpath('//*[@id="nr"]/td[1]/a/@href')[0]return [book_name, book_author, book_url]except:return None# 下载函数def download(self, book_name, url):response = requests.get(url=url, headers=self.__random_ua())root = etree.HTML(response.content)content_urls = list(map(lambda x: "http://www.biquge.tv/" + x, root.xpath('//*[@id="list"]/dl/dd/a/@href')[9:]))content_names = root.xpath('//*[@id="list"]/dl/dd/a/text()')[9:]# 创建以书名命名的文件夹path = '《' + book_name + '》'if not os.path.exists(path):os.mkdir(path)utls_names = [i for i in zip(content_urls, content_names)]pool = Pool(processes=5)pool.map(self.parse, utls_names)print("《{}》下载完毕!".format(book_name))# 爬取文章内容函数def parse(self, url_name):url = url_name[0]name = url_name[1]try:response = requests.get(url=url, headers=self.__random_ua())html = response.content.decode('gbk')root = etree.HTML(response.content)book_name = root.xpath('//div[@class="con_top"]/a[2]/text()')[0]content = "".join(re.findall('<div id="content">(.*?)</div>', html, re.S))content = re.sub("<.*?>", "", re.sub("&nbsp;&nbsp;", " ", content))# 创建document对象document = Document()# 将文本写入文档document.add_paragraph(content)document.save("《{}》/《{}》.docx".format(book_name, name))print('《' + name + '》已下载完成')except Exception as e:with open("./log.txt", "a+", encoding="utf-8") as file:file.write("*"*30+"\n"+str(e))print("出现异常,下载中断,请查看log文件!")pass# 随机UAdef __random_ua(self):UA = ["Mozilla/5.0 (Windows NT 5.1; rv:7.0.1) Gecko/20100101 Firefox/7.0.1","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0","Mozilla/5.0 (X11; U; Linux Core i7-4980HQ; de; rv:32.0; compatible; JobboerseBot;Gecko/20100101 Firefox/38.0","Mozilla/5.0 (Windows NT 5.1; rv:36.0) Gecko/20100101 Firefox/36.0","Mozilla/5.0 (Windows NT 5.1; rv:33.0) Gecko/20100101 Firefox/33.0","Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0","Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0","Mozilla/5.0 (Windows NT 10.0; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0","Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0","Mozilla/5.0 (Windows NT 5.1; rv:40.0) Gecko/20100101 Firefox/40.0","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0","Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0","Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/20.6.14","Mozilla/5.0 (Windows NT 5.1; rv:30.0) Gecko/20100101 Firefox/30.0","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10; rv:33.0) Gecko/20100101 Firefox/33.0","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/29.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0","Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0","Mozilla/5.0 (X11; U; Linux Core i7-4980HQ; de; rv:32.0; compatible; JobboerseBot; Gecko/20100101 Firefox/38.0","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0"]headers = {"User-Agent": {}}headers["User-Agent"] = random.choice(UA)return headersif __name__ == '__main__':biquge = biqugeCrawl()print("----笔趣阁小说爬虫----")print("1-------------搜索小说")print("2----------------退出")flag = input("请输入指令选择相应功能:")while 1:error_str = ""if flag == "1":book = biquge.search_book()if book is not None:flag = input("搜索到的书名为《{}》,作者名为{},请确认是否下载【Y/N】".format(book[0], book[1]))while 1:if flag == 'Y' or flag == 'y':biquge.download(book[0], book[2])breakelif flag == 'N' or flag == 'n':breakelse:flag = input("请正确输入【Y/N】!")else:print("查无此书")elif flag == "2":exit(1)else:error_str = "指令错误,"flag = input("{}请重新输入指令选择相应功能【1.搜索;2.退出】:".format(error_str))

笔趣阁爬虫(2020重制版),贴心的操作,谁用谁知道相关推荐

  1. 用python60行代码写一个简单的笔趣阁爬虫!三分一章?

    前言 利用python写一个简单的笔趣阁爬虫,根据输入的小说网址爬取整个小说并保存到txt文件.爬虫用到了BeautifulSoup库的select方法 结果如图所示: 本文只用于学习爬虫 一.网页解 ...

  2. 偷偷溜出来写个笔趣阁爬虫

    爬笔趣阁的,或许有点小bug,权当过过手瘾 害,居然打不出代码块,就这样好了 import requests import random from lxml import etree import t ...

  3. 初学爬虫-笔趣阁爬虫

    import requests from lxml import etree base_url=input("请输入小说url:") #如春日宴的url为https://www.x ...

  4. python3+正则(re)增量爬虫爬取笔趣阁小说( 斗罗大陆IV终极斗罗)

    python3+re 爬虫爬取笔趣阁小说 斗罗大陆IV终极斗罗 爬取前准备 导入的模块 分析 正则的贪婪与非贪婪 附完整代码示例 爬取前准备 导入的模块 import redis #redis数据库 ...

  5. 爬虫练习-爬取笔趣阁小说

    练习一下爬虫,将笔趣阁的小说根据需求目标再爬取下来,本文仅仅学习爬虫技术,大家还是要支持一下正版网站的 思路: Created with Raphaël 2.2.0开始输入书名查询小说是否存在跳转页面 ...

  6. java爬虫爬取笔趣阁小说

    java爬虫爬取笔趣阁小说 package novelCrawler;import org.jsoup.Connection; import org.jsoup.HttpStatusException ...

  7. Python爬虫--笔趣阁小说爬取

    Python爬虫–笔趣阁小说爬取 爬虫用到的插件 import requests from lxml import etree 小说目录页 以小说"我有百万技能点"为例,在笔趣阁搜 ...

  8. 爬虫实战|从笔趣阁爬取书籍并简单保存

    最近在看崔庆才那本经典的爬虫开发书籍,之前虽然看过一点视频,但是与书籍相比还是书籍更加成体系,让我对知识有一个宏观的把控.目前已经看了前四章,了解了一些基础知识和如何解析数据的方法,但是对于数据的保存 ...

  9. python爬虫-笔趣阁

    突发奇想去爬笔趣阁的小说,毕竟我是一个老书虫,闲话不多说,代码呈上.主要使用requests BeautifulSoup from urllib.request import quote, unquo ...

最新文章

  1. 番茄时间有感之关于在疫情期间我与ACM不得不说的故事
  2. 是什么还让你停留在 iOS 平台?是这些理由吗
  3. 浅谈java.awt使用过程中遇到的问题
  4. python cos函数_Python Tensorflow cos()用法及代码示例
  5. c++ primer练习题 第七章 类 (Class)
  6. jQuery特效 | 导航底部横线跟随鼠标缓动
  7. defaultView与currentStyle的区别_获取CSS样式值
  8. pycharm汉化(搜索不到插件的参考第二中方法)
  9. php在线拍照代码,PHP+Javascript实现在线拍照功能实例_php技巧
  10. 【任务二】打卡——by 003-Vamein
  11. python与金融数据分析论文_python 金融大数据分析 pdf
  12. 太美医疗科技CTMS临床试验项目管理系统的全新升级
  13. 使用Python模拟武侠小说中两派人的一场遭遇战。
  14. euler和鸿蒙,euleros 鸿蒙
  15. shell脚本中 set -ex
  16. 为什么我的C语言移位操作达不到效果??
  17. 专题二:无穷小量阶的比较-一刷
  18. 苹果手机软件升级密码_密码太多总是忘?不如试试这7个密保工具
  19. python简单心形代码爱情闪字_HTML5 + CSS3 实现闪光字
  20. Spring源码深度解析(郝佳)-学习-RMI使用及Spring源码解读

热门文章

  1. 机器学习(书籍推荐)
  2. Windows 11 绕过 TPM 方法总结,通用无 TPM 镜像下载 (2023 年 1 月更新)
  3. 计算机修复需要连接互联网么,win10网络连接问题怎么修复
  4. markdown数学公式编辑学习
  5. json 数据 下载为.csv表格方法封装
  6. php 剪头,【家园】剪头(散文)
  7. 转:七年之痒,再见理想
  8. 传统目标检测后处理问题
  9. 综合纳税服务平台的设计
  10. buuctf解题记录