首頁技術文章正文

python beautifulsoup庫的作用和用法詳細介紹

更新時間:2021-06-21 來源:黑馬程序員 瀏覽量:

使用lxml庫時需要編寫和測試XPath語句,顯然降低了開發(fā)效率。除了lxml庫之外,還可以使用Beautiful Soup來提取HTML/XML數據。雖然這兩個庫的功能相似,但是Beautiful Soup使用起來更加簡潔方便,受到開發(fā)人員的推崇。

Beautiful Soup概述

截止到目前,BeautifulSoup(3.2.1版本)已經停止開發(fā),官網推薦現在的項目使用beautifulsoup4( Beautiful Soup4版本,簡稱bs4)開發(fā)。

bs4是一個HTML/XML的解析器,其主要功能是解析和提取HTML/XML數據。它不僅支持CSS選擇器,而且支持Python標準庫中的HTML解析器,以及l(fā)xml的XML解析器。通過使用這些轉化器,實現了慣用的文檔導航和查找方式,節(jié)省了大量的工作時間,提高了開發(fā)項目的效率。

bs4庫會將復雜的HTML文檔換成樹結構(HITML DoM),這個結構中的每個節(jié)點都是一個Pyhon對象。這些對象可以歸納為如下4種:

(1) bs4.element.Tag類:表示HTML中的標簽,是最基本的信息組織單元,它有兩個非常重要的屬性,分別是表示標簽名字的name屬性和表示標簽屬性的attrs屬性。

(2) bs4.element.NavigableString類:表示HTML中標簽的文本(非屬性字符串)。

(3) bs4.BeautifulSoup類:表示HTML DOM中的全部內容,支持遍歷文檔樹和搜索文檔樹的大部分方法。

(4) bs4.element.Comment類:表示標簽內字符串的注釋部分,是一種特殊的Navigable String對象。


使用bs4的一般流程如下:

(1)創(chuàng)建一個BeautifulSoup類型的對象。

根據HTML或者文件創(chuàng)建BeautifulSoup 對象。

(2)通過BeautifulSoup對象的操作方法進行解讀搜索。

根據DOM樹進行各種節(jié)點的搜索( 例如,find_all()方法可以搜索出所有滿足要求的節(jié)點,find()方法只會搜索出第一個滿足要求的節(jié)點),只要獲得了一個節(jié)點,就可以訪問節(jié)點的名稱、屬性和文本。

(3)利用DOM樹結構標簽的特性,進行更為詳細的節(jié)點信息提取。

在搜索節(jié)點時,也可以按照節(jié)點的名稱、節(jié)點的屬性或者節(jié)點的文字進行搜索。上述流程如下圖所示。

1624258199895_bs4庫的使用流程.png


構建BeautifulSoup對象

通過一個字符串或者類文件對象(存儲在本地的文件句柄或Web網頁句柄)可以創(chuàng)建BauifulSoup類的對象。 BeautifulSoup類中構造方法的語法如下:

def_init_(self, markup="", features=None, builder=None, parse_only=None, 
from_encoding=None, exclude_encodings=None, **kwargs)

上述方法的一些參數含義如下:
(1) markup:表示要解析的文檔字符串或文件對象。
(2) features:表示解析器的名稱。
(3) builder:表示指定的解析器。
(4) from_encoding:表示指定的編碼格式。
(5) exclude _encodings:表示排除的編碼格式。 例如,根據字符串html_doc創(chuàng)建一個BeautifulSoup對象:

from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc, 'lxml')

上述示例中,在創(chuàng)建BeautifulSoup實例時共傳入了兩個參數。其中,第一個參數表示包含被解析HTML文檔的字符串;第二個參數表示使用lxml解析器進行解析。

目前,bs4 支持的解析器包括Python標準庫、lxml和html5lib。為了讓用戶更好地選擇合適的解析器,下面列舉它們的使用方法和優(yōu)缺點,如表所示。

解析器使用方法優(yōu)勢劣勢
lxml HTML解析器BeautifulSoup(markup,"lxml")(1)速度快;
(2)文檔容錯能力強
需要安裝C語言庫
Python標準庫BeautifulSoup(markup, "html.parser")(1) Python的內置標準庫;
(2)執(zhí)行速度適中;
(3)文檔容錯能力強
Python 2.7.3或3.2.2之前的版本中文檔容錯能力差
lxml XML解析器BeautifulSoup(markup, [<<lxml-xml>>])
BeautifulSoup(markup, "xml")
(1)速度快;
(2)唯一支持XML的解析器
需要安裝C語言庫
html5libBeautifulSoup(markup, "html5lib")(1)最好的容錯性;
(2)以瀏覽器的方式解析文檔
(3)生成HTML5格式的文檔
(1)速度慢;
(2)不依賴外部擴展

在創(chuàng)建BeautifulSoup對象時,如果沒有明確地指定解析器,那么BeautifulSoup對象會根據當前系統(tǒng)安裝的庫自動選擇解析器。解析器的選擇順序為:lxml、html5lib、Python標準庫。在下面兩種情況下,選擇解析器的優(yōu)先順序會發(fā)生變化:

(1)要解析的文檔是什么類型,目前支持html、xml和html5。

(2)指定使用哪種解析器。

如果明確指定的解析器沒有安裝,那么BeautifulSoup對象會自動選擇其他方案。但是,目前只有l(wèi)xml解析器支持解析XML文檔,一且沒有安裝lxml庫,就無法得到解析后的對象。

使用print()函數輸出剛創(chuàng)建的BeantifulSoup對象soup,代碼如下:

print(soup.prettify())

上述示例中調用了petif()方法進行打印,既可以為HTML標簽和內容增加換行符,又可以對標簽做相關的處理,以便于更加友好地顯示HTML內容。為了直觀地比較這兩種情況,下面分別列出直接打印和調用prettify()方法后打印的結果。直接使用print()函數進行輸出,示例結果如下:

<html><head><title>The Dormouse's story</title></head>
<body>
</body></html>

調用prettify()方法后進行輸出,示例結果如下:

<html>
	<head>
		<title>
			The Dormouse's story
		</title>
	</head>
	<body>
	</body>
</html>

通過操作方法進行解讀搜索

實際上,網頁中有用的信息都存在于網頁中的文本或者各種不同標簽的屬性值,為了能獲得這些有用的網頁信息,可以通過一些查找方法獲取文本或者標簽屬性。因此,bs4庫內置了一些查找方法,其中常用的兩個方法功能如下:

(1) find()方法:用于查找符合查詢條件的第一 個標簽節(jié)點。

(2) find_all()方法:查找所有符合查詢條件的標簽節(jié)點,并返回一個列表。

這兩個方法用到的參數是一樣的,這里以find_all()方法為例,介紹在這個方法中這些參數的應用。find_all()方法的定義如下:

find_all(self, name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs)

上述方法中一些重要參數所表示的含義如下:

1.name參數

在找所有名字為name的標簽,但字符串會被自動忽略。下面是 name參數的幾種情況:
(1) 傳人字符串:在搜索的方法中傳入一個字符串,BeautifuSoup對象會查找與字符事無全匹配的內容。例如:

soup.find_all('b')

 上述示例用于查找文檔中所有的<b>標簽。

 (2)傳人正則表達式:如果傳入一個正則表達式,那么BautifulSoup對象會通過re模塊的match()函數進行匹配。下面的示例中,使用正則表達式"^b"匹配所有以字母b開頭的標簽。

import re
for tag in soup.find_all(re.compile("^b")) :
	print(tag.name)
#輸出結果如下
body

(3)傳人列表:如果傳入一個列表,那么BeautifulSoup對象會將與列表中任一元索匹配的內容返回。在下面的示例中,找到了文檔中所有的<a>標簽和<b>標簽。

soup.find_all(["a", "b"])
# 部分輸出結果如下:
[<b>The Dormouse's story</b>,
<a classm"sister" href="http://example.com/elsie" 1d="link1">E1sle</a>,

2.attrs參數
如果某個指定名字的參數不是搜索方法中內置的參數名,那么在進行搜索時,會把該參數當作指定名稱的標簽中的屬性來搜索。在下面的示例中,在find_all()方法中傳人名稱為id的參數,這時BeautiflSoup對象會搜索每個標簽的id屬性。

soup.find_all(id='link2')
# 輸出的結果可能是:
[<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

若傳入多個指定名字的參數,則可以同時過濾出標簽中的多個屬性。在下面的示例中,既可以搜索每個標簽的id屬性,同時又可以搜索href屬性。

import re
soup.find_all(href=re.compile("elsie"), id='link1')
# 輸出的結果可能是:
[<a class="sister" href="http://example.com/elsie" id="linkl">Elsie</a>]


如果要搜索的標簽名稱為class,由于class屬于Python的關鍵字,所以可在class的后面加上一個下畫線。例如:

soup.find_all("a", class_="sister")
# 部分輸出結果如下:
# [<a href="http: //example.com/elsie" id="link1">Elsie</a>,

但是,有些標簽的屬性名稱是不能使用的,例如HTML5中的“data-”屬性,在程序中使用時,會出現SyntaxError異常信息。這時,可以通過find_all()方法的attrs參數傳入一個字典來搜索包含特殊屬性的標簽。例如:

data_soup=BeautifulSoup('<div data-foo="value">foo!</div>', 'lxml')
data_soup.find_all(data-foo="value")
# 程序輸出如下報錯信息:
# SyntaxError: keyword can't be an expression
data_soup.find_all(attrs={"data-foo": "value"})
# 程序可匹配的結果
# [<div data-foo="value">foo!</div>]

3.text參數
通過在find_all()方法中傳人text參數,可以搜索文檔中的字符串內容。與name參數的可選值一樣,text參數也可以接受字符串、正則表達式和列表等。例如:

soup.find_all(text="Elsie")
# [u'Elsie']
soup.find_all(text=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']

limit參數 在使用find_all()方法返回匹配的結果時,倘若DOM樹非常大,那么搜索的速度會相當慢。這時,如果不需要獲得全部的結果,就可以使用limit參數限制返回結果的數量,其效果與SQL語句中的limit關鍵字所產生的效果類似。一旦搜索到結果的數量達到了limit的限制,就會停止搜索。例如:

soup.find_all("a", limit=2)

上述示例會搜索到最多兩個符合搜索條件的標簽。

recursive參數 在調用find_all()方法時,Beutifuloup對象會檢索當前節(jié)點的所有子節(jié)點。這時,如果只想搜索當前節(jié)點的直接子節(jié)點,就可以使用參數recursive=False。例如:

soup.html.find_all("title")
# [<title>The Dormouse's story</title>]
soup.html.find_all("titile", recursive=False)
# []

除了上述兩個常用的方法以外,bs4庫中還提供了一些通過 節(jié)點間的關系進行查我的方法。由于這些方法的參數和用法跟fnd, alll 方法類似,這里就不再另行介紹。

通過CSS選擇器進行搜索


除了bs4庫提供的操作方法以外,還可以使用CSS選擇器進行查找。什么是CSS呢? CSS (Cascading Style Sheets,層疊樣式表)是一種用來表現HTML或XML等文件樣式的計算機語言,它不僅可以靜態(tài)地修飾網頁,而且可以配合各種腳本語言動態(tài)地對網頁各元索進行格式化。

要想使用Css對HTML頁面中的元素實現一對一、一對多或多對一的控制,需要用到CSS選擇器。 每一條CSS樣式定義均由兩部分組成,形式如下:

[code]選擇器{樣式}[/code]

其中,在{} 之前的部分就是“選擇器”。選擇器指明了}中樣式的作用對象,也就是“樣式”作用于網頁中的哪些元素。

為了使用CSS選擇器達到篩選節(jié)點的目的,在bs4庫的BeautifulSoup類中提供了一個select()方法,該方法會將搜索到的結果放到列表中。 CSS選擇器的查找方式可分為如下幾種:

1.通過標簽查找

在編寫CSS時,標簽的名稱不用加任何修飾。調用select0方法時,可以傳人包含某個標簽的字符串。使用CSS選擇器查找標簽的示例如下:

soup.select("title")
# 查找的結果可能為
# [<title>The Dormouse's story</title>]


2.通過類名查找


在編寫CSS時,需要在類名的前面加上“.” 。例如,查找類名為sister的標簽,示例如下:

soup.select('.sister')
# 并查找的結果可能為
# [<a href="http://example.com/elsie" id="linkl"><!-- Elsie --></a>, <a href="http://example.com/lacie" id="link2">Lacie</a>, <a href="http://example.com/tillie" id="link3">Tillie</a> ]


3.通過id名查找

在編寫CSS時,需要在id名稱的前面加上“#”。例如,查找id名為link1的標簽,具體示例如下;

soup.select("#link1")
# 查找的結果可能為
# [<a href-"http://example.com/elsie" id="link1">Elsie</a>]


4.通過組合的形式查找

組合查找與編寫CLASS文件時標簽名、類名、id 名的組合原理一樣,二者需要用空格分開。例如,在標簽p中,查找id值等于link1的內容。

soup.select('p #link1')
# 手查找的結果可能為
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

可以使用“>”將標簽與子標簽分隔,從而找到某個標簽下的直接子標簽。例如:

soup.select("head > title")
# 查找的結果可能為
# [<title>The Dormouse's story</title>]


5.通過屬性查找

可以通過屬性元素進行查找,屬性需要用中括號括起來。但是,屬性和標簽屬于同一個結點,它們中間不能加空格,否則將無法匹配到。例如:

soup.select('a[href="http://example.com/elsie"]')
# 查找的結果可能為
# [<a href="http: //example. com/elsie" id="link1">Elsie</a>]

同樣,屬性仍然可以與上述查找方式組合,即不在同一節(jié)點的屬性使用空格隔開,同一節(jié)點的屬性之間不加空格。例如:

soup.select('P a[href="http://example.com/elsie"]')
# 查找的結果可能為
# [<a href="http://example.com/elsie" id="link1">Elsie</a>]

上述這些查找方式都會返回一個列表。遍歷這個列表,可以調用get _text() 方法來獲取節(jié)點 的內容。例如:

<br class="Apple-interchange-newline"><div></div>
soup=BeautifulSoup(html_doc, 'lxml')
for element in soup.select('a'):
    print(element.get_text())    # 獲取節(jié)點的內容
# 獲取到節(jié)點的內容可能為
Elsie
Lacie                                                        
Tillie


分享到:
在線咨詢 我要報名
和我們在線交談!