摘要
XPath 使用路徑表達(dá)式來選取 XML 文檔中的節(jié)點(diǎn)或節(jié)點(diǎn)集却盘。節(jié)點(diǎn)是通過沿著路徑 (path) 或者步 (steps) 來選取的狰域。可以通過lxml模塊來使用XPath語法
XPath的語法
初步篩選:
<img src="/wp-content/uploads/2018/08/XPath.png" />
注意:
html文檔的根結(jié)點(diǎn)是html黄橘,但是"/body"并不會(huì)返回body兆览,因?yàn)榇藭r(shí)表示從根結(jié)點(diǎn)開始選取,實(shí)際上路徑位于根結(jié)點(diǎn)一級(jí)旬陡,所以
這級(jí)只有html拓颓,沒有body。需要從根結(jié)點(diǎn)選取body描孟,需要表明從根結(jié)點(diǎn)的下一級(jí)選取驶睦,即"./body"
比如:
./body/div//span/@href
表示文檔中body結(jié)點(diǎn)下兒子結(jié)點(diǎn)中所有的div結(jié)點(diǎn)下的所有子孫結(jié)點(diǎn)中的span結(jié)點(diǎn)的兒子結(jié)點(diǎn)中的href屬性
即:
<html>
...
<body>
<!-- 兒子中所有的div -->
<div>
<!-- 子孫中所有的span -->
<span>
<!-- 兒子結(jié)點(diǎn)中所有的href屬性的值 -->
href的值
</span>
</div>
</body>
</html>
我們發(fā)現(xiàn)砰左,每一級(jí)的標(biāo)簽名都默認(rèn)了選取“所有”該名字標(biāo)簽的前提,而body標(biāo)簽我之所以不用所有的來定義场航,只是因?yàn)橐粋€(gè)html文檔中只有一個(gè)body標(biāo)簽
/和//的區(qū)分是很重要的缠导,后面進(jìn)一步篩選結(jié)點(diǎn)也應(yīng)該在它們的前提下
進(jìn)一步篩選:
謂語:寫在在[]中
相關(guān)函數(shù) :
last() : 獲取最后一個(gè)元素的序號(hào)
position() : 獲取元素的位置序號(hào)
在[]中的可以是序號(hào)(從1開始),可以是屬性溉痢,也可以是邏輯表達(dá)式(等式直接用"=")
比如:
./body/div[last()-1]/div[@id]/span[position()<3]/a[@href="#"]
表示選取文檔中的根結(jié)點(diǎn)下的body的兒子結(jié)點(diǎn)中倒數(shù)第二個(gè)div結(jié)點(diǎn)的兒子結(jié)點(diǎn)中含id屬性的所有div結(jié)點(diǎn)的兒子結(jié)點(diǎn)中前面兩個(gè)span結(jié)點(diǎn)中的兒子結(jié)點(diǎn)中href屬性等于"#"的a結(jié)點(diǎn)
即:
<html>
<body>
.......
<!-- 最后一個(gè)div -->
<div>
<!-- 帶有id屬性的所有div -->
<div id = "...">
<!-- 前面兩個(gè)span-->
<span>
<!-- href屬性等于"#"的a -->
<a href = "#"></a>
</span>
</div>
</div>
</body>
</html>
我們知道僻造,上面選取方式都比較具體,那么有沒有一種比較寬泛的方式選取結(jié)點(diǎn)呢孩饼?有髓削,通配符
- 匹配任何元素節(jié)點(diǎn)。
@* 匹配任何屬性節(jié)點(diǎn)镀娶。
node() 匹配任何類型的節(jié)點(diǎn)立膛。
text() 匹配文本結(jié)點(diǎn)
string() 匹配所有文本結(jié)點(diǎn)
比如:
./body//[@]//*:
表示文檔中body結(jié)點(diǎn)下的所有兒子結(jié)點(diǎn)的帶屬性的兒子結(jié)點(diǎn)的任何類型的子孫結(jié)點(diǎn)
即:
<html>
<body>
<!-- 所有任何類型的兒子結(jié)點(diǎn) -->
<node>
<!-- 所有帶屬性的任何兒子結(jié)點(diǎn)-->
<node attr>
<!-- 所有任何類型的子孫結(jié)點(diǎn) -->
<node>...</node>
</node>
</node>
</body>
</html>
通過上面的知識(shí),我們已經(jīng)可以很好的選取html文檔中的元素了梯码。
總結(jié):
獲取XPath路徑宝泵,就是先使用/或//等初步篩選元素,然后通過謂語或者通配符進(jìn)行進(jìn)一步篩選
說明
以下代碼默認(rèn)已導(dǎo)入lxml模塊中的etree模塊
from lxml import etree
解析過程如下:
- 通過html內(nèi)容生成selector
- 通過selector的xpath方法得到符合匹配條件的元素轩娶,返回列表
- 遍歷列表或者獲取列表中特定元素
比如:
# html內(nèi)容
html = "<!DOCTYPE HTML><html><body><p><a>123</a></p></body></html>"
# 生成解析html的selector
selector = etree.HTML(html)
# 獲取符合條件的元素
content = selector.xpath("http://a")
print(content[0].text) # 123
# 或者
content = selector.xpath("http://a/text()")
print(content[0]) # 123
補(bǔ)充內(nèi)容
沒有特定需求儿奶,其實(shí)不需要用到補(bǔ)充內(nèi)容。
1.選取多個(gè)路徑:
使用"|"運(yùn)算符連接兩個(gè)路徑表示或鳄抒,比如:
./body/div | ./body/div//a
表示./body/div 或 ./body/div//a
2.謂語中能夠使用的運(yùn)算符:
<img src="/wp-content/uploads/2018/08/XPathOpera.png" />
- 軸:
通過“軸名::”的前綴形式改變/的含義闯捎,可用改變選取元素的順序,比如/默認(rèn)為子元素軸可用/child:表示
a/parent::node() :表示a所有的任意類型父節(jié)點(diǎn)
比如许溅,./body//a/parent::node()
表示選取文檔中body的子孫結(jié)點(diǎn)中的所有a結(jié)點(diǎn)的任意類型的父節(jié)點(diǎn)
即:
<html>
<body>
<!--a的所有任意類型的父節(jié)點(diǎn) -->
<node>
<!-- body的所有子孫結(jié)點(diǎn)中的a結(jié)點(diǎn)隙券,記為a -->
<a></a>
</node>
</body>
</html>
可以容易發(fā)現(xiàn),parent::改變了在文檔樹中從上到下選取元素的順序
相關(guān)的軸:
<img src="/wp-content/uploads/2018/08/XPathAxes.jpg">