本文主要是介绍Python 网络爬虫从0到1 (4):Beautiful Soup 4库入门详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
从先前的几篇文章中,我们已经能够使用Requests库构造请求并获得正确的响应,但是在样例中我们也发现了仅使用Requests库的缺陷。在网络爬虫的设计中,仅能构造请求并收到响应是远远不够的。想要获取响应中有意义的信息并能够由此采取下一步行动,是整个流程中的重要一段。所以本篇文章,我们就来一起学习较为流行的HTML/XML数据分析提取库:Beautiful Soup 4
Beautiful Soup 4介绍
Beautiful Soup 4库是一个在Python爬虫设计中非常流行的数据分析提取库。它能够解析HTML/XML语言并生成文档树。由于其简单易用的特性被许多小型爬虫所采用。
HTML语言作为一种标记语言,每一个元素都由一对标签包含,层层嵌套形成树状结构。当人去阅读这段代码时,实际内容会被一大串描述元素样式的代码淹没,观察较为繁琐;但程序阅读恰恰相反,标签化、结构化且严谨的语法非常适合程序(浏览器等)理解分析,并按照当初设计的方式渲染重构网页。
我们获得的来自服务器的响应一般为HTML格式的一个页面,由于HTML语言特性,人类难以直观理解实际效果,这就需要一个程序来解析这个响应。浏览器核心也包含一个HTML解析器,而在爬虫中,Beautiful Soup 4库就起到了这样的效果。
至于这个Python库的名称为什么是BeautifulSoup4
(即bs4
)而不是BeautifulSoup
,是因为后者已经用来表示BeautifulSoup3
库(为了兼容性原因仍然保留),为避免名称冲突,才使用这个名字。
关于这个库的更多信息以及使用指南,请参阅Beautiful Soup 4官方手册(中文)Beautiful Soup 4.4.0 文档
Beautiful Soup 4库的安装、引用与测试
- Beautiful Soup 4包安装与安装其他库包的方法相同,Windows cmd/Linux Terminal 下,输入如下命令
pip install beautifulsoup4
等待安装完成即可。
- 引用这个库的方法与其他库略有不同,实际上,Beautiful Soup 4是一个类,包含在
bs4
包中,使用时只需要从包中单独引用BeautifulSoup类即可。使用from-import语句实现
from bs4 import BeautifulSoup
注意:BeautifulSoup
中的B
与S
为大写字母,Python对大小写敏感
- 下面使用一个小样例来测试Beautiful Soup 4的功能,该类的基本功能会在下面讲到
示例实现步骤
- 使用
Requests
库下载了一个样例页面 - 将响应主体(HTML格式)作为参数声明了一个
BeautifulSoup
实例soup
- 使用其
prettify()
方法将主体内容进行了优化并输出
import requests
from bs4 import BeautifulSoupr = requests.get("http://python123.io/ws/demo.html")
# 提交请求抓取响应
# print(r.text)
soup = BeautifulSoup(r.text, features="html.parser")
# 声明实例并将响应主体作为参数传入
print(soup.prettify())
#使用prettify()方法输出优化后的内容
BeautifulSoup类使用
HTML基础知识
在了解BeautifulSoup
类的原理前,先来补充一点HTML语言的相关知识。
HTML语言的各个元素均由标签构成,一对一对标签以及中间包括的内容构成了元素,例如:
<p class="title">Hello World</p>
其中,
-
p
:标签名称,p表示段落(paragraph) -
class="title"
:标签的属性,属性键为class
,值为"title"
,这个属性与CSS样式表相关 -
Hello World
:标签主体内容 -
/p
:标签结束符号,与p
标签开始符号一一对应 -
标签开始部分(标签名称和属性)与标签结束都由尖括号包含,两个尖括号中间的内容为标签主体内容
这样的标签嵌套叠加,形成了一个树状结构,被称为文档树
附表:HTML常用标签
标签 名称 | 说明 |
---|---|
<a> | 链接 |
<b> | 普通文本 |
<body> | 文档主体内容标签 |
<div> | HTML文档中的分隔区块 |
<form> | 创建表单用于用户输入 |
<hn> | 标题,n为等级1-6 |
<img> | 图片 |
<span> | 对一部分文本进行着色 |
<script> | JavaScript脚本 |
BeautifulSoup类实例化
BeautifulSoup
类中的一个实例正与一个文档树一一对应(类本身也是)。**声明一个新的实例时,将HTML内容作为参数传递给实例初始化函数,这个HTML内容所对应的文档树就按照BeautifulSoup
类的结构被对应到了实例中。**通过Beautiful Soup库,我们能够对文档树进行解析、遍历、维护。
在初始化一个BeautifulSoup
实例时,不仅需要提供HTML文档内容作为参数,还需要选择一个适合的解释器
解析器 | 名称 | 优点 | 缺点 |
---|---|---|---|
Python标准库解析器 | html.parser | 是Python内置标准库 执行速度适中 文档容错能力强 | 较早版本Python中的解析器容错能力弱且不稳定 |
lxml HTML解析器 | lxml | 速度快 文档容错能力强 | 依赖C语言库 |
lxml XML解析器 | lxml-xml | 速度快 唯一一个XML解析器 | 依赖C语言库 |
html5lib | html5lib | 容错性最佳 以浏览器方式解析文档 生成html5格式文档 | 速度慢 不依赖外部拓展 |
其中,Python标准库解析器在Python标准库中,不需要另外安装;其他的解析器需要自行安装第三方库(lxml的两个解析器安装lxml
包,html5lib解析器安装html5lib
包)
声明一个新实例的语法(尖括号仅表示名称,不在语法中)
<Name> = BeautifulSoup(<HTML Document>, features="<Parser Name>")
其中,
Name
:新实例的名称HTML Document
:需要解析的HTML文档,以字符串形式,也可以为打开的文件Parser Name
:解析器名称,各个解析器的名称见上表
BeautifulSoup类的基本元素
基本元素 | 说明 |
---|---|
Tag | 标签,为文档的最基本组成元素,上面已经介绍 |
Name | 标签的名称,例如标签名称为p,调用格式为<tag>.name |
Attributes | 标签的属性,以字典形式组织,调用格式为<tag>.attrs |
NavigableString | 可以遍历的字符串,为标签内非属性字符串,即为上面提到的标签主体内容,格式<tag>.string |
Comment | 标签内字符串的注释部分,是一种特殊的NavigableString ,格式同上 |
Text | 标签中的主体内容(不含注释),格式<tag>.text |
Beautiful Soup | 整个文档对应的类的实例,这个元素的名称为[document] |
- 标签元素的类型为
bs4.element.Tag
- 标签的NavigableString不是一个str类型数据,而是Beautiful Soup 4中另行定义的类型
bs4.element.NavigableString
- 关于各种属性的使用方法,请见下面的
BeautifulSoup标签的属性
BeautifulSoup类获取标签
基本元素中,除了Tag
为独立的标签元素外,其余所有都可以视作Tag
的属性,那么,如何从BeautifulSoup类中提取一个标签呢?我们以实例soup
为例
tag_a = soup.a
tag_p = soup.p
实际上,使用soup.就可以获得实例对应文档树中第一个名称为tag name
的标签,如果文档树中不存在这个标签,不会报错,而是返回空,且这些标签名称由于不固定,IDE不提供代码补全,所以要小心标签名称错误
注意,使用这个方法只能获得文档中的一个标签,如果需要其他标签,请使用后面讲到的文档遍历
BeautifulSoup标签的属性
标签的属性在上面的基本元素中已经基本给出,下面挑选必要的属性逐个介绍
Attributes
:标签属性域中的属性,为字典形式,对于HTML中已经定义的多值属性,将返回一个List
(即使只有一个也返回List)- 如果该标签没有属性,将返回为空
- 由于属性为字典格式,可以使用字典的相关操作,例如单独输出某个键的值
tag.attrs['class']
NavigableString
:标签中的主要内容(可遍历字符串),即两对尖括号中间的内容- 如果该标签没有可遍历字符串,则返回空
- 如果不为空,
NavigableString
不是一个str
普通字符串型数据,而是Beautiful Soup 4中另行定义的类型bs4.element.NavigableString
- 如果一个标签的主体部分既有文本又有注释,则string为空,请见
Text
Comment
:标签中的注释内容,注意:Comment
为一种特殊的NavigableString
,其使用方法与返回形式完全相同,即使用string,两个返回格式相同,无法从这里区分Comment
与NavigableString
,需要用类型或Text判断- 不同于普通的
NavigableString
,Comment
有自己独有的类型bs4.element.Comment
- 如果一个标签的主体部分既有文本又有注释,则string为空,请见
Text
- 不同于普通的
Text
:标签中的主要内容(不包含注释),也是两对尖括号中的内容- 与NavigableString不同的是,Text在文本与注释同时出现时,会过滤注释内容,仅保留文本内容
Text
的类型为str
,为Python标准类型
Beautiful Soup HTML文档遍历方法
Beautiful Soup 支持HTML文档树的上行遍历
、下行遍历
、平行遍历
三种遍历方法。所有遍历均通过查询当前标签的属性实现,即
<tag>.<attribute>
下行遍历
从根节点元素开始向文档叶节点遍历(寻找子节点)
Beautiful Soup 为下行遍历提供了三个属性
属性 | 说明 |
---|---|
.contents | 子节点列表,将这个标签的所有子节点(下一层)以列表形式给出 |
.children | 子节点的可迭代类型对象,生成这个标签所有子节点(下一层)的可迭代列表对象 |
.descendants | 子孙节点的可迭代类型对象,包含这个标签所有子孙节点(下面所有) |
- 注意:子节点不仅有标签类型,也有其他字符串,如
\n
换行符或纯文本,这些字符串的类型为NavigableString
- 可迭代类型的原文为
list_iterator object
.descendants
的遍历顺序为先序遍历
上行遍历
从叶节点元素开始向文档根节点遍历(寻找父节点)
Beautiful Soup 为上行遍历提供了两个属性
属性 | 说明 |
---|---|
.parent | 父节点,这个标签的父节点,仅一个 |
.parents | 先辈节点、这个节点的所有父节点的迭代(父节点、父节点的父节点……) |
- 仅在最高一级的根节点
[document]
节点(参见上文HTML基础知识中文档树结构图)的类型为BeautifulSoup
,即为BeautifulSoup本身,其他节点的类型均为bs4.element.Tag
- 根节点的父节点为空
平行遍历
在平行节点间横向遍历,平行节点,即兄弟节点,指父节点为同一个节点的一系列节点
Beautiful Soup 为平行遍历提供了四个属性
属性 | 说明 |
---|---|
.next_sibling | 按照HTML文本序的下一个平行节点 |
.previous_sibling | 按照HTML文本序的上一个平行节点 |
.next_siblings | 按照HTML文本序的下面所有平行节点 |
.previous_sibling | 按照HTML文本序的上面所有平行节点 |
-
注意:平行节点不仅有标签类型,也有其他字符串,如
\n
换行符或纯文本等,这些字符串的类型为NavigableString
,使用时请注意区分 -
可以通过判断该元素的
name
属性是否为None来确定该元素是否为NavigableString
(若使用类型判断,则需要导入整个bs4)if not tag.name is None:do_something()
Beautiful Soup HTML文档优化
使用Requests
库得到的响应文档未经过处理(换行、缩进等),且由于HTML的特性,没有渲染情况下可读性较差,需要通过优化提升可读性,Beautiful Soup
类的Prettify()
方法提供了这个功能。需要将返回值打印才能看到效果(只是在其中添加换行符)
soup = BeautifulSoup(HTML_text, "html.parser")
print(soup.prettify())
基于Beautiful Soup库的HTML内容查找方法
查找标签find_all()
Beautiful Soup提供了一个专用的方法用来查找指定名称的标签
soup.find_all('name')
#soup 为搜索范围的Tag或BeautifulSoup对象,name 为要查找的标签名称
函数返回一个列表,包含所有符合名称的标签
-
由于列表可遍历(可迭代),可以使用for语句遍历整个搜索结果列表,列表中的元素类型仍然为
bs4.element.Tag
-
当想要获取多个类型的标签时,可以将一个包含有欲查找标签名称(字符串类型)的列表作为参数传入标签
-
当想要获得这个soup中的所有标签时(相当于树遍历),可以将参数变为
True
-
如果还想要进一步限制查找内容,
find_all()
函数还提供了class
属性参数soup.find_all('name', 'attr')
这将搜索所有名称为
name
且class
类属性为attr
的标签
如果将name
设为空''
,则将返回所有class
符合的标签,而不限制标签名称 -
还可以限制id属性
soup.find_all(id = 'link1')
这将搜索所有
id
属性为"link1"的标签 -
这个函数的另一个参数
recursive
递归,默认为True
,表示将遍历该标签对象下的所有子孙节点,否则只遍历该节点的子节点 -
又一个参数
string
,可以搜索标签主体内容(一对尖括号中间的内容),返回类型为NagivableString
必须精确匹配内容才能搜索到,实际没有太大意义,以后将使用正则表达式标准库
re
来完成正则表达式匹配搜索
其他查找语句
除了find_all()外,Beautiful Soup还提供了其他特性的搜索函数,这些函数的参数与find_all()
相同,有对应需求时,直接使用函数即可
函数 | 说明 |
---|---|
.find() | 搜索且只返回第一个结果 |
.find_parents() | 在先辈节点中搜索,返回列表 |
.find_parent() | 在先辈节点中搜索,且只返回一个结果 |
.find_next_siblings() | 在后续平行节点中搜索,返回一个列表 |
.find_next_sibling() | 在后续平行节点中搜索,且只返回一个结果 |
.find_previous_siblings() | 在之前的平行节点中搜索,返回一个列表 |
.find_previous_sibling() | 在之前的平行节点中搜索,且只返回一个结果 |
这篇关于Python 网络爬虫从0到1 (4):Beautiful Soup 4库入门详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!