安装
安装BeautifulSoup
可通过系统的包管理工具安装:
1 | apt-get install Python-bs4 |
或者通过python的包管理工具pip
进行安装:
1 | pip install beautifulsoup4 -i http://mirrors.aliyun.com/pypi/simple/ |
安装解析器
python内置了HTML解析器,若要使用第三方的解析器,如lxml
,则需根据操作系统和python的版本选择对应的包进行安装,若要离线安装,windows下可点击该链接下载。
1 | apt-get install Python-lxml |
或纯python实现的html5lib
,其解析方式与浏览器相同。
1 | apt-get install Python-html5lib |
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
python标准库 | BeautifulSoup(html, ‘html.parser’) | python的内置标准库 执行速度适中 文档容错能力强 |
Python2.7.3或3.2.2前的版本中文容错能力差 |
lxml HTML解析器 | BeautifulSoup(html, ‘lxml’) | 速度快 文档容错能力强 |
需要安装c语言库 |
lxml XML解析器 | BeautifulSoup(html, [‘lxml’, ‘xml’]) | 速度快 唯一支持XML的解析器 |
需要安装c语言库 |
html5lib | BeautifulSoup(html, ‘html5lib’) | 最好的容错性 以浏览器的方式解析文档 生成HTML5格式的文档 |
速度慢 不依赖外部扩展 |
使用技巧
假设有一个网页html
,创建一个BeautifulSoup
对象,并指定解析器。
1 | from bs4 import BeautifulSoup |
注:灵活利用IDE的打断点进行debug可以快速调试,拿到自己需要的元素
对象种类
~将复杂HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以归为以下四类:
Tag
Tag通俗点讲就是HTML中的一个个标签,它的类型是bs4.element.Tag
,对于Tag有两个重要的属性,是name和attrs。
1 | # 每个tag都有自己的名字,通过.name来获取 |
注:如果标签中某个属性有多值,则解析后返回的类型是list,但是转换的文档是xml时除外。
NavigableString
用于获取标签内部的文字,如下:
1 | soup.title.string |
BeautifulSoup
表示的是一个文档的全部内容,大部分时候可以将其看作为一个特殊的Tag,可通过以下方式获取其名称和属性:
1 | soup.name |
Comment
是一个特殊类型的NavigableString对象,其输出的内容不包括注释符号
1 | soup.a # <a class="mnav"><!--新闻--></a> |
遍历文档树
子节点
.contents和.children
contents:获取Tag的所有子节点,返回一个list
1
2
3soup.contents
soup.contents[0].namechildren:获取Tag的所有子节点,返回一个生成器
1
2for child in soup.body.children:
print(child).descendants
.contents
和.children
属性仅包含tag的直接子节点,.descendants
可以对所有tag的子孙节点进行递归循环。.string
如果tag只有一个子节点,这个tag可以使用
.string
方法获取,如果有多个子节点,则返回为None.strings和.stripped_strings
若果tag中包含多个字符串,可以使用
.strings
循环获取如果字符串包含很多空格或空行,可以使用
.stripped_strings
去除父节点
.parent
通过
.parent
获取某个元素的父节点顶层节点的父节点是BeautifulSoup对象
BeautifulSoup对象的
.parent
是None.parents
通过
.parents
可以递归获取元素的所有父节点兄弟节点
.next_sibling和.previous_sibling
使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点
.next_siblings和.previous_siblings
通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出
搜索文档树
这里主要列举
find_all
和find
方法以及CSS选择器,其他方法可参考官方文档。find_all
find_all(name, attrs, recursive, text, **kwargs)
name参数
字符串过滤:会查找与字符串完全匹配的内容
1
2a_list = soup.find_all("a")
print(a_list)正则表达式过滤:如果传入的是正则表达式,那么BeautifulSoup4会通过search()来匹配内容
1
2
3a_list = soup.find_all(re.compile("a"))
for item in a_list:
print(item)列表:如果传入一个列表,BeautifulSoup4将会与列表中的任一元素匹配到的节点返回
1
2
3a_list = soup.find_all(["meta", "link"])
for item in a_list:
print(item)方法:传入一个方法,根据方法来匹配
1
2
3
4
5
6def name_is_exists(tag):
return tag.has_attr("name")
a_list = soup.find_all(name_is_exists)
for item in a_list:
print(item)kwargs
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
1
2
3
4
5
6
7
8
9
10
11
12# 查询id=head的Tag
t_list = soup.find_all(id="head")
print(t_list)
# 查询href属性包含ss1.bdstatic.com的Tag
t_list = soup.find_all(href=re.compile("http://news.baidu.com"))
print(t_list)
# 查询所有包含class的Tag(注:class要加上_进行区分)
t_list = soup.find_all(class_=True)
for item in t_list:
print(item)attrs
不是所有的属性都可以使用上面的方式进行搜索,比如HTML的data-*属性,这时可以使用attrs参数,定义一个字典来搜索包含特殊属性的tag。
1
2
3t_list = soup.find_all(attrs={"data-foo":"value"})
for item in t_list:
print(item)string
通过string参数可以搜索文档中的字符串内容,与name参数的可选值一样,string参数接收字符串,正则表达式,列表,True。
1
2
3
4
5t_list = soup.find_all(string="Elsie")
t_list = soup.find_all(string=["Tillie", "Elsie", "Lacie"])
t_list = soup.find_all(string=re.compile("Dormouse"))limit
传入一个limit参数来限制返回的数量。
1
2
3t_list = soup.find_all("a", limit=2)
for item in t_list:
print(item)recursive
默认会检索当前tag的所有子孙节点,如果只想搜索直接子节点,可以使用该参数。
1
soup.html.find_all(recursive=False)
find
find( name , attrs , recursive , string , **kwargs )
返回符合条件的第一个Tag,即当我们要取一个值的时候就可以用该方法1
soup.find("head").find("title")
CSS选择器
通过tag标签名查找
1
2
3soup.select("title")
soup.select("a")通过tag标签逐层查找:
1
2
3soup.select("body a")
soup.select("html head title")找到某个tag标签下的直接子标签:
1
2
3soup.select("head > title")
soup.select("p > #link1")找到兄弟节点标签:
1
2
3soup.select("#link1 ~ .sister")
soup.select("#link1 + .sister")通过class属性查找:
1
2
3soup.select(".sister")
soup.select("[class~=sister]")通过tag的id查找:
1
2
3soup.select('#link1')
soup.select("a#link2")同时用多种css选择器查询:
1
soup.select("#link1,#link2")
通过是否存在某个属性来查找:
1
soup.select("a[href]")
通过属性的值来查找:
1
2
3
4
5
6
7soup.select('a[href="http://example.com/elsie"]')
soup.select'a[href^="http://example.com"]')
soup.select('a[href$="tillie"]')
soup.select('a[href*=".com/el"]')通过语言设置来查找:
1
2
3
4
5
6
7
8
9
10
11multilingual_markup = """
<p lang="en">Hello</p>
<p lang="en-us">Howdy, y'all</p>
<p lang="en-gb">Pip-pip, old fruit</p>
<p lang="fr">Bonjour mes amis</p>
"""
multilingual_soup = BeautifulSoup(multilingual_markup)
multilingual_soup.select('p[lang|=en]')
# [<p lang="en">Hello</p>,
# <p lang="en-us">Howdy, y'all</p>,
# <p lang="en-gb">Pip-pip, old fruit</p>]返回查找到的元素的第一个
1
soup.select_one(".sister")
修改文档树
BeautifulSoup的强项是文档树的搜索,但同时也可以方便的修改文档树,这部分可详细参考官方文档。