创建 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属性为NoneComment: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'):以 列表 形式获取指定属性的值。如果它是多值属性,那么列表中存在多个字符串,否则列表中就只有一个字符串。
