Python中利用xpath解析HTML

2021-08-07 15:10:33 字數 3901 閱讀 6768

在進行網頁抓取的時候,分析定位html節點是獲取抓取資訊的關鍵,目前我用的是lxml模組(用來分析xml文件結構的,當然也能分析html結構), 利用其lxml.html的xpath對html進行分析,獲取抓取資訊。

首先,我們需要安裝乙個支援xpath的python庫。目前在libxml2的**上被推薦的python binding是lxml,也有beautifulsoup,不嫌麻煩的話還可以自己用正規表示式去構建,本文以lxml為例講解。

假設有如下的html文件:

1

<

html

>

2<

body

>

3<

form

>

4<

div

id='leftmenu'

>

5<

h3>text

h3>

6<

ul id=』china』

>

7<

li>...

li>

8<

li>...

li>

9......

10ul

>

11<

ul id=』england』

>

12<

li>...

li>

13<

li>...

li>

14......

15ul

>

16div

>

17form

>

18body

>

19html

>

直接使用lxml處理:

1 import codecs

2from lxml import

etree

3 f=codecs.open("

ceshi.html

","r

","utf-8")

4 content=f.read()

5f.close()

6 tree=etree.html(content)

etree提供了html這個解析函式,現在我們可以直接對html使用xpath了,是不是有點小激動,現在就嘗試下吧。

在使用xpath之前我們先來看看作為對照的jquery和re。

在jquery裡要處理這種東西就很簡單,特別是假如那個ul節點有id的話(比如是china』>):

$("#china").each(function());
具體到此處是:

$("#leftmenu").children("h3:contains('text')").next("ul").each(function());
找到id為leftmenu的節點,在其下找到乙個內容包含為」text」的h3節點,再取其接下來的乙個ul節點。

在python裡要是用re來處理就略麻煩一些:

block_pattern=re.compile(u"

(.*?)

", re.i |re.s)

m=block_pattern.findall(content)

item_pattern=re.compile(u"

(.*?)

", re.i |re.s)

items=item_pattern.findall(m[0])

for i in

items:

print i

那麼用xpath要怎麼做呢?其實跟jquery是差不多的:

nodes=tree.xpath("

/descendant::ul[@id='china']

")

當然,現在沒有id的話也就只能用類似於jquery的方法了。完整的xpath應該是這樣寫的(注意,原檔案中的tag有大小寫的情況,但是在xpath裡只能用小寫):

nodes=tree.xpath(u"

/html/body/form/div[@id='leftmenu']/h3[text()='text']/following-sibling::ul[1]

")

更簡單的方法就是像jquery那樣直接根據id定位:

nodes=tree.xpath(u"

//div[@id='leftmenu']/h3[text()='text']/following-sibling::ul[1]

")

這兩種方法返回的結果中,nodes[0]就是那個「text」的h3節點後面緊跟的第乙個ul節點,這樣就可以列出後面所有的ul節點內容了。

如果ul節點下面還有其他的節點,我們要找到更深節點的內容,如下的迴圈就是把這些節點的文字內容列出:

nodes=nodes[0].xpath("

li/a")

for n in

nodes:

print n.text

對比三種方法應該可以看出xpath和jquery對於頁面的解析都是基於xml的語義進行,而re則純粹是基於plain text。re對付簡單的頁面是沒有問題,如果頁面結構複雜度較高的時候(比如一堆的div來回巢狀之類),設計乙個恰當的re pattern可能會遠比寫乙個xpath要複雜。特別是目前主流的基於css的頁面設計方式,其中大部分關鍵節點都會有id――對於使用jquery的頁面來說則更是如此,這時xpath相比re就有了決定性的優勢。

附錄:基本xpath語法介紹,詳細請參考xpath的官方文件

xpath基本上是用一種類似目錄樹的方法來描述在xml文件中的路徑。比如用「/」來作為上下層級間的分隔。第乙個「/」表示文件的根節點(注意,不是指文件最外層的tag節點,而是指文件本身)。比如對於乙個html檔案來說,最外層的節點應該是」/html」。

同樣的,「..」和「.」分別被用來表示父節點和本節點。

xpath返回的不一定就是唯一的節點,而是符合條件的所有節點。比如在html文件裡使用「/html/head/scrpt」就會把head裡的所有script節點都取出來。

為了縮小定位範圍,往往還需要增加過濾條件。過濾的方法就是用「[」「]」把過濾條件加上。比如在html文件裡使用「/html/body/div[@id='main']」,即可取出body裡id為main的div節點。

其中@id表示屬性id,類似的還可以使用如@name, @value, @href, @src, @class….

而 函式text()的意思則是取得節點包含的文字。比如:helloworld

< /div>中,用」div[text()='hello']「即可取得這個div,而world則是p的text()。

函式position()的意思是取得節點的位置。比如「li[position()=2]」表示取得第二個li節點,它也可以被省略為「li[2]」。

不過要注意的是數字定位和過濾 條件的順序。比如「ul/li[5][@name='hello']」表示取ul下第五項li,並且其name必須是hello,否則返回空。而如果用 「ul/li[@name='hello'][5]」的意思就不同,它表示尋找ul下第五個name為」hello「的li節點。

此外,「*」可以代替所有的節點名,比如用」/html/body/*/span」可以取出body下第二級的所有span,而不管它上一級是div還是p或是其它什麼東東。

而 「descendant::」字首可以指代任意多層的中間節點,它也可以被省略成乙個「/」。比如在整個html文件中查詢id為「leftmenu」的 div,可以用「/descendant::div[@id='leftmenu']」,也可以簡單地使用「 //div[@id='leftmenu']」。

至於「following-sibling::」字首就如其名所說,表示同一層的下乙個節點。」following-sibling::*」就是任意下乙個節點,而「following-sibling::ul」就是下乙個ul節點。

風火程式設計 python爬蟲幾個xpath解析方法

requests獲取的響應體 from lxml import etree html etree.html response.text 二進位制型別用.content result html.xpath expression 返回list,乙個用 0 selenium獲取的響應體 result re...

python中xpath的使用

xpath在python的爬蟲學習中,起著舉足輕重的地位,對比正規表示式 re兩者可以完成同樣的工作,實現的功能也差不多,但xpath明顯比re具有優勢,在網頁分析上使re退居二線。xpath介紹 是什麼?全稱為xml path language一種小型的查詢語言 說道xpath是門語言,不得不說它...

python中xpath常用方法 小結

這是乙個test.html檔案內容 以下是xpath使用方法 coding utf 8 import lxml import lxml.etree html lxml.etree.parse test.html print type html res html.xpath li print res ...