实战干货:Python3小说站点爬虫|附下载
点击上方“Python高校”,关注
文末干货立马到手
作者:Jack Cui
http://cuijiahua.com/blog/2017/10/spider_tutorial_1.html
建议:请在电脑的陪同下,阅读本文。本文以实战为主,阅读过程如稍有不适,还望多加练习。
实战:爬取中网小说网站「笔趣看」上的文字。
(1)实战背景
小说网站-笔趣看:
URL:http://www.biqukan.com/
笔趣看是一个盗版小说网站,这里有很多起点中文网的小说,该网站小说的更新速度稍滞后于起点中文网正版小说的更新速度。并且该网站只支持在线浏览,不支持小说打包下载。因此,本次实战就是从该网站爬取并保存一本名为《一念永恒》的小说,该小说是耳根正在连载中的一部玄幻小说。PS:本实例仅为交流学习,支持耳根大大,请上起点中文网订阅。
(2)小试牛刀
我们先看下《一念永恒》小说的第一章内容,URL:http://www.biqukan.com/1_1094/5403177.html
我们先用已经学到的知识获取 HTML 信息试一试,编写代码如下:
1# -*- coding:UTF-8 -*-
2import requests
3
4if __name__ == '__main__':
5 target = 'http://www.biqukan.com/1_1094/5403177.html'
6 req = requests.get(url=target)
7 print(req.text)
运行代码,可以看到如下结果:
可以看到,我们很轻松地获取了 HTML 信息。但是,很显然,很多信息是我们不想看到的,我们只想获得如右侧所示的正文内容,我们不关心 div、br 这些 html 标签。如何把正文内容从这些众多的 html 标签中提取出来呢?这就是本次实战的主要内容。
(3)Beautiful Soup
爬虫的第一步,获取整个网页的 HTML 信息,我们已经完成。接下来就是爬虫的第二步,解析 HTML 信息,提取我们感兴趣的内容。对于本小节的实战,我们感兴趣的内容就是文章的正文。提取的方法有很多,例如使用正则表达式、Xpath、Beautiful Soup 等。对于初学者而言,最容易理解,并且使用简单的方法就是使用 Beautiful Soup 提取感兴趣内容。
Beautiful Soup 的安装方法和 requests 一样,使用如下指令安装(也是二选一):
pip install beautifulsoup4
easy_install beautifulsoup4
一个强大的第三方库,都会有一个详细的官方文档。我们很幸运,Beautiful Soup 也是有中文的官方文档。URL:
http://beautifulsoup.readthedocs.io/zh_CN/latest/
同理,我会根据实战需求,讲解 Beautiful Soup 库的部分使用方法,更详细的内容,请查看官方文档。
现在,我们使用已经掌握的审查元素方法,查看一下我们的目标页面,你会看到如下内容:
不难发现,文章的所有内容都放在了一个名为 div 的“东西下面”,这个"东西"就是 html 标签。HTML 标签是 HTML 语言中最基本的单位,HTML 标签是 HTML 最重要的组成部分。不理解,没关系,我们再举个简单的例子:
一个女人的包包里,会有很多东西,她们会根据自己的习惯将自己的东西进行分类放好。镜子和口红这些会经常用到的东西,会归放到容易拿到的外侧口袋里。那些不经常用到,需要注意安全存放的证件会放到不容易拿到的里侧口袋里。
html 标签就像一个个“口袋”,每个“口袋”都有自己的特定功能,负责存放不同的内容。显然,上述例子中的 div 标签下存放了我们关心的正文内容。这个 div 标签是这样的:
1<div id="content", class="showtxt">
细心的朋友可能已经发现,除了 div 字样外,还有 id 和 class。id 和 class 就是 div 标签的属性,content 和 showtxt 是属性值,一个属性对应一个属性值。这东西有什么用?它是用来区分不同的 div 标签的,因为 div 标签可以有很多,我们怎么加以区分不同的 div 标签呢?就是通过不同的属性值。
仔细观察目标网站一番,我们会发现这样一个事实:class 属性为 showtxt 的 div 标签,独一份!这个标签里面存放的内容,是我们关心的正文部分。
知道这个信息,我们就可以使用 Beautiful Soup 提取我们想要的内容了,编写代码如下:
1# -*- coding:UTF-8 -*-2from bs4 import BeautifulSoup3import requests4if __name__ == "__main__":5 target = 'http://www.biqukan.com/1_1094/5403177.html'6 req = requests.get(url = target)7 html = req.text8 bf = BeautifulSoup(html)9 texts = bf.find_all('div', class_ = 'showtxt')
10 print(texts)
在解析 html 之前,我们需要创建一个 Beautiful Soup 对象。BeautifulSoup 函数里的参数就是我们已经获得的 html 信息。然后我们使用find_all
方法,获得 html 信息中所有 class 属性为 showtxt 的 div 标签。find_all
方法的第一个参数是获取的标签名,第二个参数class_
是标签的属性,为什么不是 class,而带了一个下划线呢?因为 python 中 class 是关键字,为了防止冲突,这里使用class_
表示标签的 class 属性,class_
后面跟着的 showtxt 就是属性值了。看下我们要匹配的标签格式:
1<div id="content", class="showtxt">
这样对应的看一下,是不是就懂了?可能有人会问了,为什么不是find_all('div', id = 'content', class_ = 'showtxt')
?这样其实也是可以的,属性是作为查询时候的约束条件,添加一个class_='showtxt'
条件,我们就已经能够准确匹配到我们想要的标签了,所以我们就不必再添加 id 这个属性了。运行代码查看我们匹配的结果:
我们可以看到,我们已经顺利匹配到我们关心的正文内容,但是还有一些我们不想要的东西。比如 div 标签名,br 标签,以及各种空格。怎么去除这些东西呢?我们继续编写代码:
1# -*- coding:UTF-8 -*-2from bs4 import BeautifulSoup3import requests4if __name__ == "__main__":5 target = 'http://www.biqukan.com/1_1094/5403177.html'6 req = requests.get(url = target) 7 html = req.text8 bf = BeautifulSoup(html)9 texts = bf.find_all('div', class_ = 'showtxt')
10 print(texts[0].text.replace('\xa0'*8,'\n\n'))
find_all 匹配的返回的结果是一个列表。提取匹配结果后,使用 text 属性,提取文本内容,滤除 br 标签。随后使用 replace 方法,剔除空格,替换为回车进行分段。
在 html 中是用来表示空格的。replace('\xa0'*8,'\n\n')
就是去掉下图的八个空格符号,并用回车代替:
程序运行结果如下:
可以看到,我们很自然的匹配到了所有正文内容,并进行了分段。我们已经顺利获得了一个章节的内容,要想下载正本小说,我们就要获取每个章节的链接。我们先分析下小说目录:URL:http://www.biqukan.com/1_1094/
通过审查元素,我们发现可以发现,这些章节都存放在了 class 属性为 listmain 的 div 标签下,选取部分 html 代码如下:
1<div class="listmain">2<dl>3<dt>《一念永恒》最新章节列表</dt>4<dd><a href="/1_1094/15932394.html">第 1027 章 第十道门</a></dd>5<dd><a href="/1_1094/15923072.html">第 1026 章 绝伦道法!</a></dd>6<dd><a href="/1_1094/15921862.html">第 1025 章 长生灯!</a></dd>7<dd><a href="/1_1094/15918591.html">第 1024 章 一目晶渊</a></dd>8<dd><a href="/1_1094/15906236.html">第 1023 章 通天道门</a></dd>9<dd><a href="/1_1094/15903775.html">第 1022 章 四大凶兽!</a></dd>
10<dd><a href="/1_1094/15890427.html">第 1021 章 鳄首!</a></dd>
11<dd><a href="/1_1094/15886627.html">第 1020 章 一触即发!</a></dd>
12<dd><a href="/1_1094/15875306.html">第 1019 章 魁祖的气息!</a></dd>
13<dd><a href="/1_1094/15871572.html">第 1018 章 绝望的魁皇城</a></dd>
14<dd><a href="/1_1094/15859514.html">第 1017 章 我还是恨你!</a></dd>
15<dd><a href="/1_1094/15856137.html">第 1016 章 从来没有世界之门!</a></dd>
16<dt>《一念永恒》正文卷</dt> <dd><a href="/1_1094/5386269.html">外传 1 柯父。</a></dd>
17<dd><a href="/1_1094/5386270.html">外传 2 楚玉嫣。</a></dd> <dd><a href="/1_1094/5386271.html">外传 3 鹦鹉与皮冻。</a></dd>
18<dd><a href="/1_1094/5403177.html">第一章 他叫白小纯</a></dd> <dd><a href="/1_1094/5428081.html">第二章 火灶房</a></dd>
19<dd><a href="/1_1094/5433843.html">第三章 六句真言</a></dd> <dd><a href="/1_1094/5447905.html">第四章 炼灵</a></dd>
20</dl>
21</div>
在分析之前,让我们先介绍一个概念:父节点、子节点、孙节点。<div>
和</div>
限定了<div>
标签的开始和结束的位置,他们是成对出现的,有开始位置,就有结束位置。我们可以看到,在<div>
标签包含<dl>
标签,那这个<dl>
标签就是<div>
标签的子节点,<dl>
标签又包含<dt>
标签和<dd>
标签,那么<dt>
标签和<dd>
标签就是<div>
标签的孙节点。有点绕?那你记住这句话:谁包含谁,谁就是谁儿子!
他们之间的关系都是相对的。比如对于<dd>
标签,它的子节点是<a>
标签,它的父节点是<dl>
标签。这跟我们人是一样的,上有老下有小。
看到这里可能有人会问,这有好多<dd>
标签和<a>
标签啊!不同的<dd>
标签,它们是什么关系啊?显然,兄弟姐妹喽!我们称它们为兄弟结点。
好了,概念明确清楚,接下来,让我们分析一下问题。我们看到每个章节的名字存放在了<a>
标签里面。<a>
标签还有一个 href 属性。这里就不得不提一下<a>
标签的定义了,<a>
标签定义了一个超链接,用于从一张页面链接到另一张页面。<a>
标签最重要的属性是 href 属性,它指示链接的目标。
我们将之前获得的第一章节的 URL 和<a>
标签对比看一下:
1http://www.biqukan.com/1_1094/5403177.html
不难发现,<a>
标签中 href 属性存放的属性值/1_1094/5403177.html
是章节 URLhttp://www.biqukan.com/1_1094/5403177.html
的后半部分。其他章节也是如此!那这样,我们就可以根据<a>
标签的 href 属性值获得每个章节的链接和名称了。
总结一下:小说每章的链接放在了 class 属性为 listmain 的<div>
标签下的<a>
标签中。链接具体位置放在 html->body->div->dl->dd->a 的 href 属性中。先匹配 class 属性为 listmain 的<div>
标签,再匹配<a>
标签。编写代码如下:
1# -*- coding:UTF-8 -*-2from bs4 import BeautifulSoup3import requests4if __name__ == "__main__":5 target = 'http://www.biqukan.com/1_1094/'6 req = requests.get(url = target)7 html = req.text8 div_bf = BeautifulSoup(html)9 div = div_bf.find_all('div', class_ = 'listmain')
10 print(div[0])
还是使用 find_all 方法,运行结果如下:
很顺利,接下来再匹配每一个<a>
标签,并提取章节名和章节文章。如果我们使用 Beautiful Soup 匹配到了下面这个<a>
标签,如何提取它的 href 属性和<a>
标签里存放的章节名呢?
1<a href="/1_1094/5403177.html">第一章 他叫白小纯</a>
方法很简单,对 Beautiful Soup 返回的匹配结果 a,使用 a.get('href')方法就能获取 href 的属性值,使用 a.string 就能获取章节名,编写代码如下:
1# -*- coding:UTF-8 -*-2from bs4 import BeautifulSoup3import requests4if __name__ == "__main__":5 server = 'http://www.biqukan.com/'6 target = 'http://www.biqukan.com/1_1094/'7 req = requests.get(url = target) html = req.text8 div_bf = BeautifulSoup(html)9 div = div_bf.find_all('div', class_ = 'listmain')
10 a_bf = BeautifulSoup(str(div[0]))
11 a = a_bf.find_all('a')
12 for each in a:
13 print(each.string, server + each.get('href'))
因为 find_all 返回的是一个列表,里边存放了很多的<a>
标签,所以使用 for 循环遍历每个<a>
标签并打印出来,运行结果如下:
最上面匹配的一千多章的内容是最新更新的 12 章节的链接。这 12 章内容会和下面的重复,所以我们要滤除,除此之外,还有那 3 个外传,我们也不想要。这些都简单地剔除就好。
(3)整合代码
每个章节的链接、章节名、章节内容都有了。接下来就是整合代码,将获得内容写入文本文件存储就好了。编写代码如下:
1# -*- coding:UTF-8 -*-2from bs4 import BeautifulSoup3import requests, sys45class downloader(object):6 def __init__(self):7 self.server = 'http://www.biqukan.com/'8 self.target = 'http://www.biqukan.com/1_1094/'9 self.names = [] #存放章节名
10 self.urls = [] #存放章节链接
11 self.nums = 0 #章节数
12
13 def get_download_url(self):
14 req = requests.get(url = self.target)
15 html = req.text
16 div_bf = BeautifulSoup(html)
17 div = div_bf.find_all('div', class_ = 'listmain')
18 a_bf = BeautifulSoup(str(div[0]))
19 a = a_bf.find_all('a')
20 self.nums = len(a[15:]) #剔除不必要的章节,并统计章节数
21 for each in a[15:]:
22 self.names.append(each.string)
23 self.urls.append(self.server + each.get('href'))
24
25 """
26 函数说明:获取章节内容
27 Parameters:
28 target - 下载连接(string)
29 Returns:
30 texts - 章节内容(string)
31 """
32 def get_contents(self, target):
33 req = requests.get(url = target)
34 html = req.text
35 bf = BeautifulSoup(html)
36 texts = bf.find_all('div', class_ = 'showtxt')
37 texts = texts[0].text.replace('\xa0'*8,'\n\n')
38 return texts
39
40 """
41 函数说明:将爬取的文章内容写入文件
42 Parameters:
43 name - 章节名称(string)
44 path - 当前路径下,小说保存名称(string)
45 text - 章节内容(string)
46 Returns:
47 无
48 """
49 def writer(self, name, path, text):
50 write_flag = True
51 with open(path, 'a', encoding='utf-8') as f:
52 f.write(name + '\n')
53 f.writelines(text)
54 f.write('\n\n')
55
56if __name__ == "__main__":
57 dl = downloader()
58 dl.get_download_url()
59 print('《一年永恒》开始下载:')
60 for i in range(dl.nums):
61 dl.writer(dl.names[i], '一念永恒.txt', dl.get_contents(dl.urls[i]))
62 sys.stdout.write(" 已下载:%.3f%%" % float(i/dl.nums*100) + '\r')
63 sys.stdout.flush()
64 print('《一年永恒》下载完成')
很简单的程序,单进程跑,没有开进程池。下载速度略慢,喝杯茶休息休息吧。代码运行效果如下图所示:
资料已打包,扫下方二维码加我好友:备注:“ Python3小说 ” 获取????长按识别,添加微信
(添加人数较多,会自动通过)推荐:开源库Python 开发者必知的 11 个 Python GUI 库
10款 Web开发最佳的 Python 框架
推荐 GitHub 上100天学习 Python的开源项目
Python绘图还在用Matplotlib?out了 !发现一款手绘可视化神器!面试我用 Python 爬了天猫内衣店的数据Python爬完数据后,我终于买车不用坐引擎盖哭啦
1年工作经验,拿下今日头条 Python 开发面经分享!Python 面试中 8 个必考问题
面试 4 个月,最终入职微软!10 家公司 Python 面试题总结
面试了9家公司,拿到5份Offer面试Python怕? 你想要的315道题都在这了如何拿到半数面试公司Offer——我的Python求职之路学习路线基于TensorFlow 2.0的中文深度学习开源书来了!GitHub趋势日榜第一,斩获2K+星
微软官方上线了Python 教程,7个章节就把Python说通了最全 14 张思维导图:教你构建 Python 编程的核心知识体系Python 从入门到精通:一个月就够了!24招加速你的Python,超级实用!
即学即用的 30 段 Python 非常实用的代码工具最靠谱的Pycharm 汉化安装+ 破解详细教程!Python数据分析、挖掘常用工具
Python 最强 IDE 详细使用指南!
一款 Python 自动抢票神器,收藏起来回家不愁!实践和数据分析Python 开发植物大战僵尸游戏
用 Python 来找合适的妹子
一键分析你上网行为,看你是在认真工作还是摸鱼
Python给照片换底色,基于opencv模块10个经典的小技巧:快速用 Python 进行数据分析使用 Python 进行微信好友分析爬虫我给曾经暗恋的初中女同学,用Python实现了她飞机上刷抖音为了能早点买房,我用 Python 预测房价走势!被女朋友三番五次拉黑后,我用 Python 写了个“舔狗”必备神器谁偷偷删了你的微信?别慌!Python 揪出来为了给女友挑合适的内衣,我用 Python 爬了天猫内衣店的数据Python爬完数据后,我终于买车不用坐引擎盖哭啦这里除了干货一无所有人生苦短,我选在看
实战干货:Python3小说站点爬虫|附下载相关推荐
- 学习笔记-spring-mybatis-jsoup-http-client小说站点爬虫(1)--获取小说站点章节列表
获取小说站点章节列表 第一次写博客,写得不好请见谅 目的是让自己印象更加深刻,锻炼自己表达能力,同时可以和大家一起交流学习,大神勿喷! 本次学习教程来自吾爱破解小说站点爬虫-spring-mybati ...
- Python3 03 网络爬虫 <下载漫画>
@ 我的老师:Jack Cui PS:我是通过 看 Jack Cui 老师的文章 学习的爬虫,也为我之后的 爬虫打开了大门. 3.1 下载漫画 那么这一节,我们就要 去网络上下载漫画.即 图片 的爬取 ...
- 干货集锦:200+生信范文、30+款软件、12类图片素材PPT,今年的SCI稳了!(附下载)...
最近收到不少粉丝的留言,表示快要被论文和课题薅光了头发???? 别慌!稳住!为了满足大家的学习需求,小编特意整理了一份生信学习干货包,需要的同学们手速下载收藏!希望大家科研有进步,论文早见刊,抗起fl ...
- 【干货】微信私域运营实战指南.pdf(附下载链接)
大家好,我是文文,今天给大家分享易观数科.易观方舟和零一裂变联合发布的干货报告<微信私域运营实战指南.pdf>,本文档包含私域"留量"三部曲:获客转化.活客粘客.创造价 ...
- 【干货】小米用户画像实战.pdf(附下载链接)
今天给大家带来小米大数据部武汉用户画像负责人徐函秋先生所做的分享<小米用户画像实战.pdf>,关注用户画像的伙伴们别错过了.本次分享理论和实践(结合小米大数据丰富的实践案例)结合,包含如下 ...
- Python爬虫获取异步加载站点pexels并下载图片(Python爬虫实战3)
Python爬虫获取异步加载站点pexels并下载图片(Python爬虫实战3) 1. 异步加载爬虫 对于静态页面爬虫很容易获取到站点的数据内容,然而静态页面需要全量加载站点的所有数据,对于网站的访问 ...
- 【爬虫实战项目】Python爬虫批量下载音乐飙升榜并保存本地(附源码)
前言 今天给大家介绍的是Python爬虫批量下载音乐飙升榜并保存本地,在这里给需要的小伙伴们代码,并且给出一点小心得. 首先是爬取之前应该尽可能伪装成浏览器而不被识别出来是爬虫,基本的是加请求头,但是 ...
- 【爬虫实战项目】Python爬虫批量下载评书音频并保存本地(附源码)
前言 今天给大家介绍的是Python爬虫批量下载评书音频并保存本地,在这里给需要的小伙伴们代码,并且给出一点小心得. 首先是爬取之前应该尽可能伪装成浏览器而不被识别出来是爬虫,基本的是加请求头,但是这 ...
- 实战|Python轻松实现动态网页爬虫(附详细源码)
用浅显易懂的语言分享爬虫.数据分析及可视化等干货,希望人人都能学到新知识. 项目背景 事情是这样的,前几天我公众号写了篇爬虫入门的实战文章,叫做<实战|手把手教你用Python爬虫(附详细源码) ...
最新文章
- Leetcode12. 整数转罗马数字(C++)
- 用Axis创建的Webservice的集成与发布
- 不一样的视角,程序员世界里的环保
- Android--Pin流程,飞行模式相关流程总结【工作日记一】
- kr中的逆波兰表示法计算器
- Zookeeper学习笔记——1 单机版本环境搭建
- 同事:你居然还在用 try catch 处理异常? 有点Low啊
- 定时重启_SpringBoot基于数据库的定时任务实现方法
- android怎么用经纬度定位,android 根据经纬度定位所在城市
- 2021年运维工程师主要职责和就业前景
- 【安全攻防知识-4】CTF之MISC
- DaZeng:Vue全家桶实现小米商城(二)
- 正则正数,负数,整数,浮点数校验大全
- HTML5期末大作业:动漫人物介绍网站设计——柯南(5页) 含报告 HTML+CSS+JavaScript dw网页设计 web网页设计与开发
- ospf协议(包含负载分担)
- 征服统计学09|统计学里的p值有何意义
- UIToolBar实现高斯模糊
- 《STL源码剖析》问题总结
- 多线程下载器 IDM
- c语言数学语文英语成绩编程,输入10名学生的序号和每个学生三门功课(数学、英语、C语言程序设计)的成绩,编程计算出每个学生的总分...