1. 為什麼要使用 find
和 find_all
?
今天我們要聊聊兩個主要的方法,讓我們更高效且有針對性地從 HTML 文件中提取元素:find
和 find_all
。
在進入程式碼之前,我們先來聊聊為什麼需要這些方法。想像一個網頁就像一座巨大的圖書館,每一個詞彙和句子都是 HTML 元素。要找到我們需要的資訊,有時候就像試圖根據冰淇淋的顏色來猜它的味道一樣困難。而 find
和 find_all
方法就是你的「味道探測器」,幫助你精確找到所需的資料。
find
: 這個方法有點像程式員早晨找第一杯咖啡的習慣——它快速找到並返回符合條件的第一個元素。find_all
: 比較耐心且徹底的方法,會返回包含所有符合條件元素的列表。適合需要更多資訊的情況(例如一天中的多杯咖啡)。
2. 使用 find
那麼,當你需要快速提取第一個符合條件的元素時,可以使用 find
方法。它接受的參數包括標籤名稱、屬性甚至是函數。
find
方法的簽名
find(name=None, attrs={}, recursive=True, string=None, **kwargs)
find
方法的參數
- name: 想要搜尋的標籤名稱。可以是任何 HTML 標籤,例如
div
、p
、h1
或a
等。 - attrs: 標籤屬性的字典。例如,
{'class': 'example'}
或{'id': 'main'}
。這個參數可以讓你縮小搜尋範圍。 - recursive: 布林值參數,決定方法是否搜尋所有嵌套層次的標籤。預設值是
True
,表示會在所有層次中搜尋。 - string: 搜尋包含特定文字的元素。這對於依據文字內容過濾元素很有用。
- kwargs: 用於基於屬性搜尋的額外參數。例如,傳遞
class_
就會被解釋為attrs={'class': 'value'}
。
範例
from bs4 import BeautifulSoup
html_doc = """
<html>
<head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
</body>
</html>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
first_link = soup.find('a') # 找到第一個 <a> 標籤
print(first_link) # 輸出:<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>
如你所見,find
方法找到了文件中的第一個 <a>
標籤,我們可以安心繼續我們的搜尋,知道需要的資訊已經找到了。
3. 使用 find_all
find_all
方法會返回所有符合條件的元素列表。這在需要獲取特定類型的所有標籤或具有特定類的所有元素時特別有用。
find_all
方法的簽名
find_all(name=None, attrs={}, recursive=True, string=None, limit=None, **kwargs)
find_all
方法的參數
- name: 想要搜尋的標籤名稱。可以是標籤名稱字串(例如
div
、a
、p
等)或標籤名稱列表(例如["div", "p"]
)。 - attrs: 用於過濾標籤的屬性字典,例如
{'class': 'example'}
。 - recursive: 決定是否要遞迴搜尋嵌套的標籤,預設值為
True
。 - string: 搜尋包含指定文字的標籤。
- limit: 設定返回結果的最大數量。如果指定,方法將返回不超過
limit
的元素數量。 - kwargs: 用於過濾標籤屬性的額外參數。
find_all
的使用範例
如果 find
是快速搜尋書架上的特定書本,那麼 find_all
就是更詳細的方式,就像是閱讀每個章節標題一樣。
all_links = soup.find_all('a') # 找到所有 <a> 標籤
for link in all_links:
print(link.get('href')) # 輸出:http://example.com/elsie, http://example.com/lacie, http://example.com/tillie
在這個範例中,我們找到了所有的 <a>
標籤,然後從中提取了它們的連結。當你需要收集頁面上的所有連結時,這非常實用。
重要! find()
和 find_all()
方法不僅可以在 soup
物件上調用,也可以在任何從這些方法或 select()
等方法返回的子元素上調用。
4. 使用屬性篩選元素
現在,當我們控制住對資料的渴望時,是時候更加具體了。方法 find
和 find_all
允許根據屬性篩選元素。這就像為咖啡機設置篩選器,以獲得你偏好的飲料。
link_with_id = soup.find('a', id='link2') # 找到具有 id='link2' 的 <a>
print(link_with_id.text) # 輸出:Lacie
使用 id
參數,我們很快找到了需要的元素。同樣,也可以使用其他屬性,例如 class
。
links_with_class = soup.find_all('a', class_='sister') # 找到所有具有 class='sister' 的 <a>
for link in links_with_class:
print(link.get('id')) # 輸出:link1, link2, link3
5. 比較 find
和 find_all
:何時使用?
瞭解了這兩個方法後,你可能會問:什麼時候用 find
,什麼時候用 find_all
?很簡單。如果你確定頁面上只有一個符合條件的元素,或者只對第一個感興趣,那就用 find
。如果需要收集所有符合條件的元素,那就用 find_all
。
參數 | find |
find_all |
---|---|---|
返回值 | 第一個符合條件的元素(如果找不到,返回 None ) |
符合條件的元素列表(如果找不到,返回空列表) |
用途 | 需要只有一個元素 | 需要收集所有符合條件的元素 |
limit 參數 |
不適用 | 支持:設置最大返回數量 |
範例比較:如果需要獲取頁面中所有 h2
標籤,用 find_all
。但如果只需要第一個 h2
,用 find
就夠了。
# 獲取頁面中所有 h2 標籤
all_h2_tags = soup.find_all("h2")
# 只獲取第一個 h2 標籤
first_h2_tag = soup.find("h2")
6. 實踐任務
現在你瞭解了理論,我們來實踐一下吧!撰寫一個小腳本,從一個部落格中提取文章標題與連結。為此,我們將使用 find_all
來尋找所有標題和連結,假設它們位於帶有 class="post-title"
的 <h2>
標籤中。
blog_html = """
<html>
<body>
<h2 class="post-title"><a href="http://example.com/post1">First Post</a></h2>
<h2 class="post-title"><a href="http://example.com/post2">Second Post</a></h2>
<h2 class="post-title"><a href="http://example.com/post3">Third Post</a></h2>
</body>
</html>
"""
blog_soup = BeautifulSoup(blog_html, 'html.parser')
post_titles = blog_soup.find_all('h2', class_='post-title')
for post in post_titles:
title = post.text
link = post.find('a')['href']
print(f"Title: {title}, Link: {link}")
如果一切順利,你會看到:
Title: First Post, Link: http://example.com/post1
Title: Second Post, Link: http://example.com/post2
Title: Third Post, Link: http://example.com/post3
請注意,上例中的 find()
方法是在 post
對象上調用的。這表明可以在已找到的元素上搜索它的子元素。
7. 常見錯誤
使用 find
和 find_all
時,常會遇到一些錯誤。例如,如果 find
方法找不到元素,會返回 None
,這可能導致 AttributeError
。因此,在使用前總是檢查返回值。
此外,屬性錯誤也很常見。例如,如果屬性拼寫錯誤,方法可能會找不到任何東西。因此我建議總是檢查 HTML 代碼中的屬性是否正確。
GO TO FULL VERSION