文章目錄
- 寫在前面
- python 爬蟲
- BeautifulSoup庫是什么
- BeautifulSoup的安裝
- 解析器對比
- BeautifulSoup的使用
- BeautifulSoup 庫中的4種類
- 獲取標簽
- 獲取指定標簽
- 獲取標簽的的子標簽
- 獲取標簽的的父標簽(上行遍歷)
- 獲取標簽的兄弟標簽(平行遍歷)
- 獲取注釋
- 根據條件查找標簽
- 根據CSS選擇器查找標簽
寫在前面
本文主要介紹了python爬蟲
中的BeautifulSoup庫的安裝和使用,如果是爬蟲小白,請先看文章爬蟲入門與requests庫的使用,再來看本文章,這樣你會有更深刻地理解,當然,大佬隨意。
python 爬蟲
BeautifulSoup庫是什么
BeautifulSoup是一個用于解析 HTML
和 XML
文檔的 Python 庫
,它幫助你從網頁中提取數據。這個庫非常靈活,并且可以與多種不同的解析器一起工作,比如 Python 內置的 html.parser
、lxml
或者 html5lib
。
BeautifulSoup的安裝
想要安裝BeautifulSoup庫,則需要執行以下安裝命令:
pip install bs4
pip install beautifulsoup4
pip install soupsieve
pip install lxml
解析器對比
如上圖,其中markup為一個html
文件或者html
代碼(字符串形式)。
BeautifulSoup的使用
BeautifulSoup 庫中的4種類
BeautifulSoup
將復雜的 HTML 文檔轉換成由 Python 對象構成的樹形結構,主要包括以下四種類型的對象:Tag
, NavigableString
, BeautifulSoup
, 和 Comment
。
Tag
:表示標簽。NavigableString
:表示標簽之間的文本內容。BeautifulSoup
:表示整個解析后的文檔。Comment
:一種特殊的NavigableString
,表示 HTML 中標簽之間的注釋。
獲取標簽
獲取指定標簽
Tag(獲取標簽):
from bs4 import BeautifulSoupwith open(file="test.html", mode='r', encoding='utf-8') as fp:soup = BeautifulSoup(markup=fp, features='html.parser')# 解析html文件并將解析結果返回# 查找并獲取HTML文檔中的第一個 <h2> 標簽。h2_tag = soup.h2# 打印找到的 <h2> 標簽(如果有的話)。如果沒有找到 <h2> 標簽,則打印None。print(h2_tag)# 打印 <h2> 標簽的數據類型。如果是有效的標簽,它將是bs4.element.Tag 類型;#如果沒有找到標簽,則是NoneType。print(type(h2_tag))# 打印標簽名 print(h2_tag.name) # 修改標簽名后打印,并不會修改原HTML文檔中的標簽名 h2_tag.name = 'h3' print(h2_tag.name)# 獲取標簽之間的文本內容(純文本內容),如果標簽中還有標簽,則返回None print(h1_tag.string) # 獲取標簽之間的文本內容,如果標簽中還有標簽,#則獲取所有二級標簽的內容(以換行分隔)# 最終將所有的文本內容拼接成一個字符串返回print(h1_tag.get_text())img_tag = soup.img #獲取到第一個<img>標簽# 以字典方式獲取標簽的所有屬性的鍵和值print(img_tag.attrs)# 獲取img標簽中屬性alt的值,如果屬性不存在報KeyError錯誤print(img_tag['alt'])# 獲取img標簽中屬性alt的值,如果屬性不存在返回Noneprint(img_tag.get('alt'))print(img_tag.attrs.get('alt'))# 以上兩種方式是同樣的效果img_tag['alt'] = '修改后的alt'# 打印修改后的alt的值print(img_tag['alt'])# 刪除屬性del img_tag['alt']# 打印標簽內容print(img_tag)
下面詳細地講解一下需要注意的方法:
標簽名.get_text():
# 獲取標簽之間的文本內容,如果標簽中還有標簽,
# 則獲取所有二級標簽的文本內容(以換行分隔)
# 最終將所有的文本內容拼接成一個字符串返回print(h1_tag.get_text())
<div><p>Hello</p><span>World</span>
</div>
div_tag.get_text() # 輸出: '\nHello\nWorld\n'
div_tag.get_text(strip=True) # 輸出: 'HelloWorld'
div_tag.get_text(separator=" | ") # 輸出: '\n | Hello | \n | World | \n'
獲取標簽的的子標簽
- 獲取指定標簽的所有子節點標簽及文本內容(列表形式返回)
標簽名.contents:
標簽名.contents#獲取當前標簽的直接子節點列表(不含子孫)
<div><p>Hello</p><span>World</span>
</div>
div_tag.contents
# 輸出: ['\n', <p>Hello</p>, '\n', <span>World</span>, '\n']
注意:與上面的
標簽名.get_text()
作區別
- 獲取指定標簽的所有子節點標簽及文本內容(迭代器形式返回)
soup.標簽名.children
#獲得標簽對應的子標簽和子字符串(回車)的迭代類型,可以直接用于迭代
- 獲取指定標簽的所有子孫后代節點標簽及文本內容(迭代器形式返回)
soup.標簽名.descendants
# 獲得標簽對應的所有的子孫標簽和子孫字符串的迭代類型,可以直接用于迭代
獲取標簽的的父標簽(上行遍歷)
- 獲取指定標簽的父標簽(迭代器形式返回)
soup.標簽名.parent
#獲得標簽對應的父標簽
- 獲取指定標簽的所有先輩標簽(迭代器形式返回),
從直接父級開始,逐級向上到文檔根節點
soup.標簽名.parents#獲得標簽對應的先輩標簽的迭代類型,可以直接用于迭代
獲取標簽的兄弟標簽(平行遍歷)
- 獲取指定標簽相鄰的下一個平行標簽(按html代碼順序)
soup.標簽名.next_sibling
#返回按html代碼順序的下一個平行節點標簽
- 獲取指定標簽相鄰的上一個平行標簽(按html代碼順序)
soup.標簽名.previous_sibling
# 返回html代碼順序的上一個平行節點標簽
- 獲取指定標簽后續的所有平行標簽(即按html代碼順序排在指定標簽后的所有兄弟標簽)
soup.標簽名.previous_siblings
# 返回html代碼順序的后續所有平行節點標簽
- 獲取指定標簽前序的所有平行標簽(即按html代碼順序排在指定標簽前的所有兄弟標簽)
soup.標簽名.previous_siblings
#返回html代碼順序的前序所有平行節點標簽
獲取注釋
想要獲取和操作html文件或代碼
中的注釋,需要通過 BeautifulSoup 的 Comment
類。
Comment類的作用;
- 提取注釋內容:從 HTML/XML 中提取被
<!-- ... -->
包裹的注釋文本。- 判斷節點類型:識別某個字符串節點是否為注釋。
定位注釋:
注釋在 BeautifulSoup 中被解析為 Comment
類型的特殊字符串對象,可通過以下方式獲取:
from bs4 import BeautifulSoup, Commenthtml = '''
<div><p>正文內容</p><!-- 這是一個隱藏的注釋 -->
</div>
'''soup = BeautifulSoup(html, 'html.parser')# 方法1:遍歷所有字符串節點,篩選出注釋
comments = soup.find_all(string=lambda text: isinstance(text, Comment))
for comment in comments:print("注釋內容:", comment) # 輸出: 這是一個隱藏的注釋# 方法2:直接通過標簽訪問(若注釋在標簽內)
div_tag = soup.div
comment_in_div = div_tag.find(string=lambda text: isinstance(text, Comment))
print(comment_in_div) # 輸出: 這是一個隱藏的注釋
操作注釋:
- 提取注釋文本:直接獲取
Comment
對象的字符串。 - 替換或刪除注釋:
# 找到對應的注釋
# 替換注釋為普通文本
comment = div_tag.find(string=lambda text: isinstance(text, Comment))
comment.replace_with("替換后的文本")# 刪除注釋
comment.extract()
例子( 提取注釋中的日期):
from bs4 import BeautifulSoup, Commenthtml = '''
<div class="article"><!-- 文章發布時間:2023-10-01 --><h1>標題</h1><p>正文內容...</p>
</div>
'''soup = BeautifulSoup(html, 'html.parser')
div_tag = soup.find('div', class_='article')
#定位到了指定的標簽# 查找注釋并提取日期
comment = div_tag.find(string=lambda text: isinstance(text, Comment))
if comment:date = comment.strip().split(":")[-1]print("發布日期:", date) # 輸出: 2023-10-01
根據條件查找標簽
soup.find_all(name,attrs,string)#name 目的標簽名,同時查找多個標簽時格式為
#name=['標簽名1','標簽名2'],name=True時,查找出所有標簽#attrs 目的標簽中的屬性值,查找標簽名與name相同,同時標簽屬性的所有值中有attrs的標簽
#也可以直接對屬性進行查找 soup.find_all(class="title")
# 查找class屬性的值為"title"的標簽link = soup.find_all('a', {'class': 'sister', 'id': 'link2'})
#同時對多個屬性查找#string 對標簽文本內容的查找(支持使用正則表達)#limit 限制返回結果的數量,類似于 SQL 中的 `LIMIT` 關鍵字。
#當搜索到的結果數量達到限制時,停止搜索并返回結果#recursive 控制是否檢索所有子孫節點。
#如果設置為 `False`,則只搜索直接子節點#函數作用:以列表的形式返回查找結果
#soup(……) ----------soup.find_all(……)
如上,為常用的查找方法,其中soup.find()
的作用是查找第一個匹配的標簽,找到后立馬返回,不再繼續查找,其參數與soup.find_all(……)
相同。
根據CSS選擇器查找標簽
#可以直接使用標簽名查找元素
title_tags = soup.select('title')
print(title_tags)#使用(.類名)選擇類查找元素
sister_links = soup.select('.sister')
print(sister_links)#使用井號(`#id名`)選擇ID查找元素
link1 = soup.select('#link1')
print(link1)#使用空格選擇后代元素
bold_text = soup.select('p b')
print(bold_text)#使用大于號(`>子標簽名`)選擇直接子元素
direct_children = soup.select('body > p')
print(direct_children)
# 輸出: [<p class="title"><b>The Dormouse's story</b></p>,
#<p class="story">...</p>]# 輸出body下所有子標簽中的p標簽#可以根據屬性來選擇元素
specific_link = soup.select('a[href="http://example.com/lacie"]')
print(specific_link)#可以使用偽類選擇器,例如選擇第一個元素
first_sister = soup.select('.sister:first-child')
print(first_sister)
#選擇class="sister"的標簽下的第一個子標簽