BeautifulSoup模塊

Beautiful Soup是一個(gè)Python的HTML解析框架,我們可以利用它方便的處理HTML和XML文檔。Beautiful Soup有3和4兩個(gè)版本,目前3已經(jīng)停止開發(fā)。所以我們當(dāng)然還是學(xué)習(xí)最新的Beautiful Soup 4.如果需要詳細(xì)文檔的話可以參考Beautiful Soup中文文檔,這是難得的不是機(jī)翻的文檔。

解析文檔

獲取文檔

Beautiful Soup只是一個(gè)HTML解析庫(kù),所以我們?nèi)绻虢馕鼍W(wǎng)上的內(nèi)容,第一件事情就是把它下載下來(lái)。對(duì)于不同的網(wǎng)站,可能會(huì)對(duì)請(qǐng)求進(jìn)行過(guò)濾。糗事百科的網(wǎng)站就對(duì)沒(méi)有UA的請(qǐng)求直接拒絕掉。所以如果我們要爬這樣的網(wǎng)站,首先需要把請(qǐng)求偽裝成瀏覽器的樣子。具體網(wǎng)站具體分析,經(jīng)過(guò)我測(cè)試,糗事百科只要設(shè)置了UA就可以爬到內(nèi)容,對(duì)于其他網(wǎng)站,你需要測(cè)試一下才能確定什么設(shè)置能管用。

有了Request對(duì)象還不行,還需要實(shí)際發(fā)起請(qǐng)求才行。下面代碼的最后一句就使用了Python3的urllib庫(kù)發(fā)起了一個(gè)請(qǐng)求。urlopen(req)方法返回的是Reponse對(duì)象,我們調(diào)用它的read()函數(shù)獲取整個(gè)結(jié)果字符串。最后調(diào)用decode('utf-8')方法將它解碼為最終結(jié)果,如果不調(diào)用這一步,漢字等非ASCII字符就會(huì)變成\xXXX這樣的轉(zhuǎn)義字符。

import urllib.request as request

user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
headers = {'User-Agent': user_agent}
req = request.Request('http://www.qiushibaike.com/', headers=headers)

page = request.urlopen(req).read().decode('utf-8')

查詢和遍歷方法

有了文檔字符串,我們就可以開始解析文檔了。第一步是建立BeautifulSoup對(duì)象,這個(gè)對(duì)象在bs4模塊中。注意在建立對(duì)象的時(shí)候可以額外指定一個(gè)參數(shù),作為實(shí)際的HTML解析器。解析器的值可以指定html.parser,這是內(nèi)置的HTML解析器。更好的選擇是使用下面的lxml解析器,不過(guò)它需要額外安裝一下,我們使用pip install lxml就可以安裝。

import bs4

soup = bs4.BeautifulSoup(page, "lxml")

有了BeautifulSoup對(duì)象,我們就可以開始解析了。首先先來(lái)介紹一下BeautifulSoup的對(duì)象種類,常用的有標(biāo)簽(bs4.element.Tag)以及文本(bs4.element.NavigableString)。還有注釋等對(duì)象,不過(guò)不太常用,所以就不介紹了。在標(biāo)簽對(duì)象上,我們可以調(diào)用一些查找方法例如find_all等等,還有一些屬性返回標(biāo)簽的父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)、直接子節(jié)點(diǎn)、所有子節(jié)點(diǎn)等。在文本對(duì)象上,我們可以調(diào)用.string屬性獲取具體文本。

然后來(lái)說(shuō)說(shuō)BeautifulSoup的遍歷方法?;舅胁僮鞫夹枰ㄟ^(guò)BeautifulSoup對(duì)象來(lái)使用。使用方式主要有兩種:

  • 一是直接引用屬性,就是soup.title這樣的,會(huì)返回第一個(gè)符合條件的節(jié)點(diǎn);
  • 二是通過(guò)查找方法例如find_all這樣的,傳入查詢條件來(lái)查找結(jié)果。

再來(lái)說(shuō)說(shuō)查詢條件。查詢條件可以是:

  • 字符串,會(huì)返回對(duì)應(yīng)名稱的節(jié)點(diǎn);
  • 正則表達(dá)式,按照正則表達(dá)式匹配;
  • 列表,會(huì)返回所有匹配列表元素的節(jié)點(diǎn);
  • 真值True,會(huì)返回所有標(biāo)簽節(jié)點(diǎn),不會(huì)返回字符節(jié)點(diǎn);
  • 方法,我們可以編寫一個(gè)方法,按照自己的規(guī)則過(guò)濾,然后將該方法作為查詢條件。

實(shí)際例子

爬取糗事百科段子

首先打開糗事百科網(wǎng)站,按F12打開開發(fā)人員工具,然后在旁邊點(diǎn)擊分離按鈕把它變成獨(dú)立窗口,然后切到元素標(biāo)簽并最大化窗口。然后點(diǎn)擊那個(gè)鼠標(biāo)按鈕,再返回糗事百科頁(yè)面,并點(diǎn)擊一個(gè)段子,這樣就可以查看段子在HTML文檔的什么位置了。

HTML結(jié)構(gòu)

首先分析一下HTML代碼,然后我們就可以查找所需的內(nèi)容了。這里需要說(shuō)明一下,查詢方法返回的是結(jié)果集,對(duì)結(jié)果集遍歷可以得到標(biāo)簽或者文本對(duì)象。如果調(diào)用標(biāo)簽對(duì)象的.contents,會(huì)返回一個(gè)列表,列表內(nèi)是標(biāo)簽、文本或注釋對(duì)象。動(dòng)態(tài)語(yǔ)言的優(yōu)勢(shì)就是使用靈活,缺點(diǎn)就是沒(méi)有代碼提示。雖然總共代碼沒(méi)幾行,但是還是花了我一番功夫。

divs = soup.find_all('div', class_='article block untagged mb15')
for div in divs:
    links = div.find_all('a', href=re.compile(r'/article/\d*'), class_='contentHerf')
    for link in links:
        contents = link.span.contents
        contents = [i for i in contents if not isinstance(i, bs4.element.Tag)]
        print(contents)

上面的代碼會(huì)輸出首頁(yè)的所有段子。這樣我們便實(shí)現(xiàn)了半個(gè)爬蟲。為什么是半個(gè)呢?因?yàn)橐粋€(gè)完整的爬蟲可以爬取多個(gè)頁(yè)面,為了簡(jiǎn)便這里只爬首頁(yè),所以只能算半個(gè)爬蟲。不過(guò)如果你想爬取多個(gè)頁(yè)面,代碼稍加修改即可實(shí)現(xiàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容