爬虫入门_文本抽取

Background

浏览器作为客户端,接收服务器返回的消息,进行解析后展示给我们。我们可以在本地修改html信息,对网页进行“整容”,要知道网页的任何信息都可以被修改,但是修改后的信息不影响服务器端,刷新后又会变成之前服务器端推送的格式。

审查元素

有了上面的认识后,怎样修改网页的html信息呢?在你想要修改页面的某个位置右击,继续点击审查,即可获得该位置的html信息。Eg:在邮箱登陆输入密码的位置点击审查元素,将password属性改为text,输入密码时将不再是小圆点的形式。

网页的全部信息都在其html语句中,接下来我们采用python中的requests模块,获取网页的html信息。

安装python http模块requests

1
pip3 install requests

这里简单的提取一个网络小说的html信息

1
2
3
4
target = 'http://www.biqukan.com/1_1094/5403177.html'
req = requests.get(url=target)
html = req.text
print(html) # 网页html内容,同右键后的网页审查内容

requests模块获取的信息为带标签(div、br…)的html信息,还需要通过下面的beautifulsoup模块,提取中我们感兴趣的段落。

安装文本提取模块Beautiful Soup

python的第三方库,用于从html、xml文件中提取数据,以树状结构的方式执行查询。并且支持正则表达式的模糊匹配。
图片名称

1
pip3 install beautifulsoup4

这里引用Jack-Cherish对html的解释:

“一个女人的包包里,会有很多东西,她们会根据自己的习惯将自己的东西进行分类放好。镜子和口红这些会经常用到的东西,会归放到容易拿到的外侧口袋里。那些不经常用到,需要注意安全存放的证件会放到不容易拿到的里侧口袋里”。而html标签就像一个个“口袋”,每个“口袋”都有自己的特定功能,负责存放不同的内容。

例如:上述例子中的div标签下存放了我们关心的正文内容。这个div标签是这样的:

1
<div id="content", class="showtxt">

id和class就是div标签的属性,content和showtxt是属性值,一个属性对应一个属性值。它是用来区分不同的div标签的,因为div标签可以有很多,我们怎么加以区分不同的div标签呢?就是通过不同的属性值。可以发现网络小说的正文部分正唯一的对应于class=”showtxt”的div标签下。

1
2
3
4
bf = BeautifulSoup(html) # find 一对标签:<div> </div>之间的内容
texts = bf.find_all('div', class_ = 'showtxt') # 第一个参数是获取的标签名,第二个参数class_是标签的属性
print(texts[0].text.replace('\xa0'*8,'\n\n'))
#使用text属性,提取文本内容,滤除br标签; 之后进行换行符替换及提取文本部分内容

BeautifulSoup函数处理完后,可见的是提取出了该小说完整的的正文内容。

获取每个章节的链接

章节信息都放在了class = listmain的div标签下,获取方法同上。链接和章名都放在了标签<a>、</a>之间,Eg:<a href="/1_1094/5403177.html">第一章 他叫白小纯</a>

1
2
3
4
5
6
7
8
<div class="listmain">
<dl>
<dt>《一念永恒》最新章节列表</dt>
<dd><a href="/1_1094/15932394.html">第1027章 第十道门</a></dd>
<dd><a href="/1_1094/15923072.html">第1026章 绝伦道法!</a></dd>
<dd><a href="/1_1094/15921862.html">第1025章 长生灯!</a></dd>
</dl>
</div>

通过两次调用BeautifulSoup,便可以获取一对标签<a>、</a>之间的内容。

1
2
3
4
5
6
7
8
req = requests.get(url = target) 
html = req.text
div_bf = BeautifulSoup(html)
div = div_bf.find_all('div', class_ = 'listmain')
a_bf = BeautifulSoup(str(div[0]))
a = a_bf.find_all('a')
for each in a:
print(each.string, server + each.get('href'))

完整地爬取一部小说程序整合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# -*- coding:UTF-8 -*-
from bs4 import BeautifulSoup
import requests
import sys

class downloader(object):
"""下载小说《一念永恒》"""
def __init__(self):
self.server = "http://www.biqukan.com/"
self.target = "http://www.biqukan.com/1_1094/"
self.names = [] # 存放章节名称
self.urls = [] # 存放每章链接
self.nums = [] # 章节数量

def get_download_url(self):
"""获取下载链接url及每章名称names,以list形式放到实例化后的class中"""
req = requests.get(url = self.target)
html = req.text
div_bf = BeautifulSoup(html)
div = div_bf.find_all('div', class_ = 'listmain')
# 获取到章节名称的html信息,在class = 'listmain'中
a_bf = BeautifulSoup(str(div[0]))
a = a_bf.find_all('a') # 返回一个list
self.nums = len(a[15:]) # 过滤了前15条噪声章节
for each in a[15:]:
self.names.append(each.string)
self.urls.append(self.server + each.get('href'))

def get_contents(self, target):
"""
函数说明:获取class_list中每一个url下的内容
target:下载地址
return: texts - 内容(string类型)
"""
req = requests.get(url = target)
html = req.text
bf = BeautifulSoup(html)
texts = bf.find_all('div', class_ = 'showtxt')
texts = texts[0].text.replace('\xa0'*8, '\n\n')
return texts

def writer(self, name, path, text):
"""
函数说明:爬取的texts写入文件
name:章节名称
path:文件路径
text:章节内容
"""
with open(path, 'a',encoding='utf-8') as f:
f.write(name + '\n') # write只能写入str
f.writelines(text) # 自动迭代写入一个字符串列表[str]
f.write('\n\n')

if __name__ == "__main__":
dl = downloader() # 类的实例化
dl.get_download_url() # 获取章节名称信息,更新类中的list变量names、urls、nums
print('开始下载...')
# print(type(dl.nums)) # int型,跟最后定义nums的变量相关
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.flush()
print("Success!")

Refer:

Python3网络爬虫快速入门实战解析
Python开发简单爬虫
当一个颜值很高的程序员是怎样一番体验?