如何利用Python爬取网络小说

1 LSGO软件技术团队

贡献人:马子轩

如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。

If you like the content here, the greatest helpyou can give meis forwarding, so tell your friends and encourage them to learn together.

我们在学习Python之余总想着让其更具趣味性,可以更好地学习。下面我将讲解如何从网站中爬取我们想看的小说。让我们枯燥无聊的学习生涯稍微多些趣味。

需要只是一点点对requests库、Beautiful库及 python 基础知识的了解。

Python版本:Python3.X

运行平台:Windows

IDE:PyCharm

浏览器:Chrome

本次讲解所有代码已放入GitHub上托管。

https://github.com/siwuya520/python-web-crawler.git

了解爬虫

我们一直口口声声说着用爬虫去爬取某某数据。

那么问题来了,什么是爬虫呢?

网络爬虫,别称网络蜘蛛,它是一段程序(一个脚本),能够模拟浏览器自动的浏览网页,来自动地批量地采集我们需要的资源。

废话不多说,开始今天的爬虫之旅。

爬取章节内容

俗话说得好,饭要一口一口吃,路要一步一步走。我们要爬取每一章内容,须先知晓如何爬取一章内容。

本次爬取网站:笔趣阁 http://www.biquge.cm/

本次爬取小说:《修真四万年》 http://www.biquge.cm/6/6217/

第一步,根据URL获取网页的HTML信息

在python3中可以用requests库进行网页爬取。

import requests

if __name__=='__main__':

target='http://www.biquge.cm/6/6217/3638117.html'

req=requests.get(url=target)

print(req.text)

运行结果如下:

我们轻松地获得了HTML信息,但为什么会出现乱码呢?

事实上这是由于字符编码问题引起的。往往用requests库抓取中文网页时容易出现乱码问题。那如何解决呢?

下面介绍两种方法:

(1)我们可以在调用response.text()之前使用response.encoding='编码格式'

这个方法需要我们进入所爬去网站去查看编码格式。

点击鼠标右键,点击检查,得到如下界面:

点击右侧head标签得到如图:

可以很显然看到编码格式为‘gbk’。

所以我们可以写出代码来解决乱码问题:

import requests

if __name__=='__main__':

target='http://www.biquge.cm/6/6217/3638117.html'

req=requests.get(url=target)

req.encoding='gbk'

print(req.text)

运行得到:

(2)使用req.content返回bytes型数据,然后将bytes型数据转化为str数据。

代码如下:

import requests

if __name__=='__main__':

target='http://www.biquge.cm/6/6217/3638117.html'

req=requests.get(url=target)

html=req.content

html_doc=str(html,'gbk')

print(html_doc)

解决完乱码问题后我们得到了我们需要的能理解看懂的html信息,但是,有很多信息是我们不想看到的,我们只想要小说正文内容。我们不关心div、br这些html标签。

那如何把正文内容从这些众多的html标签中提取出来呢?

这就用到了BeautifulSoup库。

同理按上面方法我们查看第一章目标网页:

我们可以看到文章的所有内容都放在了一个名为div的东西下面,这个东西就是html标签。HTML标签是HTML语言中最基本的单位,HTML标签是HTML最重要的组成部分。

我们可以看到,我们所需的文本内容在一个div标签下,这个标签是这样的:

div id="content"

知道了这个内容,我们就可以用BeautifulSoup来提取我们想要的内容了。编写代码如下:

from bs4 import BeautifulSoup

import requests

if __name__=='__main__':

target='http://www.biquge.cm/6/6217/3638117.html'

req=requests.get(url=target)

html=req.content

html_doc=str(html,'gbk')

bf=BeautifulSoup(html_doc)

texts=bf.find_all('div',id="content")

print(texts)

在解析html之前,先创建一个BeautifulSoup对象,BeautifulSoup函数里面的参数就是我们获得的html信息。然后使用find_all方法,获取html信息中所有id属性为content的div标签。

运行代码查看我们匹配结果:

我们可以看到,我们已经顺利匹配到我们关心的正文内容,但是还有一些我们不想要的东西。比如div标签名,br标签,以及各种空格。怎么去除这些东西呢?我们继续编写代码:

from bs4 import BeautifulSoup

import requests

if __name__ == "__main__":

target = 'http://www.biquge.cm/6/6217/3638117.html'

req = requests.get(url = target)

html = req.content

html_doc=str(html,'gbk')

bf = BeautifulSoup(html_doc)

texts = bf.find_all('div', id="content")

print(texts[0].text)

find_all匹配的返回的结果是一个列表。提取匹配结果后,使用text属性,提取文本内容,滤除br标签。得到:

我们已经顺利获得了一个章节的内容,要想下载正本小说,我们就要获取每个章节的链接。我们先分析下小说目录:http://www.biquge.cm/6/6217/

在网址进行审查得到:

我们看到每个章节的名字存放在了标签里面。标签还有一个href属性。标签定义了一个超链接,用于从一张页面链接到另一张页面。 标签最重要的属性是href属性,它指示链接的目标。

我们将之前获得的第一章节的 URL 和标签对比看一下:

http://www.biquge.cm/6/6217/3638117.html

我们可以看到 标签中href属性存放的属性值/1_1094/5403177.html是章节 URL http://www.biqukan.com/1_1094/5403177.html的后半部分。那这样,我们就可以根据标签的href属性值获得每个章节的链接和名称了。

编写代码如下:

from bs4 import BeautifulSoup

import requests

if __name__ == "__main__":

target = 'http://www.biquge.cm/6/6217/'

req = requests.get(url = target)

html = req.content

html_doc=str(html,'gbk')

div_bf = BeautifulSoup(html_doc)

div = div_bf.find_all('div', id='list' )

print(div[0])

运行结果:

接下来再匹配每一个标签,并用a.get('href')方法获取href的属性值,使用a.string方法获取章节名。代码如下:

from bs4 import BeautifulSoup

import requests

if __name__ == "__main__":

server = 'http://www.biquge.cm/'

target =  'http://www.biquge.cm/6/6217/'

req = requests.get(url = target)

html = req.content

html_doc=str(html,'gbk')

div_bf = BeautifulSoup(html_doc)

div = div_bf.find_all('div', id='list'  )

a_bf = BeautifulSoup(str(div[0]))

a = a_bf.find_all('a')

for each in a:

print(each.string, server + each.get('href'))

find_all返回的是一个列表,里边存放了很多的标签,所以使用for循环遍历每个标签并打印出来,运行结果如下:

整合代码:

# -*- coding:UTF-8 -*-

from bs4 import BeautifulSoup

import requests, sys

class downloader(object):

# 类说明下载笔趣阁修真四万年,self只有在类的方法中才会有,

# 独立的函数或方法是不必带有self的。self在定义类的方法时是必须有的,

# 虽然在调用时不必传入相应的参数。

def __init__(self):  # 初始化变量

# 爬取图书网站,self.server='http://www.biquge.cm/' 的意思

# 就是把外部传来的参数server的值赋值给类downloader自己的属性

# 变量self.server,下面函数可共用

self.server = 'http://www.biquge.cm/'

self.target = 'http://www.biquge.cm/6/6217/'

# 爬取图书主目录所在网址,用来获取每一章节url

self.names = []  # 存放章节名

self.urls = []  # 存放章节链接

self.nums = 0  # 章节数

def get_download_url(self):  # 获取下载链接

req = requests.get(url=self.target)  # 获得该网页的html信息

html = req.content  # #获得html文件

html_doc=str(html,'gbk')

div_bf = BeautifulSoup(html_doc)  # 创建一个BeautifulSoup对象

div = div_bf.find_all('div', id='list')

# 匹配div标签,获取id属性list的内容,用find_all是因为获得的是列表

a_bf = BeautifulSoup(str(div[0]))  # 以list中的内容构建Beautiful对象

a = a_bf.find_all('a')  # 找到所有a标签,a标签中为每一章网址

self.nums = len(a[:])  # 索引从第一章到最后一章,记数

for each in a[:]:

self.names.append(each.string)  # 添加a标签下的字符串即章节名

self.urls.append(self.server + each.get('href'))

# 获取每一章链接,用get()方法获取a标签中href属性

def get_contents(self, target):  # 获取章节内容

req = requests.get(url=target)

html = req.content

html_doc=str(html,'gbk')

bf = BeautifulSoup(html_doc)

texts = bf.find_all('div', id="content")

# 获取div标签id属性content的内容

texts = texts[0].text.replace('\xa0'*8,'\n')

# 剔除"'div'标签及'id=content'"和br/,

# 提取texts内容中text文本

return texts

def writer(self, name, path, text):  # 将爬取的文章内容写入文件

with open(path, 'a' ,encoding='utf-8')as f:

# ‘a’表示追加到文件,encoding='utf-8'表示以utf-8进行编码

f.write(name + '\n')  # write方法写入章节名并换行

f.writelines(text)  # writelines方法写入文章内容

f.write('\n')  # 换行写完一章

# 当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行

if __name__ == "__main__":

dl = downloader()

dl.get_download_url()

print('《修真四万年》开始下载:')

for i in range(dl.nums):

dl.writer(dl.names[i], '修真四万年.txt', dl.get_contents(dl.urls[i]))

sys.stdout.write("  已下载:%.3f%%" % float(i / dl.nums) + '\r')

# sys.stdout是映射到打开脚本的窗口

sys.stdout.flush()

# 在Linux系统下,必须加入sys.stdout.flush()才能一秒输一个数字

# 在Windows系统下,加不加sys.stdout.flush()都能一秒输出一个数字

print('《修真四万年》下载完成')

到此为止,利用Python爬取小说的过程就全部介绍完了,希望能够帮助大家!See You!

经过8年多的发展,LSGO软件技术团队在地理信息系统、数据统计分析、计算机视觉领域积累了丰富的研发经验,也建立了人才培养的完备体系。

欢迎对算法设计与实现感兴趣的同学加入,与我们共同成长进步。

本微信公众平台长期系统化提供有关机器学习、软件研发、教育及学习方法、数学建模的知识,并将以上知识转化为实践。拒绝知识碎片化、耐心打磨技能、解决实际问题是我们的宗旨和追求。

欢迎关注,请扫描二维码:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180922B010SA00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券