在本章中,我们将讨论 Beautiful Soup 中在不同方向上导航 HTML 文档树的不同方法 - 上下、侧向和来回。
在本章的所有例子中,我们将使用以下HTML字符串:
html = """
<html><head><title>Yoagoa</title></head>
<body>
<p class="title"><b>在线教程库</b></p>
<p class="story">Yoagoa 有一个优秀的教程集合:
<a href="https://yoagoa.com/Python" class="lang" id="link1">Python</a>,
<a href="https://yoagoa.com/Java" class="lang" id="link2">Java</a> 和
<a href="https://yoagoa.com/PHP" class="lang" id="link3">PHP</a>;
提升你的编程技能。</p>
<p class="tutorial">...</p>
"""
所需标签的名称使您可以导航解析树。例如,soup.head
可以获取 <head>
元素:
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
print (soup.head.prettify())
输出
<head>
<title>
Yoagoa
</title>
</head>
向下导航
一个标签可能包含在其内部的字符串或其他标签。Tag
对象的 .contents
属性返回属于它的所有子元素的列表。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.head
print (list(tag.children))
输出
[<title>Yoagoa</title>]
返回的对象是一个列表,尽管在这种情况下,只有单个子标签被包含在 <head>
元素中。
.children
.children
属性也返回一个标签中包含的所有元素的列表。下面,<body>
标签中的所有元素都作为一个列表给出。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.body
print (list(tag.children))
输出
['\n', <p class="title"><b>在线教程库</b></p>, '\n',
<p class="story">Yoagoa 有一个优秀的教程集合:
<a class="lang" href="https://yoagoa.com/Python" id="link1">Python</a>,
<a class="lang" href="https://yoagoa.com/Java" id="link2">Java</a> 和
<a class="lang" href="https://yoagoa.com/PHP" id="link3">PHP</a>;
提升你的编程技能。</p>, '\n', <p class="tutorial">...</p>, '\n']
而不是将它们作为一个列表获取,您可以使用 .children
生成器来迭代一个标签的子元素:
示例
tag = soup.body
for child in tag.children:
print (child)
输出
<p class="title"><b>在线教程库</b></p>
<p class="story">Yoagoa 有一个优秀的教程集合:
<a class="lang" href="https://yoagoa.com/Python" id="link1">Python</a>,
<a class="lang" href="https://yoagoa.com/Java" id="link2">Java</a> 和
<a class="lang" href="https://yoagoa.com/PHP" id="link3">PHP</a>;
提升你的编程技能。</p>
<p class="tutorial">...</p>
.descendents
.contents
和 .children
属性仅考虑一个标签的直接子元素。.descendants
属性允许您递归地遍历一个标签的所有子元素:它的直接子元素,直接子元素的子元素,等等。
BeautifulSoup
对象位于所有标签层次结构的顶部。因此其 .descendants
属性包括 HTML 字符串中的所有元素。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
print (soup.descendants)
.descendants
属性返回一个生成器,可以使用 for
循环进行迭代。在这里,我们列出了 <head>
标签的后代。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.head
for element in tag.descendants:
print (element)
输出
<title>Yoagoa</title>
Yoagoa
<head>
标签包含一个 <title>
标签,后者又包含一个 NavigableString
对象 Yoagoa
。 标签只有一个子元素,但它有两个后代:<title>
标签和 <title>
标签的子元素。但 BeautifulSoup
对象只有一个直接子元素(<html>
标签),但它有很多后代。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tags = list(soup.descendants)
print (len(tags))
输出
27
向上导航
正如您可以通过 .children
和 .descendants
属性导航文档的下游部分,BeautifulSoup 提供了 .parent
和 .parents
属性来导航标签的上游部分。
.parent
每个标签和每个字符串都有一个包含它的父标签。您可以通过 parent
属性访问一个元素的父级。在我们的例子中,<head>
标签是 <title>
标签的父级。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.title
print (tag.parent)
输出
<head><title>Yoagoa</title></head>
由于 <title>
标签包含一个字符串(NavigableString
),该字符串的父级就是 <title>
标签本身。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.title
string = tag.string
print (string.parent)
输出
<title>Yoagoa</title>
.parents
您可以使用 .parents
遍历一个元素的所有父级。这个例子使用 .parents
从嵌套在文档深处的一个 <a>
标签,导航到文档的最顶层。在下面的代码中,我们跟踪示例 HTML 字符串中的第一个 <a>
标签的父级。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.a
print (tag.string)
for parent in tag.parents:
print (parent.name)
输出
Python
p
body
html
[document]
横向导航
出现在同一缩进级别的 HTML 标签被称为兄弟标签。考虑以下 HTML 片段:
<p>
<b>
Hello
</b>
<i>
Python
</i>
</p>
在外层 <p>
标签中,我们在同一缩进级别上有 <b>
和 <i>
标签,因此它们被称为兄弟标签。BeautifulSoup 使您能够在同一级别的标签之间进行导航。
.next_sibling
和 .previous_sibling
这些属性分别返回同一级别上的下一个标签和同一级别上的前一个标签。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag1 = soup.b
print ("next:",tag1.next_sibling)
tag2 = soup.i
print ("previous:",tag2.previous_sibling)
输出
next: <i>Python</i>
previous: <b>Hello</b>
由于 <b>
标签左侧没有兄弟标签,而 <i>
标签右侧也没有兄弟标签,所以在两种情况下都会返回 None
。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag1 = soup.b
print ("next:",tag1.previous_sibling)
tag2 = soup.i
print ("previous:",tag2.next_sibling)
输出
next: None
previous: None
.next_siblings
和 .previous_siblings
如果一个标签的右侧或左侧有两个或更多的兄弟标签,可以使用 .next_siblings
和 .previous_siblings
属性进行导航。这两个属性返回生成器对象,因此可以使用 for
循环进行迭代。
让我们使用以下 HTML 片段来达到这个目的:
<p>
<b>
Excellent
</b>
<i>
Python
</i>
<u>
Tutorial
</u>
</p>
使用以下代码来遍历下一个和前一个兄弟标签。
示例
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Excellent</b><i>Python</i><u>Tutorial</u></p>", 'html.parser')
tag1 = soup.b
print ("next siblings:")
for tag in tag1.next_siblings:
print (tag)
print ("previous siblings:")
tag2 = soup.u
for tag in tag2.previous_siblings:
print (tag)
输出
next siblings:
<i>Python</i>
<u>Tutorial</u>
previous siblings:
<i>Python</i>
<b>Excellent</b>
来回导航
在 Beautiful Soup 中,next_element
属性返回解析树中的下一个字符串或标签。另一方面,previous_element
属性返回解析树中的前一个字符串或标签。有时,next_element
和 previous_element
属性的返回值类似于 next_sibling
和 previous_sibling
属性。
.next_element
和 .previous_element
示例
html = """
<html><head><title>Yoagoa</title></head>
<body>
<p class="title"><b>在线教程库</b></p>
<p class="story">Yoagoa 有一个优秀的教程集合:
<a href="https://yoagoa.com/Python" class="lang" id="link1">Python</a>,
<a href="https://yoagoa.com/Java" class="lang" id="link2">Java</a> 和
<a href="https://yoagoa.com/PHP" class="lang" id="link3">PHP</a>;
提升你的编程技能。</p>
<p class="tutorial">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find("a", id="link3")
print (tag.next_element)
tag = soup.find("a", id="link1")
print (tag.previous_element)
输出
PHP
Yoagoa 有一个优秀的教程集合:
<a>
标签后 id 为 "link3"
的 next_element
是字符串 PHP
。同样地,previous_element
返回 <a>
标签前 id 为 "link1"
的字符串。
.next_elements
和 .previous_elements
这些 Tag
对象的属性分别返回之后和之前的所有标签和字符串的生成器。
下一个元素示例
tag = soup.find("a", id="link1")
for element in tag.next_elements:
print (element)
输出
Python
,
<a class="lang" href="https://yoagoa.com/Java" id="link2">Java</a>
Java
and
<a class="lang" href="https://yoagoa.com/PHP" id="link3">PHP</a>
PHP
;
提升你的编程技能。
前一个元素示例
tag = soup.find("body")
for element in tag.previous_elements:
print (element)
输出
<html><head><title>Yoagoa</title></head>