XPath 的使用
? XPath,全稱XML Path Language,即XML路徑語言,它是一門在XML文檔中查找信息的語言,最初用于搜尋XML文檔,但是也同樣適用于HTML文檔的搜索。前面我們在解析或抽取網頁信息時,使用的是正則表達式,雖然這是一個萬能的方法,但是編寫太麻煩了,一旦表達式寫錯就得不到正確的結果,還有就是可讀性不強,寫完后估計自己也不知道這是啥回事了,所以在爬蟲時可以使用XPath來做相應數據的抽取。
先列舉XPath的常用規則:
舉例:
//title[@lang='eng']? ?代表選擇所有名稱為 title,同時屬性lang的值為eng的節點。
?
1. 實例
from lxml import etree text = ''' <div><ul><li class="item-0"><a href="link1.html">first item</a></li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-inactive"><a href="link3.html">third item</a></li><li class="item-1"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul> </div> ''' # 實例化一個XPath對象 etree.HTML(html文檔) html = etree.HTML(text) result = etree.tostring(html) print(result.decode('utf-8'))
首先導入lxml庫的etree模塊,然后聲明了一段HTML文本,調用etree.HTML()初始化,這樣就構造了一個XPath解析對象了。
?
2. 所有節點
使用//開頭的XPath規則來選擇所有符合的幾點,以上面的HTML文本為例,如果要選取所有節點,可以這樣實現:
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//*') print(result)
這里使用*代表所有節點,也就是整個HTML文本中的所有節點都會被獲取。返回的是一個列表,每個元素都是一個Element類型。
當然,此處匹配也可以指定節點:
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li') print(result)
這里選取的是所有li節點,使用//然后直接加上節點名稱即可,調用時直接使用xpath()方法即可。
?
3. 子節點
可以使用//或/來獲取子節點,前者包括子孫節點,而后者僅僅是直接子節點:
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li/a') print(result)
上面得到的是一個包含所有li元素里面的直接子節點a的一個列表。
?
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//ul//a')
上面獲取到的是所有ul節點中的所有a節點。
注意/和//的區別,/用于獲取直接子節點,//用于獲取子孫節點
?
4. 父節點
使用..可以查找父節點:
from lxml import etree html = etree.parse('./test.html',etree.HTTPParser()) result = html.xpath('//a[@href="link4.html"]/../@class') print(result)
上面獲取到的就是href屬性為link4.html的所有a節點的父節點的class屬性
除此以外,還可以使用parent::來獲取父節點:
from lxml import etree html = etree.parse('./test.html',etree.HTTPParser()) result = html.xpath('//a[@href="link4.html"]/parent::*/@class')
?
5. 屬性匹配
使用@符號進行屬性過濾,比如要選取class為item-1的li節點,可以這樣實現:
from lxml import etree html = etree.parse('./test.html',etree.HTTPParser()) result = html.xpath('//li[@class="item-1"]')
?
6. 文本獲取
使用text()方法既可獲取節點中的文本(標簽體):
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li[@class="item-0"]/a/text()') print(result)