天天看點

html提取工具好多話還來,Python 爬蟲網頁内容提取工具xpath(一)

上一節,我們詳述了lxml.html的各種操作,接下來我們熟練掌握一下XPath,就可以熟練的提取網頁内容了。

XPath 是什麼?

XPath的全稱是 XML Path Language,即XML 路徑語言,是一種在XML(HTML)文檔中查找資訊的語言。它有4點特性:

XPath 使用路徑表達式在 XML 文檔中進行導航

XPath 包含一個标準函數庫

XPath 是 XSLT 中的主要元素

XPath 是一個 W3C 标準

html提取工具好多話還來,Python 爬蟲網頁内容提取工具xpath(一)

我們從網頁中提取資料,主要應用前兩點。

XPath 路徑表達式

使用XPath我們可以很容易定位到網頁中的節點,也就是找到我們關心的資料。這些路徑跟電腦目錄、網址的路徑很相似,通過/來表示路徑的深度。

XPath 标注函數庫

頭内建了100多個函數,當然我們提取資料用到的有限,也就不用記住全部100多個函數了。

Xpath 的節點(Node)

XPath中的核心就是節點(Node),定義了7種不同類型的節點: 元素(Element)、屬性(Attribute)、文本(Text)、命名空間(Namespace)、處理指令(processing-instruction)、注釋(Comment)和文檔節點(Document nodes)

這些節點組成一棵節點樹,樹的根節點被稱為文檔節點。

其中注釋就是html裡面的注釋:

而命名空間、處理指令和網頁資料提取基本沒關系,這裡就不再詳述。

下面我們以一個簡單的html文檔為例,來解釋不同的節點及其關系。

ABC

  • home
  • python

這段html中的節點有:

文檔節點:

元素節點:

python

屬性節點: id="menu"

XPath 節點的關系

節點間的關系完全照搬人類傳宗接代的輩分關系,但隻是直系關系,沒有叔叔、大伯之類的旁系關系。

還是以上面的html文檔為例來說明節點關系:

父(Parent)

每個元素節點(Element)及其屬性都有一個父節點。

比如,body的父是html,而body是div、ul 的父親。

子(Children)

每個元素節點可以有零個、一個或多個子。

比如,body有兩個子:div,ul,而ul也有兩個子:兩個li。

同輩(Sibling)

同輩有相同的父輩節點。

比如,div和ul是同輩。

先輩(Ancestor)

某節點的父輩及其以上輩分的節點。

比如,li的父輩有:ul、div、body、html

後代(Descendant)

某節點的子及其子孫節點。

比如,body的後代有:div、ul、li。

XPath節點的選取

選取節點,也就是通過路徑表達來實作。這是我們在網頁提取資料時的關鍵,要熟練掌握。

下表是比較有用的路徑表達式:

表達式

說明

nodename

選取目前節點的名為nodename的所有子節點。

/

從根節點選取,在路徑中間時表示一級路徑

//

從目前節點開始選擇文檔中的節點,可以是多級路徑

.

從目前節點開始選取

..

從父節點開始選取

@

按屬性選取

接下來通過具體的示例來加深對路徑表達的了解:

路徑表達式

解釋

/html/body/ul/li

從根節點開始依照路徑選取li元素。傳回多個。

//ul/li[1]

還是選取li元素,但是路徑多級跳躍到ul/li。[1]表示隻取第一個li。

//li[last()]

還是選取li,但路徑更跳躍。[last()]表示取最後一個li元素。

//li[@class]

選取根節點的名為li且有class屬性的所有後代。

//li[@class=”item”]

選擇根節點的名為li且class屬性為item的所有後代。

//body/*/li

選取body的名為li的孫子節點。*是通配符,表示任何節點。

//li[@*]

選取所有帶屬性的li元素。

//body/div | //body/ul

選取body的所有div和ul元素。

body/div

相對路徑,選取目前節點的body元素的子元素div。絕對路徑以 / 開始。

XPath函數

Xpath的函數很多,涉及到錯誤、數值、字元串、時間等等,然而我們從網頁中提取資料的時候隻會用到很少的一部分。其中最重要的就是字元串相關的函數,比如contains()函數。

contains(a, b)

如果字元串a包含字元串b,則傳回true,否則傳回false。

比如: contains(‘猿人學Python’, ‘Python’),傳回true

那麼它用在什麼時候呢?我們知道,一個html标簽的class是可以有多個屬性值的,比如:

...

這段html中div有三個class值,第一個表面它是一條釋出的消息,後面兩個是對格式做了更多的設定。如果我們想提取網頁中所有釋出的消息,隻需要比對到post-item 即可,這時候就可以用上contains了:

doc.xpath('//div[contains(@class, "post-item")]')

跟contains()類似的字元串比對的函數還有:

starts-with(string1, string2) 判斷string1是否以string2開頭

ends-with(string1, string2) 判斷string1是否以string2結尾

matches(string, pattern) 通過正規表達式比對

然而,在lxml的xpath中使用ends-with(), matches() 會報錯

In [232]: doc.xpath('//ul[ends-with(@id, "u")]')

---------------------------------------------------------------------------

XPathEvalError Traceback (most recent call last)

in ()

----> 1 doc.xpath('//ul[ends-with(@id, "u")]')

src/lxml/etree.pyx in lxml.etree._Element.xpath()

src/lxml/xpath.pxi in lxml.etree.XPathElementEvaluator.__call__()

src/lxml/xpath.pxi in lxml.etree._XPathEvaluatorBase._handle_result()

XPathEvalError: Unregistered function

lxml 竟然不支援ends-with(), matches()函數

到lxml官方網站去看看,原來它說了隻支援 XPath 1.0:

lxml supports XPath 1.0, XSLT 1.0 and the EXSLT extensions through libxml2 and libxslt in a standards compliant way.

接着又在Wikipedia上找到Xpath 2.0 和 1.0 的差異對比,果然ends-with(), matches() 隻屬于2.0。下圖中,粗體部分是1.0包含的,其它是2.0也有的:

html提取工具好多話還來,Python 爬蟲網頁内容提取工具xpath(一)

好了,Xpath在網頁内容提取中要用到的部分我們已經學完了。下一節,我們将以執行個體講解xpath具體提取資料的過程。

我的公衆号:猿人學 Python 上會分享更多心得體會,敬請關注。

***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***