创建 BeautifulSoup 对象
从字符串创建:
soup = bs4.BeautifulSoup(字符串,解析器)
从 文件 创建:
soup = bs4.BeautifulSoup(open('index.html', 'r'), 'html.parser')
或
with open('index.html', 'r') as file:
soup = bs4.BeautifulSoup(file)
常用解析器及其优缺点
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
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"]) BeautifulSoup(markup, "xml") |
速度快;唯一支持XML的解析器 | 需要安装 C 语言库 |
html5lib | BeautifulSoup(markup, "html5lib") |
最好的容错性;不依赖外部扩展;生成 HTML5 格式的文档 | 速度慢 |
bs4 中的四种对象
bs4 中有四种对象:Tag
,NavigableString
,BeautifulSoup
,Comment
Tag
:通俗来讲就是 HTML 中的标签NavigableString
:标签中间的字符内容,其子标签为None
。该对象也可以当做特殊的Tag
对象BeautifulSoup
:用BeautifulSoup
函数处理HTML
/XML
代码后生成的对象,使用时可以当做特殊的Tag
对象,其.name
属性为[document]
,.attrs
属性为None
Comment
:Tag.string
会将注释内容也显示出来,且去掉了注释符号,所以区分 标签内容 和 注释内容 只能通过判断它们的类型,注释内容的类型为Comment
Tag 的方法和属性
基本属性:
Tag.tag
:该Tag
的子标签Tag.name
:标签名Tag.attrs
:以字典形式存储的标签属性(多值属性会用列表处理)
可以用三种方法获取某个标签属性:Tag['class']
Tag.get('class')
Tag.attrs['class']
前两种是 Tag
对象自带用法,最后一种是字典的用法。
标签的属性可以被添加、删除或修改,操作方法与字典是一样的。如:
Tag['class'] = 'red'
Tag.get('class') = 'red'
Tag.attrs['class'] = 'red'
Tag.string
:标签中间的文本内容,该文本内容是NavigableString
对象- 如果一个标签里面没有标签了,那么
.string
就会返回标签里面的内容。 - 如果标签里面只有唯一的一个标签,那么
.string
也会返回最里面的内容。 - 如果
Tag
中包含多个子节点,无法确定.string
方法应该调用哪个子节点的内容, 输出结果则为None
- 如果一个标签里面没有标签了,那么
遍历文档树
节点内容
Tag.strings
:如果一个标签中包含多个子节点,可以使用 .strings
生成器获取所有内容
for string in Tag.strings:
print(repr(string))
Tag.stripped_strings
:.strings
产生的内容可能包含很多 空格和空行,使用该方法可以去除多余空白
for string in Tag.stripped_strings:
print(repr(string))
子节点
Tag.contents
:以 列表形式 返回当前 Tag 的 直接子节点Tag.children
:以 list 生成器对象的形式返回当前 Tag 的 直接子节点Tag.descendants
:返回一个包含当前 Tag 所有子孙节点的对象(遍历方式为深度优先)
父节点
Tag.parent
:输出 直接父节点Tag.parents
:输出 包含所有父节点的可迭代对象,迭代时会 从里到外 输出所有父节点
兄弟节点(同级节点)
Tag.next_sibling
:输出下一个兄弟节点Tag.previous_sibling
:输出上一个兄弟节点Tag.next_siblings
:返回 包含所有后面的兄弟节点 的可迭代对象,迭代时要先用repr
转化Tag.previous_siblings
:返回 包含所有前面的兄弟节点 的可迭代对象,迭代时要先用repr
转化
前后节点(不分级别)
Tag.next_element
:输出下一个节点Tag.previous_element
:输出上一个节点Tag.next_elements
:返回 包含所有后面的节点 的可迭代对象,迭代时要先用repr
转化Tag.previous_elements
:返回 包含所有前面的节点 的可迭代对象,迭代时要先用repr
转化
搜索文档树
主要使用 find()
、 find_all()
、 select()
这三个方法。
select()
方法以 css 选择器为参数,返回匹配到的所有元素。
find_all()
返回一个可迭代对象,对象中的每个元素都是一个 Tag
对象。find()
的用法与 find_all()
相同,只不过 find()
只返回搜索到的第一个元素。
下面以 find_all()
为例,介绍 find_all()
和 find()
的参数。
name
参数(查找标签)
传字符串(查找指定标签):
soup.find_all('a')
传正则表达式(查找符合条件的标签):
for tag in soup.find_all(re.compile("^b")):
print(tag.name) # output: body b
:::info
Beautiful Soup 会通过正则表达式的 match()
来匹配内容
:::
传列表(查找多个指定的标签名):
soup.find_all(["a", "p"]) # 查找所有 a 和 p 标签
传 True
(True
可以匹配任何值):
soup.find_all(True)
传函数名(自定义查找标准):
def has_class_but_no_id(tag): # 参数是要遍历的每个节点
return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id) # 函数名后不加括号
:::warning 注:函数只接受一个元素作为参数。 :::
keyword
参数(查找标签属性)
可以将属性名当做关键字参数来搜索,如:
soup.find_all(href="http://www.baidu.com/")
会返回文档中 href
属性的值是 "http://www.baidu.com/"
的标签,构成列表。
可以将属性值设为 True
,会返回拥有该属性的所有标签,例如:
soup.find_all(href=True)
会返回文档中拥有 href
属性的所有标签,因为 True
匹配任何值。
使用多个 keyword
参数可以同时过滤 Tag 的多个属性:
soup.find_all(href=re.compile("elsie"), id='link1')
# 匹配结果:[<a class="sister" href="http://example.com/elsie" id="link1">three</a>]
:::warning
注:因为 class
是 Python 中的关键字,所以以 class
作为 keyword
参数时,要写成 class_
:::
text
参数(查找标签内容)
通过 text
参数可以搜索文档中的字符串内容。
与 name
参数的可选值一样, text
参数接受 字符串、正则表达式、列表、**True**
其他参数
limit
参数:限制查找结果个数。如:
soup.find_all("a", limit=2)
recursive
参数:默认为 True
,此时查找当前 Tag 的所有子节点。若设为 False
,则只查找直接子节点。
例如:
soup.html.find_all("title", recursive=False)
其他方法
Tag.prettify()
:格式化输出内容。Tag.get_attribute_list('class')
:以 列表 形式获取指定属性的值。如果它是多值属性,那么列表中存在多个字符串,否则列表中就只有一个字符串。