Beautiful Soup - 搜尋樹



在本章中,我們將討論 Beautiful Soup 中用於在不同方向導航 HTML 文件樹的不同方法 - 上下、左右和來回。

我們將在本章的所有示例中使用以下 HTML 字串:

html = """
<html><head><title>TutorialsPoint</title></head>
   <body>
      <p class="title"><b>Online Tutorials Library</b></p>

      <p class="story">TutorialsPoint has an excellent collection of tutorials on:
      <a href="https://tutorialspoint.tw/Python" class="lang" id="link1">Python</a>,
      <a href="https://tutorialspoint.tw/Java" class="lang" id="link2">Java</a> and
      <a href="https://tutorialspoint.tw/PHP" class="lang" id="link3">PHP</a>;
      Enhance your Programming skills.</p>

      <p class="tutorial">...</p>
"""

所需標籤的名稱允許您導航解析樹。例如 soup.head 將獲取 <head> 元素:

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')

print (soup.head.prettify())

輸出

<head>
   <title>
      TutorialsPoint
   </title>
</head>

向下導航

標籤可以包含字串或其他包含在其中的標籤。Tag 物件的 .contents 屬性返回屬於它的所有子元素的列表。

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')

tag = soup.head 
print (list(tag.children))

輸出

[<title>TutorialsPoint</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>Online Tutorials Library</b></p>, '\n', 
<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a class="lang" href="https://tutorialspoint.tw/Python" id="link1">Python</a>,
<a class="lang" href="https://tutorialspoint.tw/Java" id="link2">Java</a> and
<a class="lang" href="https://tutorialspoint.tw/PHP" id="link3">PHP</a>;
Enhance your Programming skills.</p>, '\n', <p class="tutorial">...</p>, '\n']

您可以使用 .children 生成器迭代標籤的子元素,而不是將它們作為列表獲取:

示例

tag = soup.body 
for child in tag.children:
   print (child)

輸出

<p class="title"><b>Online Tutorials Library</b></p>
<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a class="lang" href="https://tutorialspoint.tw/Python" id="link1">Python</a>,
<a class="lang" href="https://tutorialspoint.tw/Java" id="link2">Java</a> and
<a class="lang" href="https://tutorialspoint.tw/PHP" id="link3">PHP</a>;
Enhance your Programming skills.</p>


<p class="tutorial">...</p>

.descendents

.contents 和 .children 屬性僅考慮標籤的直接子元素。.descendants 屬性允許您遞迴地迭代標籤的所有子元素:它的直接子元素、其直接子元素的子元素,依此類推。

BeautifulSoup 物件位於所有標籤層次結構的頂部。因此,它的 .descendents 屬性包含 HTML 字串中的所有元素。

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')

print (soup.descendants)

.descendents 屬性返回一個生成器,可以使用 for 迴圈迭代。這裡,我們列出 head 標籤的後代。

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')
tag = soup.head
for element in tag.descendants:
   print (element)

輸出

<title>TutorialsPoint</title>
TutorialsPoint

head 標籤包含一個 title 標籤,該標籤又包含一個 NavigableString 物件 TutorialsPoint。<head> 標籤只有一個子元素,但它有兩個後代:<title> 標籤和 <title> 標籤的子元素。但是 BeautifulSoup 物件只有一個直接子元素(<html> 標籤),但它有許多後代。

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')

tags = list(soup.descendants)
print (len(tags))

輸出

27

向上導航

就像您使用 children 和 descendents 屬性導航文件的下游一樣,BeautifulSoup 提供了 .parent 和 .parent 屬性來導航標籤的上游

.parent

每個標籤和每個字串都有一個包含它的父標籤。您可以使用 parent 屬性訪問元素的父元素。在我們的示例中,<head> 標籤是 <title> 標籤的父元素。

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')

tag = soup.title
print (tag.parent)

輸出

<head><title>TutorialsPoint</title></head>

由於 title 標籤包含一個字串(NavigableString),因此字串的父元素是 title 標籤本身。

示例

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'html.parser')

tag = soup.title
string = tag.string
print (string.parent)

輸出

<title>TutorialsPoint</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> 標籤右側沒有同級,因此在這兩種情況下它都返回 Nobe。

示例

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>TutorialsPoint</title></head>
<body>
<p class="title"><b>Online Tutorials Library</b></p>

<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a href="https://tutorialspoint.tw/Python" class="lang" id="link1">Python</a>,
<a href="https://tutorialspoint.tw/Java" class="lang" id="link2">Java</a> and
<a href="https://tutorialspoint.tw/PHP" class="lang" id="link3">PHP</a>;
Enhance your Programming skills.</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
TutorialsPoint has an excellent collection of tutorials on:

id 為 "link3" 的 <a> 標籤之後的 next_element 是字串 PHP。同樣,previous_element 返回 id 為 "link1" 的 <a> 標籤之前的字串。

.next_elements 和 .previous_elements

Tag 物件的這些屬性分別返回其後和之前的所有標籤和字串的生成器。

Next elements 示例

tag = soup.find("a", id="link1")
for element in tag.next_elements:
   print (element)

輸出

Python
,

<a class="lang" href="https://tutorialspoint.tw/Java" id="link2">Java</a>
Java
 and

<a class="lang" href="https://tutorialspoint.tw/PHP" id="link3">PHP</a>
PHP
;
Enhance your Programming skills.


<p class="tutorial">...</p>
...

Previous elements 示例

tag = soup.find("body")
for element in tag.previous_elements:
   print (element)

輸出

<html><head><title>TutorialsPoint</title></head>
廣告