👻👻相信不少小夥伴們通過我的兩篇萬字博文的輪番轟炸已經實作了從入坑到會完全學會requests庫,并且可以獨立開發出屬于自己的小爬蟲項目!!!——爬蟲之路,永無止境~👻👻
第一篇爬蟲入坑:一篇萬字博文帶你入坑爬蟲這條不歸路(你還在猶豫什麼&抓緊上車) 【❤️熬夜整理&建議收藏❤️】
第二篇爬蟲庫requests庫詳解:兩萬字博文教你python爬蟲requests庫,看完還不會我把我女朋友都給你【❤️熬夜整理&建議收藏❤️】
😬😬那麼,第二步就是從頁面解析到我們想要的資料!相信小夥伴們通過我的後兩篇萬字博文的輪番轟炸已經深刻地學會了網頁(HTML)結構,并能夠通過XPath熟練的進行頁面解析。但是又有小夥伴說了——有些網頁裡的資料藏得深啊!靠XPath搞不出來啊怎麼辦呢?😬😬
網頁結構HTML必備知識總結文:前端HTML兩萬字圖文大總結,快來看看你會多少!【❤️熬夜整理&建議收藏❤️】
第一個解析庫XPath庫詳解:萬字博文教你python爬蟲必備XPath庫,看完還不會我把我女朋友都給你【❤️建議收藏系列❤️】
😜😜解析不出來資料,原因無非有二:一是你功力不夠(要多加練習哦!);二是XPath也不是萬能的,終究有它也不行的時候(雖然它已經夠牛筆了!)。是以,應粉絲們需求——本部落客再來傳授一技絕學:Beautiful Soup!!!😜😜
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iN0YWMkZjYlJjYmJWMkVDN2QWNzU2YmdzMidzM0YTN48CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
重點來啦!重點來啦!! 💗💗💗
對于一個網頁來說,都有一定的特殊結構和層級關系,而且很多節點都有id或class來做區分,是以借助它們的結構和屬性來提取不是很香嗎?說的好!Beautiful Soup這一強大的解析工具,它就是是以而誕生的,它就是借助網頁的結構和屬性等特性來解析網頁的哦!下面我們就來走進Beautiful Soup的世界!
學好解析庫,網頁資料任我取!!! |
❤️Beautiful Soup萬字博文詳解❤️
- 1.BeautifulSoup
-
- (1)簡介:
- (2)安裝:
- (3)解析器:
- (4)執行個體引入:
- (5)各種常用操作/選擇器詳解:
-
- 初級階段——必備操作:
-
- 1.練氣期——基操勿6:
- 2.築基期——Tag對象:
-
- 拓展——擷取屬性騷操作:
-
- 1.每個節點可能有多個屬性,比如id和class等,選擇這個節點元素後,可以調用attrs擷取所有屬性:
- 2.可以看到,attrs的傳回結果是字典形式。如果要擷取name屬性,就相當于從字典中擷取某個鍵值。也可以不寫attrs而直接像上述一樣,直接在節點元素後面加中括号,傳入屬性名:
- 3.注意:有的傳回字元串,有的傳回結果是字元串組成的清單。**比如:name屬性的值是唯一的,傳回的結果就是單個字元串;而對于class,一個節點元素可能有多個class,是以傳回的是清單!**
- 3.金丹期——擷取文本内容:
- 中級階段——關聯選擇:
-
- 戰前準備:
- 1.元嬰期——子代标簽的選擇:
-
- ①contents
- ②children
- 拓展——簡要講一下NavigableString對象:
- 2.化神期——後代标簽的選擇:
- 3.煉虛期——兄弟标簽的選擇:
- 4.合體期——父節點标簽的選擇:
-
- ①parent——隻能擷取選中标簽的父親節點:
- ②parents——可以擷取選中标簽的所有的父輩元素:
- 5.大乘期——資訊的提取:
-
- ①string——提取目前節點中含有單個字元串的情況:
- ②strings——提取目前節點中含有多個字元串的情況:
- 騷操作——使用stripped_strings将全是空白的行去掉:
- 究極階段——方法選擇器(渡劫期):
-
- 1.通過name搜尋,根據節點名查詢:
- 2.通過屬性搜尋,這時候我們可以通過傳遞給attrs一個字典參數來進行查詢。
- 3.通過文本内容搜尋:
- 4.限制查找範圍為子節點:
- 5.拓展——結合使用正規表達式進行查找:
- 升華階段(多重渡劫):
-
- 第一部分——方法選擇器:
- 第二部分——CSS選擇器:
-
- 1.使用方法:
- 2.實戰講解:
-
- ①擷取所有p标簽:
- ②擷取p标簽下面的a标簽,傳回結果在清單裡:
- 2.In The End!
1.BeautifulSoup
(1)簡介:
BeautifulSoup 是一個可以從HTML或XML檔案中提取資料的Python庫,它的使用方式相對于正則來說更加的簡單友善,常常能夠節省我們大量的時間。它借助網頁的結構和屬性等特征來解析網頁! |
🙉官方為其解釋如下🙉:
- Beautiful Soup提供一些簡單的,Python式的函數來處理導航,搜尋,修改分析樹等功能。它是一個工具箱,通過解析文檔為使用者提供需要抓取的資料,因為簡單,是以不需要多少代碼就可以寫出一個完整的應用程式。
- Beautiful Soup自動将輸入文檔轉換為Unicode編碼,輸出文檔轉換為UTF-8編碼。你不需要考慮編碼方式,除非文檔沒有指定一個編碼方式,這時你僅僅需要說明一下原始編碼方式就可以了。
- Beautiful Soup已成為和lxml一樣出色的Python解釋器,為使用者靈活地提供不同的解析政策或強勁的速度。
(小提示:Beautiful Soup我們也簡稱為bs4哦!别聽到這個名就不認識了哈!)
官方中文文檔在此!
(2)安裝:
😻CMD指令安裝😻(一句指令一步到位【媽媽再也不用擔心我不會安庫啦!】):
pip install beautifulsoup4
(3)解析器:
需要注意的是使用BeautifulSoup需要指定解析器(因為Beautiful Soup在解析時實際上依賴解析器,它除了支援Python标準庫中的HTML解析器外,還支援一些第三方解析器【比如lxml】)
BeautifulSoup解析網頁必須要指定一個可用的解析器哦!以下是幾種主要的解析器:
由于這個解析的過程在大規模的爬取中是會影響到整個爬蟲系統的速度的,并且通過以上對比可以看出,lxml解析器有解析HTML和XML的功能,而且速度快,容錯能力強,是以推薦使用它,而本部落客一貫使用的也是它哦!注意——lxml需要單獨安裝(也是CMD一句指令搞定!):
pip install lxml
溫馨小提示:如果一段HTML或XML文檔格式不正确的話,那麼在不同的解析器中傳回的結果可能是不一樣的,是以一定要指定一個确定的解析器! |
(4)執行個體引入:
(我們定義一個html_doc字元串模拟爬取到的待解析的頁面資料)
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" target="_blank" rel="external nofollow" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" target="_blank" rel="external nofollow" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
# 第一個參數:上述HTML字元串;第二個參數:解析器的類型(使用lxml)——完成BeautifulSoup對象的初始化!
soup = BeautifulSoup(html_doc, "lxml") # 将html轉化為可操作的對象
print(type(soup))
輸出如下(會發現已經是一個BeautifulSoup對象,下面我們就可以調用soup的各個方法和屬性對其進行為所欲為的解析了!):
首先來個騷操作——調用prettify()方法。功能:将要解析的字元串以标準的縮進格式輸出。
輸出為:
<html>
<head>
<title>
The Dormouse's story
</title>
</head>
<body>
<p class="title" name="dromouse">
<b>
The Dormouse's story
</b>
</p>
<p class="story">
Once upon a time there were three little sisters; and their names were
<a class="sister" href="http://example.com/elsie" id="link1">
Elsie
</a>
,
<a class="sister" href="http://example.com/lacie" id="link2">
Lacie
</a>
and
<a class="sister" href="http://example.com/tillie" id="link3">
Tillie
</a>
;
and they lived at the bottom of a well.
</p>
<p class="story">
...
</p>
</body>
</html>
我們觀察輸出和原HTML字元串發現——對于不标準的HTML字元串BeautifulSoup可以自動更正其格式(小夥伴們想想看是不是上一個etree子產品也可以!)。但是需要注意的一點是:這一自動更正其格式的操作是在初始化BeautifulSoup時就完成了,而不是調用prettify()方法造就的哦!
(5)各種常用操作/選擇器詳解:
初級階段——必備操作:
1.練氣期——基操勿6:
練氣期(吸納天地靈氣,入體化為元力,壽元可達至百來歲;丹田為氣狀,初步掌握靈氣術法運用,已具備神識,不
能辟谷,體内元氣并不能支撐太久的禦劍飛行)
print(soup.title) # 擷取title标簽
print(soup.title.name) # 擷取title标簽的标簽名 擷取節點名稱,調用name屬性即可!
print(soup.title.string) # 擷取title标簽的文本内容
print(soup.title.parent) # 擷取title标簽的父标簽
print(soup.find(id="link2")) # 找到id=link2的标簽
2.築基期——Tag對象:
築基期(丹田為液态狀,可辟谷,神識倍增,壽元可達兩百餘歲,不能遁光飛行,能長時間禦劍飛行)
|
print("我是Tag對象:", type(soup.a))
# 1.擷取标簽 僅擷取第一個符合條件的标簽,其他後面的節點都會忽略!
print(soup.a) # 輸出為:<a class="sister" href="http://example.com/elsie" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" id="link1">Elsie</a>
# 2.擷取屬性 僅擷取第一個符合條件的标簽的屬性值
print(soup.a["href"]) # 輸出為:http://example.com/elsie
拓展——擷取屬性騷操作:
1.每個節點可能有多個屬性,比如id和class等,選擇這個節點元素後,可以調用attrs擷取所有屬性:
print(soup.p.attrs)
print(soup.p.attrs['name'])
2.可以看到,attrs的傳回結果是字典形式。如果要擷取name屬性,就相當于從字典中擷取某個鍵值。也可以不寫attrs而直接像上述一樣,直接在節點元素後面加中括号,傳入屬性名:
print(soup.p['name'])
print(soup.p['class'])
3.注意:有的傳回字元串,有的傳回結果是字元串組成的清單。比如:name屬性的值是唯一的,傳回的結果就是單個字元串;而對于class,一個節點元素可能有多個class,是以傳回的是清單!
3.金丹期——擷取文本内容:
金丹期(丹田内有規則的圓形固态丹元,已辟谷,壽元可達五百載,可駕遁光飛行)
# 第一種方法:
print(soup.a.text)
print(soup.a.get_text())
# 第二種方法:
print(soup.body.get_text()) # 注意:這個方法會擷取選中标簽下的所有文本内容
中級階段——關聯選擇:
在實際使用中,我們很多時候不能做到一步就宣導想要的節點元素,這時就需要先選中一個節點元素,然後再以它為基準選擇它的子節點,父節點,兄弟節點等,這就是接下來要講解的關聯選擇: |
戰前準備:
先擷取到整個body标簽,後續在body裡進行嵌套選擇:
body = soup.body # 擷取整個body标簽
print(body)
1.元嬰期——子代标簽的選擇:
元嬰期(破丹成嬰,壽元可達千年歲月,遁光飛行,破體元嬰可瞬移)
contents和children: |
|
①contents
②children
tags = body.children # 列印body.children可知這是個疊代器。擷取的同樣也是所有直接子節點。
print(tage)
可以使用for循環輸出疊代器内容,也可轉類型為清單直接輸出其所有内容:
拓展——簡要講一下NavigableString對象:
NavigableString的意思是可以周遊的字元串,一般被标簽包裹在其中的的文本就是NavigableString格式。我們在此類型的基礎上再次選擇得到的依然還是此類型,每次傳回的結果都相同!這樣就可以做到嵌套選擇(前面所講的Tag對象也可這樣耍——實作嵌套選擇)!
print(type(soup.body.get_text())) # 輸出為:<class 'str'>
print(type(soup.p.string)) # 輸出為:<class 'bs4.element.NavigableString'>
2.化神期——後代标簽的選擇:
化神期(體内元嬰倍增,元嬰向元神過渡,壽元可超兩千餘年,掌握元力領域,可破元嬰瞬移)
descendants: |
|
tags_des = body.descendants # 列印body.descendants可知這是個生成器。擷取的是後代(子孫)标簽
print(list(tags_des))
3.煉虛期——兄弟标簽的選擇:
煉虛期(壽元可達近五千歲,體内元嬰化為元神,返虛出本體,化為分身或衆多分身)
兄弟節點——指的是父節點相同的節點。 |
|
①先擷取body标簽裡的第一個p标簽:
p = body.p # 可以一層層擷取指定标簽,但是也隻可以擷取第一個符合條件的标簽
print(p)
②擷取符合條件的第二個标簽,使用.next_sibling方法(注意:上一步選中的body标簽裡的第一個p标簽的往下第一個兄弟節點是\n!):
③擷取符合條件的同級标簽的上一個标簽,使用.previous_sibling方法(注意:body标簽的往上第一個兄弟節點是\n!):
4.合體期——父節點标簽的選擇:
合體期(分身與本體合二為一,達到返樸歸真,初掌神通,可破煉虛萬千化身,壽元可達上萬年載)
父節點parent和parents: |
|
①parent——隻能擷取選中标簽的父親節點:
p = body.p
print(p.parent)
②parents——可以擷取選中标簽的所有的父輩元素:
p_parents = p.parents
print(p_parents) #列印可知這是個生成器
print(list(p_parents))
5.大乘期——資訊的提取:
大乘期(壽元可達兩萬餘年,熟練使用或自創神通,法力肉身已具備飛升上界的條件,谌為修士大能)
string和strings: |
|
①string——提取目前節點中含有單個字元串的情況:
p = body.p
print(p.string)
②strings——提取目前節點中含有多個字元串的情況:
gg = body.strings # 傳回的是一個generator(生成器)
print(type(gg))
print(list(gg))
騷操作——使用stripped_strings将全是空白的行去掉:
print(list(body.stripped_strings)) # 會發現這個傳回的相比上面直接用strings的差別:沒有了空白
行
究極階段——方法選擇器(渡劫期):
渡劫期(凡人向仙人過渡的境界,修士飛升上界以後,初掌天地法則,體内元力逐漸向仙元力或仙靈力轉換,失敗則
為渡劫修士,随歲月而消亡;轉換成功,則融會貫通天地法則,可與天地同壽,是為仙)
以上方法都是通過屬性來選擇,速度快是快!但是如果要選取的節點位置十分複雜的話就會很麻煩很麻煩(很多時候隻能适用于比較簡單的一些場景,)!!!是以BeautifulSoup還提供了搜尋整個文檔樹的方法find_all()。 |
源碼:
def find_all(self, name=None, attrs={}, recursive=True, text=None)
功能:擷取所有符合條件的元素
傳回值:一個可疊代對象(清單)
注意:find_all擷取到的内容在清單裡哦!!!
1.通過name搜尋,根據節點名查詢:
find_all(‘p’)可以直接查找出整個文檔樹中所有的p标簽,并傳回清單:
拓展騷操作——擷取所有的p标簽和a标簽:
2.通過屬性搜尋,這時候我們可以通過傳遞給attrs一個字典參數來進行查詢。
擷取p标簽裡class為story的p标簽:
3.通過文本内容搜尋:
結果傳回所有比對text參數值的節點文本組成的清單:
擷取a标簽裡文本為Elsie的a标簽/soup.find_all(text=“Elsie”)[0].parent也可以:
拓展——擷取屬性值:
擷取滿足條件的a标簽的href:
4.限制查找範圍為子節點:
|
5.拓展——結合使用正規表達式進行查找:
|
查找以b開頭的标簽(b标簽和body标簽):
import re
tags = soup.find_all(re.compile("^b"))
print(tags)
升華階段(多重渡劫):
第一部分——方法選擇器:
Beautiful Soup提供的方法選擇器遠遠不止一個find_all()哦!與find_all()相對的是find()方法。二者唯一差別是:find_all()方法傳回的是所有比對的元素組成的清單;而find()方法傳回的是第一個比對的元素!
第二部分——CSS選擇器:
此外,如果你對WEB開發有所研究的話,這邊Beautiful Soup也為你量身打造了一種選擇器——CSS選擇器。
1.使用方法:
隻需要調用select()方法,傳入相應的CSS選擇器即可! |
2.實戰講解:
①擷取所有p标簽:
print(soup.select("p"))
print(type(soup.select("p")[0]))
注意:我們觀察到通過CSS選擇器選中的結果類型仍舊是Tag類型!這也就說明我們依舊可以對使用CSS選擇器選中的節點為所欲為哦!(比如嵌套選擇,擷取屬性,擷取文本啥的…)
②擷取p标簽下面的a标簽,傳回結果在清單裡:
2.In The End!
從現在做起,堅持下去,一天進步一小點,不久的将來,你會感謝曾經努力的你! |
本部落客會持續更新爬蟲基礎分欄及爬蟲實戰分欄,認真仔細看完本文的小夥伴們,可以點贊收藏并評論出你們的讀後感。并可關注本部落客,在今後的日子裡閱讀更多爬蟲文!
如有錯誤或者言語不恰當的地方可在評論區指出,謝謝!
如轉載此文請聯系我征得本人同意,并标注出處及本部落客名,謝謝!> !