“干將莫邪” —— Xpath 與 lxml 庫

圖片來自 unsplash

前面的文章,我們已經(jīng)學(xué)會正則表達(dá)式以及 BeautifulSoup庫的用法仑氛。我們領(lǐng)教了正則表達(dá)式的便捷械荷,感受 beautifulSoup 的高效。本文介紹也是內(nèi)容提取的工具 —— Xpath版仔,它一般和 lxml 庫搭配使用游盲。所以,我稱這兩者為“干將莫邪”邦尊。

1 Xpath 和 lxml

  • Xpath

XPath即為XML路徑語言背桐,它是一種用來確定XML(標(biāo)準(zhǔn)通用標(biāo)記語言的子集)文檔中某部分位置的語言。XPath 基于 XML 的樹狀結(jié)構(gòu)蝉揍,提供在數(shù)據(jù)結(jié)構(gòu)樹中找尋節(jié)點(diǎn)的能力链峭。

Xpath 原本是用于選取 XML 文檔節(jié)點(diǎn)信息。XPath 是于 1999 年 11 月 16 日 成為 W3C 標(biāo)準(zhǔn)又沾。因其既簡單方便又容易弊仪,所以它逐漸被人說熟知。

  • lxml

lxml 是功能豐富又簡單易用的杖刷,專門處理 XML 和 HTML 的 Python 官網(wǎng)標(biāo)準(zhǔn)庫励饵。

2 Xpath 的語法

正則表達(dá)式的枯燥無味又學(xué)習(xí)成本高,Xpath 可以說是不及其萬分之一滑燃。所以只要花上 10 分鐘役听,掌握 Xpath 不在話下。Xpath 的語言以及如何從 HTML dom 樹中提取信息表窘,我將其歸納為“主干 - 樹支 - 綠葉”典予。

2.1 “主干” —— 選取節(jié)點(diǎn)

抓取信息,我們需知道要從哪里開始抓取乐严。因此瘤袖,需要找個(gè)起始節(jié)點(diǎn)。Xpath 選擇起始節(jié)點(diǎn)有以下可選:

表達(dá)式 描述
nodename 選取標(biāo)簽節(jié)點(diǎn)的所有子節(jié)點(diǎn)昂验。
/ 從根節(jié)點(diǎn)選取捂敌,html DOM 樹的節(jié)點(diǎn)就是 html。
// 從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn)既琴,而不考慮它們的位置占婉。
. 選擇當(dāng)前節(jié)點(diǎn),一般用于二級提取呛梆。
.. 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)锐涯,在二級提取時(shí)用到。
@ 選取屬性填物。

我們通過以下實(shí)例來了解其用法:

路徑表達(dá)式 描述
xpath('//div') 選取 div 元素的所有子節(jié)點(diǎn)纹腌。
xpath('/div') 選取 div 元素作為根節(jié)點(diǎn)霎终。如果同級有多個(gè) div ,那么所有 div 都會被選為根節(jié)點(diǎn)升薯。
xpath('/div/span') 選取屬于 div 元素<font color='red'>下</font>所有 span 元素節(jié)點(diǎn)莱褒。如果 span 有多個(gè),也會被選中涎劈。
xpath('//div') 選取所有 div 元素節(jié)點(diǎn)广凸,不管它們在文檔的位置。
xpath('//div/span') 選取 div 元素<font color='red'>下</font>的所有 span 元素節(jié)點(diǎn)蛛枚,不管位于 div 之下的什么位置
xpath("http://@[class='content']") 選取包含屬性 class 的值為 content 的節(jié)點(diǎn)谅海,不管是 div 元素還是其他元素
xpath("http://@[id='center']") 選取屬性 id 的值為 center 的節(jié)點(diǎn),不管是 div 元素還是其他元素

如果你對于提取節(jié)點(diǎn)沒有頭緒的時(shí)候蹦浦,可以使用通配符來暫時(shí)替代扭吁。等查看輸出內(nèi)容之后再進(jìn)一步確認(rèn)。

路徑表達(dá)式 描述
xpath('/div/*') 選取 div 元素節(jié)點(diǎn)<font color='red'>下</font>的所有節(jié)點(diǎn)
xpath('/div[@*]') 選取所有帶屬性的 div 元素節(jié)點(diǎn)

2.2 “分支” —— 關(guān)系節(jié)點(diǎn)與謂語

這一步的過程其實(shí)是通過起點(diǎn)一步步來尋找最終包含我們所需內(nèi)容的節(jié)點(diǎn)盲镶。我們有時(shí)需要使用到相鄰節(jié)點(diǎn)信息侥袜。因此,我們需要了解關(guān)系節(jié)點(diǎn)或者謂語溉贿。

  • 關(guān)系節(jié)點(diǎn)

一般而言枫吧,DOM 樹中一個(gè)普通節(jié)點(diǎn)具有父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)宇色、子節(jié)點(diǎn)九杂。當(dāng)然也有例外的情況。這些有些節(jié)點(diǎn)比較特殊宣蠕,可能沒有父節(jié)點(diǎn)尼酿,如根節(jié)點(diǎn);也有可能是沒有子節(jié)點(diǎn)植影,如深度最大的節(jié)點(diǎn)。Xpath 也是有支持獲取關(guān)系節(jié)點(diǎn)的語法涎永。

關(guān)系 路徑表達(dá)式 描述
parent(父) xpath('./parent::*') 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)
ancestor(先輩) xpath('./ancestor::*') 選取當(dāng)前節(jié)點(diǎn)的所有先輩節(jié)點(diǎn)思币,包括父、祖父等
ancestor-or-self(先輩及本身) xpath('./ancestor-or-self::*') 選取當(dāng)前節(jié)點(diǎn)的所有先輩節(jié)點(diǎn)以及節(jié)點(diǎn)本身
child(子) xpath('./child::*') 選取當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)
descendant(后代) xpath('./descendant::*') 選取當(dāng)前節(jié)點(diǎn)的所有后代節(jié)點(diǎn)羡微,包括子節(jié)點(diǎn)谷饿、孫節(jié)點(diǎn)等
following xpath('./following ::*') 選取當(dāng)前節(jié)點(diǎn)結(jié)束標(biāo)簽后的所有節(jié)點(diǎn)
following-sibing xpath('./following-sibing::*') 選取當(dāng)前節(jié)點(diǎn)之后的兄弟節(jié)點(diǎn)
preceding xpath('./preceding::*') 選取當(dāng)前節(jié)點(diǎn)開始標(biāo)簽前的所有節(jié)點(diǎn)
preceding-sibling xpath('./parent::*') 選取當(dāng)前節(jié)點(diǎn)之前的兄弟節(jié)點(diǎn)
self(本身) xpath('./self::*') 選取當(dāng)前節(jié)點(diǎn)本身
  • 謂語

謂語用來查找某個(gè)特定的節(jié)點(diǎn)或者包含某個(gè)指定的值的節(jié)點(diǎn)琅催。同時(shí)狞甚,它是被嵌在方括號中的。

路徑表達(dá)式 描述
xpath('./body/div[1]') 選取 body 元素節(jié)點(diǎn)<font color='red'>下</font>的第一個(gè) div 子節(jié)加袋。
xpath('./body/div[last()]') 選取 body 元素節(jié)點(diǎn)<font color='red'>下</font>的最后一個(gè) div 子節(jié)盯蝴。
xpath('./body/div[last()-1]') 選取 body 元素節(jié)點(diǎn)<font color='red'>下</font>的倒數(shù)第二個(gè) div 子節(jié)毅哗。
xpath('./body/div[position()-3]') 選取 body 元素節(jié)點(diǎn)<font color='red'>下</font>的前二個(gè) div 子節(jié)听怕。
xpath('./body/div[@class]') 選取 body 元素節(jié)點(diǎn)<font color='red'>下</font>的所有帶有 class 屬性的 div 子節(jié)。
xpath("./body/div[@class='content']") 選取 body 元素節(jié)點(diǎn)<font color='red'>下</font>的 class 屬性值為 centent 的 div 子節(jié)虑绵。

2.3"綠葉" —— 節(jié)點(diǎn)內(nèi)容以及屬性

到了這一步尿瞭,我們已經(jīng)找到所需內(nèi)容的節(jié)點(diǎn)了。接下來就是獲取該節(jié)點(diǎn)中的內(nèi)容了翅睛。Xpath 語法提供了提供節(jié)點(diǎn)的文本內(nèi)容以及屬性內(nèi)容的功能声搁。

路徑表達(dá)式 描述
text() 獲取節(jié)點(diǎn)的本文內(nèi)容
@屬性 獲取節(jié)點(diǎn)的屬性內(nèi)容

具體用法見以下實(shí)例:

路徑表達(dá)式 描述
xpath('./a/text()') 獲取當(dāng)前節(jié)點(diǎn)<font color='purple'>中</font> a 元素節(jié)點(diǎn)<font color='red'>中</font>的本文內(nèi)容
xpath('./a/@href') 獲取當(dāng)前節(jié)點(diǎn)<font color='purple'>中</font> a 元素節(jié)點(diǎn)<font color='red'>中</font>的 href 屬性的內(nèi)容

3 lxml 的用法

3.1 安裝 lxml

pip 是安裝庫文件的最簡便的方法,具體命令如下:

pip install lxml
# 如果出現(xiàn)因下載失敗導(dǎo)致安裝不上的情況捕发,可以先啟動 ss 再執(zhí)行安裝命令
# 或者在終端中使用代理
pip --proxy http://代理ip:端口 install lxml

3.2 使用 lxml

lxml 使用起來是比較簡單的疏旨。我們首先要使用 lxml 的 etree 將 html 頁面進(jìn)行初始化,然后丟給 Xpath 匹配即可扎酷。具體用法如下:

from lxml import etree

html = requests.get(url)           # 使用 requests 請求網(wǎng)頁
selector = etree.HTML(html.text)
content = selector.xpath('//a/text()')

沒錯(cuò)檐涝,就這短短幾行代碼即可完成信息提取。
值得注意的是:xpath 查找匹配返回的類型有可能是一個(gè)值霞玄,也有可能是一個(gè)存放多個(gè)值的列表骤铃。這個(gè)取決于你的路徑表達(dá)式是如何編寫的。


上篇文章:詳解 Requests 庫的用法
推薦閱讀:Python 多進(jìn)程與多線程


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坷剧,一起剝皮案震驚了整個(gè)濱河市惰爬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惫企,老刑警劉巖撕瞧,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異狞尔,居然都是意外死亡丛版,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門偏序,熙熙樓的掌柜王于貴愁眉苦臉地迎上來页畦,“玉大人,你說我怎么就攤上這事研儒≡ビВ” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵端朵,是天一觀的道長好芭。 經(jīng)常有香客問我,道長冲呢,這世上最難降的妖魔是什么舍败? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上邻薯,老公的妹妹穿的比我還像新娘裙戏。我一直安慰自己,他們只是感情好弛说,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布挽懦。 她就那樣靜靜地躺著,像睡著了一般木人。 火紅的嫁衣襯著肌膚如雪信柿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天醒第,我揣著相機(jī)與錄音渔嚷,去河邊找鬼。 笑死稠曼,一個(gè)胖子當(dāng)著我的面吹牛形病,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霞幅,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼漠吻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了司恳?” 一聲冷哼從身側(cè)響起途乃,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扔傅,沒想到半個(gè)月后耍共,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猎塞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年试读,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荠耽。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钩骇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铝量,到底是詐尸還是另有隱情伊履,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布款违,位于F島的核電站,受9級特大地震影響群凶,放射性物質(zhì)發(fā)生泄漏插爹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赠尾。 院中可真熱鬧力穗,春花似錦、人聲如沸气嫁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寸宵。三九已至崖面,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間梯影,已是汗流浹背巫员。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甲棍,地道東北人简识。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像感猛,于是被迫代替她去往敵國和親七扰。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 20170531 這幾天重新拾起了爬蟲陪白,算起來有將近5個(gè)月不碰python爬蟲了颈走。 對照著網(wǎng)上的程序和自己以前寫的...
    八神蒼月閱讀 14,164評論 3 44
  • 人生苦短,我用Python拷泽。 起初疫鹊,這篇文章是打算來寫 XPath 的,可是后來一想司致,我需要的僅是 XPath 的...
    Moscow1147閱讀 20,764評論 1 14
  • 先說酒店脂矫。 此次行程非常寬松枣耀,于是定了中午的航班飛廣州,預(yù)定了接機(jī)服務(wù)庭再,順利地達(dá)到廣州長隆酒店捞奕。 長隆酒店位于長隆...
    諾娃兒閱讀 199評論 0 0
  • 一.iOS開發(fā) iOS提示框,為什么你應(yīng)該使用 MBProgressHUD? iOS代碼實(shí)踐總結(jié) Reactive...
    PPAbner閱讀 828評論 1 14
  • 向來佳酒似佳人拄轻,每到銜杯倍覺親颅围。 難怪飲時(shí)消寂寞,自然醉后更精神恨搓。 因誰激起當(dāng)時(shí)興院促,竟自開懷現(xiàn)在身筏养。 莫問詩心何日...
    雪窗_武立之閱讀 890評論 1 10