xpath在HTML解析中的應用(加強版)

來源:互聯網
上載者:User

經過一番研究以後才發現原來libxml2其實已經內建了對HTML的解析——即使是不很規範的HTML。所以上篇《xpath在XHTML解析中的應用
》完全是我學藝不精的產物。囧

不過好處是順便學習到了j7a7c7k7
兄推薦的tidy(用的是令狐提供的µTidylib
),這也是個好東東。

現在來看如何直接使用lxml(即前文說過的libxml2的一個python binding)處理那個樣本“頁面
”:

import codecs
from lxml import etree

f=codecs.open("raptor.htm","r","utf-8")
content=f.read()
f.close()
tree=etree.HTML(content)

Bingo!果然成功。關鍵就在於etree提供了HTML這個解析函數。之後的事情就好辦多了,因為可以直接對HTML使用xpath。

不過這個樣本頁面中要解析的部分有一個問題就是:那個ul節點沒有id,所以只好麻煩一點了。

完整的xpath應該是這樣寫的(注意,原檔案中的TAG有大小寫情況,但是在XPATH裡只能用小寫):

nodes=tree.xpath(u"/html/body/form/div[@id='leftmenu']/h3[text()='檔案']/following-sibling::ul[1]")

這句xpath的意思是尋找這樣一個東東。

<html>
<body>
<form>
<div id='leftmenu'>
<h3>檔案</h3>
<ul><!-- 找到這裡 --></ul>
</div>
</form>
</body>
</html>

當然更簡單的方法就是直接根據id定位:

nodes=tree.xpath(u"//div[@id='leftmenu']/h3[text()='檔案']/following-sibling::ul[1]")

這兩種方法返回的結果中,nodes[0]就是那個“檔案”的h3節點後面緊跟的第一個ul節點。

之後就可以把每個月份的文本列出(注意,是以上面取得的ul節點為起點):

nodes=nodes[0].xpath("li/a")
for n in nodes:
print n.text

這段的意思是取得這個ul節點下的所有<li><a>節點。之後的迴圈就是把這些節點的常值內容列出。

我只能說libxml2實在是太強大了。

附錄: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()的意思則是取得節點包含的文本。比如:<div>hello<p>world</p><
/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節點。

更複雜的XPATH文法還是請參考官文檔《XML Path Language (XPath)
》。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.