相信每一位初學(xué)爬蟲的小羊都會對網(wǎng)頁HTML文檔的解析感到頭疼,不知道lxml歹颓、BeautifulSoup和pyquery這三個庫的解析原理菩颖,下面正羊羊就講一講對這個網(wǎng)頁解析過程的理解和這三個庫的基本使用啦。
首先晌缘,這個網(wǎng)頁解析是指對網(wǎng)頁內(nèi)容的提取,比如鏈家網(wǎng)上的房源信息痢站,如下圖磷箕,畫紅框的是我們要的信息。
然后按F12打開瀏覽器的監(jiān)控臺阵难,或者是在紅框的字體上右鍵點(diǎn)擊“檢查”岳枷,可以看到網(wǎng)頁代碼如下:
(先不用理會里面的代碼是講啥,不過可以留意里面的中文就是我們要的信息)
我們可以看到呜叫,每個中文信息前面空繁,都會有紅框圈起來的“標(biāo)簽”,像是
當(dāng)然朱庆,僅靠這些標(biāo)簽還不行盛泡,每個標(biāo)簽下面依照信息的種類有不同的類別,<div標(biāo)簽下就分了不同的類別class:
像是這紅框里面的就是不同的類別了椎工。前面說的三種第三方庫的作用饭于,就是根據(jù)這些標(biāo)簽以及標(biāo)簽下的不同分類蜀踏,提取出我們需要的信息。
所以掰吕,要想用好這三個第三方庫果覆,我們就得了解含這些標(biāo)簽的框架結(jié)構(gòu)。
回看前面的幾幅網(wǎng)頁代碼圖殖熟,我們可以發(fā)現(xiàn)局待,<div標(biāo)簽前面的縮進(jìn)是不一樣的,有些前面還有一個倒三角符號菱属。我們在網(wǎng)頁監(jiān)控臺上點(diǎn)擊這些倒三角的符號钳榨,可以讓下面有進(jìn)一步縮進(jìn)的信息收起或展開。這也就表明纽门,標(biāo)簽與標(biāo)簽之間薛耻,存在著一種遞歸關(guān)系。還是上一幅圖赏陵,正羊羊?qū)⒁恍?biāo)簽標(biāo)個號饼齿,方便下面的講解。
首先蝙搔,標(biāo)簽1和標(biāo)簽2的縮進(jìn)不同缕溉,由標(biāo)簽1引申出標(biāo)簽2,進(jìn)一步吃型,標(biāo)簽2引申出標(biāo)簽3~8证鸥,而標(biāo)簽3~8屬同一級別。從而勤晚,這8個標(biāo)簽有如下的引申關(guān)系:
我們將各個標(biāo)簽成為“節(jié)點(diǎn)”枉层,用親緣關(guān)系來表達(dá)各個節(jié)點(diǎn)之間的關(guān)系。其中运翼,標(biāo)簽1相對于標(biāo)簽2來講是“父節(jié)點(diǎn)”(parent)返干,標(biāo)簽2相對于標(biāo)簽1來講是“子節(jié)點(diǎn)”(children)。同理血淌,標(biāo)簽3~8是標(biāo)簽2的子節(jié)點(diǎn)(childrens)矩欠。在標(biāo)簽3~8中,各個節(jié)點(diǎn)互為兄弟節(jié)點(diǎn)(sibling)悠夯,他們都是標(biāo)簽1的子孫節(jié)點(diǎn)(descendant)癌淮,標(biāo)簽1是他們的祖節(jié)點(diǎn)(ancestor)。
(前文所列的英文為程序中所用名詞沦补,與英語的語法和意義無關(guān)乳蓄。)
有了上面所述的知識,我們就可以用解析庫啦夕膀。
lxml
為講解方便虚倒,我們采用下圖所示的HTML代碼:
首先來看下這里面的標(biāo)簽美侦,分別是<div>、<ul>魂奥、<li>菠剩、<a>,這四個標(biāo)簽層級依次遞減耻煤,最外層為<div>具壮,最內(nèi)層為<a。有如下的引申關(guān)系:
程序上先導(dǎo)入lxml庫哈蝇,然后列舉出<li節(jié)點(diǎn)下的內(nèi)容:
藍(lán)色框中有以<li為標(biāo)簽的3個條目棺妓,結(jié)果也輸出了含3個元素的列表。這些元素表示節(jié)點(diǎn)<li為Element類型炮赦。(這個不重要怜跑,可以不用管)
現(xiàn)在我們需要留意到,這段HTML文本中的每段字符吠勘,都會由尖括號<>包圍起來妆艘,除了節(jié)點(diǎn)
在lxml庫里,這里的“item”信息被定義成text看幼,我們用text()來表示這些文本。
就這樣幌陕,我們將需要的3個“item”給提取了出來诵姜。
這里提取的原理其實(shí)很簡單,就是按照標(biāo)簽一個跟著一個地對應(yīng)起來搏熄,用text()表示要提取的信息棚唆,讓xpath把這條字符串和原文匹配起來,輸出每一個text()表示的內(nèi)容心例。
舉個栗子宵凌,我們把上面xpath中用于匹配的字符串改一下,把li前面的//變?yōu)?:
這是因?yàn)樵趌i節(jié)點(diǎn)里沒有文本止后,只有屬于節(jié)點(diǎn)a的文本瞎惫,所以匹配不到。如果覺得難以理解译株,就權(quán)且讓匹配字符串開頭都是//吧瓜喇。
前面我們說到,緊靠標(biāo)簽來定位信息還是不夠的歉糜,我們還需要標(biāo)簽里的屬性乘寒,像是class。屬性的匹配方法示例如下:
這就是獲取a節(jié)點(diǎn)下屬性href為”link2.html”的文本的方法匪补。
更多功能請參照官方文檔:https://lxml.de/
BeautifulSoup
相對于xpath伞辛,BeautifulSoup操作起來會容易得多烂翰,它不需要//和/這些符號來一一匹配標(biāo)簽(節(jié)點(diǎn)),而是根據(jù)屬性來直接挑出文本信息蚤氏。我們用下面這段HTML代碼來演示:
圖中紅框里面的是我們關(guān)心的信息甘耿。有一點(diǎn)要留意,HTML代碼中每個節(jié)點(diǎn)有相應(yīng)的節(jié)點(diǎn)來閉合瞧捌,像是第一個紅框里的節(jié)點(diǎn)<title>棵里,會由</title>來閉合,像是<head>姐呐、<p>殿怜、<a>都有閉合,但是<html>和<body>卻沒有曙砂,我們先來用BeautifulSoup來解析這段HTML文本:
可以看到头谜,BeautifulSoup自動把</body>和</html>補(bǔ)齊了,這也是這個庫的優(yōu)點(diǎn)之一鸠澈。
現(xiàn)在我們可以對里面的內(nèi)容進(jìn)行解析了:
可以看到柱告,我們可以直接用標(biāo)簽<title>和文本代名詞string來取出我們要的文本,這里的string的作用和前面說的text()作用是一樣的笑陈。
在這段HTML代碼中际度,我們可以了解到節(jié)點(diǎn)b的父節(jié)點(diǎn)為節(jié)點(diǎn)p,那么我們就提取p中的屬性name的值:
因?yàn)槭且獜墓?jié)點(diǎn)b連接到節(jié)點(diǎn)p涵妥,而p是b的父節(jié)點(diǎn)(parent)乖菱,從而,用b.parent蓬网,所需信息是p中的屬性(attrs)窒所,名稱為name,故而用b.parent.attrs[‘name’]帆锋。顯然吵取,如果是屬性class,那么方括號(索引)里的就是’class’了锯厢。
更多用法請參考官方文檔:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
pyquery
這個庫比BeautifulSoup更強(qiáng)大皮官,這體現(xiàn)在其對信息的選取能力要更強(qiáng)。對HTML的初步解析(初始化)方法有多種哲鸳,可以導(dǎo)入HTML文本臣疑,也可以直接寫入要解析的網(wǎng)站網(wǎng)址,當(dāng)然也可以讓程序直接解析html文件:
具體的解析方法可以直接去看官網(wǎng)啦徙菠!
https://pyquery.readthedocs.io/en/latest/
看更多內(nèi)容讯沈,歡迎關(guān)注公眾號“正羊羊部落”