BeautifulSoup库
简介
在Beautiful Soup 4.2.0 官方文档中写道:Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方式.使用Beautiful Soup会帮你节省数小时甚至数天的工作时间。实际上它确实的非常好用,接下来我将介绍它的安装和使用方法。
安装与导入
首先,BeautifulSoup已经被移植到了beautifulsoup4库之中,因此使用它我们需要安装beautifulsoup4库,安装方法还是那么简单,在联网条件下以管理员身份在cmd
命令行输入:
pip install beautifulsoup4
使用的话导入方法为:
from bs4 import BeautifulSoup
其中bs4即使beautifulsoup4,只不过是它的简称罢了。
使用方法
首先,BeautifulSoup是我们用来解析html页面的,它允许我们传入一段字符串(这个字符串原理上应该是网页的源代码,毕竟我们是用它来解析网页)或者文件句柄:
soup = BeautifulSoup(open('xxx.html'))
or
soup = BeautifulSoup('<html>data<html>')
之后,文档将首先被转换成Unicode,并且HTML的实例都被转换成Unicode编码,然后它会使用解析器来解析这段文档,这个解析器是我们可以人工指定的,不过它一般会默认使用库中自带的解析器,下面是几种可选择的解析器及使用方法和条件:
解析器名称 | 调用方法 | 使用条件 | 特点 |
---|---|---|---|
bs4的HTML解析器 | BeautifulSoup(markup,‘html.parser’) | 安装bs4库 | 执行速度适中,文档容错能力强 |
lxml的HTML解析器 | BeautifulSoup(markup,‘lxml’) | 安装lxml库 | 执行速度快,文档容错能力强 |
lxml的XML解析器 | BeautifulSoup(markup,‘xml’) | 安装lxml库 | 执行速度快,支持xml的解析器 |
html5lib的解析器 | BeautifulSoup(markup,‘html5lib’) | 安装html5lib库 | 最好的文档容错能力,以浏览器方式解析文档,生成html5格式的文档,执行速度慢 |
BeautifulSoup中的对象
Beautiful Soup将复杂的HTML文档解析成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为5种: Tag , Name,Attributes,NavigableString , Comment,说明如下:
对象 | 说明 |
---|---|
Tag | 标签,最基本的信息单元,分别用<>和</>标明开头和结尾 |
Name | 标签的名字,如< p >…< /p >的名字就是’p’ |
Attributes | 标签的属性,往往以字典形式组织 |
NavigableString | 标签内的非属性字符串 |
Comment | 标签内字符串的注释部分一种特殊类型 |
提取数据
我们现在知道了BeautifulSoup库将我们给它的HTML文档解析成一个树形结构,它的结构是非常清晰的,有多清晰呢,下面给个例子:
>>> from bs4 import BeautifulSoup #导入库
>>> html = '''<html><head><title>abcd
</title></head>\n<body>\n<p class="title"><b>efg.</b></p>\n<p class="
course">hjkl
:\r\n<a class="py1" href="htt
p://www.qwer.com" i
d="tyui">opasd</a> and <a class="py2" h
ref="http://www.tyui.com" id="hjkl">zxcv
</a>.</p>\n</body></html>'''
>>> soup = BeautifulSoup(html,'html.parser') #解析字符串html
>>> print(soup.prettify()) #prettify函数将文档树格式化输出
<html>
<head>
<title>
abcd
</title>
</head>
<body>
<p class="title">
<b>
efg.
</b>
</p>
<p class="course">
hjkl
:
<a class="py1" d="tyui" href="htt
p://www.qwer.com" i="">
opasd
</a>
and
<a class="py2" h="" id="hjkl" ref="http://www.tyui.com">
zxcv
</a>
.
</p>
</body>
</html>
我们可以看到,当我们的HTML文档被解析后,它的结构真的像数树一样清晰哎,这个时候我们想要获得目标数据有两种方法,一种是遍历整个文档树,另一种是从整个文档树中进行搜索。而遍历文档树有三种方法,分别是:
- 下行遍历
- 上行遍历
- 平行遍历
文档树遍历
注意,后文所有示例的HTML文档均以上文中的那碗soup
为准。
下行遍历
下行遍历有三个属性供我们使用:
属性 | 作用 |
---|---|
< tag >.contents | 返回子节点的列表,即将< tag >的所有儿子节点存入列表 |
< tag >.children | 子节点的迭代类型,用来循环遍历儿子节点 |
< tag >.descendants | 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历 |
示例如下:
>>> soup.contents
[<html><head><title>abcd
</title></head>
<body>
<p class="title"><b>efg.</b></p>
<p class="course">hjkl
:
<a class="py1" d="tyui" href="htt
p://www.qwer.com" i="">opasd</a> and <a class="py2" h="" id="hjkl" ref="http://www.tyui.com">zxcv
</a>.</p>
</body></html>]
#可以看到,对soup使用contents,返回的时列表类型
>>> soup.p.contents
[<b>efg.</b>]
#这里可以看到,对其子节点p使用contents,返回的只有第一个p的子节点,所以说,
#soup.p返回soup的第一个p子节点,并不返回其它的p子节点
#而childre和descendants都是迭代类型了,应该配合for in使用,如下:
>>> for tag in soup.body.children:
print(tag.name)
>>> for tag in soup.body.descendants:
print(tag)
#迭代类型应该如此使用,至于返回结果是什么大家可以试试
在这里为什么说是属性而不是函数呢,因为函数是需要参数的,即使是没有参数也应该有个空括号,而属性的引用是不需要加括号的。
此外上行遍历和平行遍历不再举例,具体方法参考下行遍历。
上行遍历
上行遍历有两个属性供我们使用:
属性 | 作用 |
---|---|
< tag >.parent | 返回< tag >的父亲标签 |
< tag >.parents | 节点先辈标签的迭代类型,用来循环遍历先辈节点 |
平行遍历
平行遍历有四个属性:
属性 | 作用 |
---|---|
< tag >.next_sibling | 返回按照HTML文本顺序的下一个平行节点标签 |
< tag >.previous_sibling | 返回按照HTML文本顺序的上一个平行节点标签 |
< tag >.next_siblings | 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签 |
< tag >.previous_siblings | 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签 |
平行遍历是在同一父亲节点下的遍历,当两个标签不在同一父亲节点下时不进行遍历。
在标签树中,所有节点也可能是NavigableString类型,也就是说那个节点可能不是标签类型而是一个字符串类型,这样你遍历的对象就可能是一个字符串。
搜索文档树
搜索文档树是可以让我们直接在整个文档树中搜索和我们需要的目标匹配的节点数据,一个非常有用且常用的函数是:
< tag >.find_all(name,attrs,recursive,string,**kwargs)
其中各参数及其作用如下:
参数 | 作用 |
---|---|
name | 对标签名称的检索字符串 |
attrs | 对标签属性值的检索字符串,可标注属性检索 |
recursive | 是否对子孙全部检索,默认为True |
string | < tag >…</ tag >中字符串区域的检索字符串 |
示例如下:
>>> soup.find_all(name='a')
[<a class="py1" d="tyui" href="htt
p://www.qwer.com" i="">opasd</a>, <a class="py2" h="" id="hjkl" ref="http://www.tyui.com">zxcv
</a>]
>>> soup.body.find_all(name='b')
[<b>efg.</b>]
#可以看到,在使用name参数时返回在该节点包含的子节点里面的所有目标名字的节点。
>>> soup.find_all(attrs='title')
[<p class="title"><b>efg.</b></p>]
>>> soup.find_all(name='a',attrs='py2')
[<a class="py2" h="" id="hjkl" ref="http://www.tyui.com">zxcv
</a>]
#这里可以看到使用attrs匹配的就是目标标签的属性。
>>> soup.find_all('a',recursive=False)
[]
#注意,这里返回了一个空列表,既然我们让recursive=False了,说明
#不让其对所有儿子节点进行查找,那么只对儿子节点进行搜索,其儿子节点
#只有一个< html >,因此返回了一个空列表。
对于:
string参数,我们需要完整输入标签中字符串区域的字符串,其才能搜索到该字符串:
>>> soup.find_all(string='efg.')
['efg.']
>>> soup.find_all(string='efg')
[]
#如果想要不需要完整输入对应字符串即可获得信息,那么就需要用到正则表达式了,
#那个属于高级用法,实际上在使用爬虫爬取信息的时候经常会使用到正则表达式。
另外说明以下,这些参数的使用往往是配合着使用的,那样才会有更高的效率,
本次举例单独列举只是为了便于理解。
另外,在使用过程中,< tag >()等价于< tag >.find_all(),也就是说在一个标签后直接加括号和使用find_all
效果是一样的。
而在搜索文档树的find_all
方法外,还有一些扩展方法,这些方法都是基于find_all
函数的:
方法 | 作用 |
---|---|
<>.find() | 搜索且只返回一个结果,字符串类型 |
<>.find_parents | 只在先辈节点中搜索,返回列表类型 |
<>.find_parent() | 在先辈节点中返回一个结果,字符串类型 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型 |
<>.find_next_sibling() | 在后续平行节点中返回一个结果,字符串类型 |
<>.find_previous_siblings() | 在前序平行节点中搜索,返回列表类型 |
<>.find_previous_sibling() | 在前序平行节点中返回一个结果,字符串类型。 |
END
最后,关于美味汤
库的介绍就到这里了,文章列举的内容几乎满足正常的使用了,还有些小细节知识点没有列举出来,这里附上Beautiful Soup 4.2.0的官方文档中文版,里面有非常详细的使用方法介绍,有兴趣的可以多加学习:
Beautiful Soup 4.2.0 文档
本篇文章的内容到此就结束了,非常感谢你能看到这里,愿我们的未来都充满阳光,愿我们都能过得自己想要的生活。