Beautiful Soup 遍历文档树
1. 子节点
一个 Tag
可能包含多个 NaviableString
或者其他的 Tag
,这些都是这个 Tag
的子节点。 BeautifulSoup
提供了许多方法来遍历子节点。
NaviableString
没有子节点,因此无法遍历它
a. 通过 Tag
的名字遍历
操作文档树最简单的方法就是通过标签名字获取 Tag
。如果想获取 <head>
标签,只需要使用 soup.head
。
- 通过
soup.a
获得的只是标签<a></a>
的第一个标签。要像获取所有的<a></a>
标签,必须用find_all()
等方法 - 可以如果想获取标签中的子标签,则可以反复使用
.
表达式,如:soup.head.body.a
。
b. 通过 Tag.contents
和 Tag.children
遍历
Tag
的 .contents
属性可以将 Tag
的子节点按照列表的方式输出。而通过 Tag
的 .children
生成器,可以对 Tag
的子节点进行循环。
BeautifulSoup
对象也可以按照这种方式进行遍历。因为BeautifulSoup
对象一定会包含子节点,如<html>
标签。NavigableString
对象不能按照这种方式遍历。因为它没有子节点。哪怕提供给
BeautifulSoup
构造函数的字符串并没有<html></html>
标签,BeautifulSoup
也会自动构造出<html></html>
标签。
c. 通过 Tag.descendants
遍历
通过 Tag.contents
和 Tag.children
遍历时,只能访问 Tag
的直接子节点,而无法访问到孙节点以及孙节点以下节点。 而通过 Tag.descendants
可以获取 Tag
的所有子孙节点(无论是否直系子节点),注意 Tag.descendants
是一个生成器。
BeautifulSoup
对象也可以按照这种方式进行遍历。因为BeautifulSoup
对象一定会包含子节点,如<html>
标签。NavigableString
对象不能按照这种方式遍历。因为它没有子节点。
d. 通过 Tag.string
遍历
- 如果
Tag
只有一个NavigableString
类型的子节点,那么可以通过Tag.string
获得该子节点。 - 如果
Tag
只有一个Tag
类型的子节点,那么通过Tag.string
获取的是该子节点的.string
的结果。 - 如果
Tag
包含了多个子节点,那么Tag.string
输出为None
- 如果
Tag
不包含任何子节点,则Tag.string
输出为None
BeautifulSoup
对象也可以按照这种方式进行遍历。因为BeautifulSoup
对象一定会包含子节点, 如<html>
标签。NavigableString
对象不能按照这种方式遍历。因为它没有子节点。
e. 通过 Tag.strings
和 Tag.stripped_strings
遍历
如果想访问 Tag
以及所有子节点(无论是否直系子节点)中的文本内容,可以使用 Tag.strings
进行循环获取。但是这种方式获取的结果可能含有大量空格或者空白行。在这种情况下可以用 Tag.stripped_strings
可以去除多余空白内容。这两个属性都返回的是生成器对象。
Tag.strings
生成器遍历时,它会读取Tag
以及它所有子节点的文本内容,即使某个子节点没有文本 (如<div></div>
标签),此时该子节点的文本输出为空字符串。
BeautifulSoup
对象也可以按照这种方式进行遍历。因为BeautifulSoup
对象一定会包含子节点,如<html>
标签。NavigableString
对象不能按照这种方式遍历。因为它没有子节点。
2.父节点
每个 Tag
或者 NavigableString
都有父节点(某个 Tag
对象)
a. 通过 .parent
访问父节点
可以通过 Tag.parent
获取 Tag
的父节点,通过 NavigableString.parent
获取 NavigableString
的父节点。
- 文档的顶层节点,如
<html>
的父节点是BeautifulSoup
对象 BeautifulSoup
对象的父节点是None
b. 通过 .parents
访问节点
通过 Tag.parents
和 NavigableString.parents
可以递归得到元素的所有父辈节点。该属性返回的是一个生成器对象。
3. 兄弟节点
a. 通过 .next_sibling
和 .previous_sibling
遍历
在文档树中可以通过 Tag.next_sibling
或者 NavigableString.next_sibling
来查询后一个兄弟节点;通过 Tag.previous_sibling
者 NavigableString.previous_sibling
来查询前一个兄弟节点。
- 第一个节点的
.previous_sibling
返回None
- 最后一个节点的
.next_sibling
返回None
注意:对于 NavigableString
的兄弟节点一定是 Tag
节点或者为空,也可能是另一个 NavigableString
节点。而对于 Tag
节点的兄弟节点却不一定是 Tag
节点或者为空,因为也可能是 NavigableString
字符串节点(尤其是 HTML 显示时看起来是空白其实有换行符或者空白符的时候)。
b. 通过 .next_siblings
和 .previous_siblings
遍历
在文档树中可以通过 Tag.previous_siblings
或者 NavigableString.previous_siblings
来迭代本节点前面的兄弟节点;通过 Tag.next_siblings
者 NavigableString.next_siblings
来迭代本节点后面的兄弟节点。它们都是生成器对象。
4. 回退和前进
对于文档
<html>
<head><title>The Dormouse's story</title></head>
<p class="title"><b>The Dormouse's story</b></p>
</html>
HTML 解析器将这段字符串转换成一连串的事件:
- 打开
<html>
标签 - 打开
<head>
标签 - 打开
<title>
标签 - 添加一段字符串
- 关闭
<title>
标签 - 关闭
<head>
标签 - 打开
<p>
标签 - ....
Beautiful Soup
提供了重现这一过程的方法。
a. 通过 .next_element
和 .previous_element
遍历
在文档树中可以通过 Tag.next_element
或者 NavigableString.next_element
来获取本节点之后下一个被解析的对象(可能是 Tag
或者 NavigableString
);也可以通过 Tag.previous_element
或者 NavigableString.previous_element
来获取本节点之前上一个被解析的对象(可能是 Tag
或者 NavigableString
)。
.next_element
可能与.next_sibling
相同,也可能不同。对于<a> txt</a><b></b>
这种 HTML 节点,标签<a>
的下一个解析节点是<a>
内部的字符串;标签<a>
的下一个兄弟节点是<b>
标签。
a. 通过 .next_elements
和 .previous_elements
遍历
在文档树中可以通过 Tag.previous_elements
或者 NavigableString.previous_elements
来迭代本节点前面解析的节点;通过 Tag.next_elements
者 NavigableString.next_elements
来迭代本节点后面解析的节点。它们都是生成器对象。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论