首頁技術(shù)文章正文

python beautifulsoup庫的作用和用法詳細(xì)介紹

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

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

Beautiful Soup概述

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

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

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

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

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

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

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


使用bs4的一般流程如下:

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

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

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

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

(3)利用DOM樹結(jié)構(gòu)標(biāo)簽的特性,進(jìn)行更為詳細(xì)的節(jié)點信息提取。

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

1624258199895_bs4庫的使用流程.png


構(gòu)建BeautifulSoup對象

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

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

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

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

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

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

解析器使用方法優(yōu)勢劣勢
lxml HTML解析器BeautifulSoup(markup,"lxml")(1)速度快;
(2)文檔容錯能力強(qiáng)
需要安裝C語言庫
Python標(biāo)準(zhǔn)庫BeautifulSoup(markup, "html.parser")(1) Python的內(nèi)置標(biāo)準(zhǔn)庫;
(2)執(zhí)行速度適中;
(3)文檔容錯能力強(qiáng)
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)不依賴外部擴(kuò)展

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

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

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

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

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

print(soup.prettify())

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

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

調(diào)用prettify()方法后進(jìn)行輸出,示例結(jié)果如下:

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

通過操作方法進(jìn)行解讀搜索

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

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

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

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

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

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

1.name參數(shù)

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

soup.find_all('b')

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

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

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

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

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

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

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

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

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


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

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

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

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"})
# 程序可匹配的結(jié)果
# [<div data-foo="value">foo!</div>]

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

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

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

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

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

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

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

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

通過CSS選擇器進(jìn)行搜索


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

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

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

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

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

1.通過標(biāo)簽查找

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

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


2.通過類名查找


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

soup.select('.sister')
# 并查找的結(jié)果可能為
# [<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的標(biāo)簽,具體示例如下;

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


4.通過組合的形式查找

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

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

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

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


5.通過屬性查找

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

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

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

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

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

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


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