BeautifulSoup是灵活又方便的网页解析库,处理高效,支持多种解析器。虽然正则表达式比较强大,但是能用“美味的汤”能更加方便实现网页信息的提取就优先使用吧。
官方文档:http://beautifulsoup.readthedocs.io/zh_CN/latest/
安装:
pip3 install beautifulsoup4
解析器选择
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, "html.parser") | Python的内置标准库,执行速度适中,文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快 文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, ["lxml", "xml"]) | 速度快 唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性 以浏览器的方式解析文档 生成HTML5格式的文档 | 速度慢 不依赖外部扩展 |
建议
- 推荐使用lxml解析库,必要时使用html.parser
- 标签使用筛选功能弱但是速度快
- 建议使用find(),find_all()查询匹配单个结果或者多个结果
- 如果对CSS选择器熟悉建议使用select()
- 记住常用的获取属性和文本值的方法
重点部分
bs4对象种类
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag
, NavigableString
, BeautifulSoup
, Comment
.
其中Tag
有两个主要属性:name和attributes
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# name
tag.name
# attributes
tag.attrs
tag.attrs['class']
tags['class']
搜索文档树
在学习find_all()
之前需要了解过滤器。
过滤器
过滤器贯穿整个搜索的API.过滤器可以被用在tag的name中,节点的属性中,字符串中或他们的混合中,如下:
字符串:传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容
# 寻找所有<b>标签
soup.find_all('b')
正则表达式:Beautiful Soup会通过正则表达式的 match() 来匹配内容
#找出所有以h开头的标签
import re
for tag in soup.find_all(re.compile("^h")):
print(tag.name)
html, head
列表:将与列表中任一元素匹配的内容返回
# <a>或<b>
soup.find_all(["a", "b"])
True: 所有标签
自定义方法:太高级,目前搞不定
# 过滤出前后都有文字的标签
def surrounded_by_strings(tag):
return (isinstance(tag.next_element, NavigableString)
and isinstance(tag.previous_element, NavigableString))
# 包含 class 属性却不包含 id 属性
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
find_all():
find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.(BeautifulSoup是最顶的tag)
find_all( name , attrs , recursive , string , **kwargs )
name参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉
soup.find_all('body')
注: 搜索 name 参数的值可以使任一类型的过滤器 ,字符串,正则表达式,列表,方法或是 True .
keyword参数: 如果一个指定名字的参数不是搜索<u>内置的参数名</u>,搜索时会把该参数当作指定名字tag的属性来搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
for tag in soup.find_all(id=re.compile("^note-\d+")):
print(tag.name)
注:搜索指定名字的属性时可以使用的参数值包括字符串,正则表达式,列表, True.对于CSS样式,class因为和内部冲突,所以需要改为class_
string参数:通过 string 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, string 参数接受 字符串 , 正则表达式 , 列表, True .
print(soup.find_all(string="诗"))
recursive参数,默认搜索当前节点的所有子孙节点,如果只需要搜索直接节点,则recursive=False
PS: 由于find_all太常用,所以BeautifulSoup
对象和 tag
对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all()
方法
soup.title.find_all(string=True)
soup.title(string=True)
find_all还有其他类似方法,详见官方文档,不多说。CSS选择器不太熟悉,所以不去涉及select()
方法。
获取文本的方法很简单,get_text()