XPath定義
XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對元素和屬性進(jìn)行遍歷。它最初是用來搜尋 XML 文檔的,現(xiàn)在它同樣適用于 HTML 文檔的搜索
XPath 概覽
XPath 的選擇功能十分強(qiáng)大,它提供了非常簡潔明了的路徑選擇表達(dá)式 。 另外,它還提供了超過100 個內(nèi)建函數(shù),用于字符串、數(shù)值、時間的匹配以及節(jié)點、序列的處理等 。 幾乎所有我們想要定位的節(jié)點,都可以用 XPath 來選擇 。
安裝lxml
pip install lxml
初步使用
讀取本地html文件
etree模塊會自動修正HTML文件中缺失的內(nèi)容
from lxml import etree
# 讀取html文檔,字符串
fp = open("index.html",'r',encoding='utf-8')
html = fp.read()
# 實例化XPath解析對象,可以將字符串轉(zhuǎn)換成Element對象
tree = etree.HTML(html)
print(tree)
web網(wǎng)站html文件
from lxml import etree
import requests
html = requests.get(url="https://www.baidu.com")
tree = etree.HTML(html.text)
print(tree)
xpath 常用表達(dá)式
xpath的使用其實就是根據(jù)表達(dá)式找出文檔中所有符合條件的內(nèi)容
表達(dá)式 | 描述 |
---|---|
nodename | 選取此節(jié)點的所有子節(jié)點 |
/ | 從當(dāng)前節(jié)點選取直接子節(jié)點 |
// | 從當(dāng)前節(jié)點選取子孫節(jié)點 |
. | 選取當(dāng)前節(jié)點 |
.. | 選取當(dāng)前節(jié)點的父節(jié)點 |
@ | 選取屬性 |
* | 通配符,選擇所有元素節(jié)點與元素名 |
[@attrib] | 選取具有給定屬性的所有元素 |
[@attrib=‘value’] | 選取給定屬性具有給定值的所有元素 |
[tag] | 選取所有具有指定元素的直接子節(jié)點 |
[tag=‘text’] | 選取所有具有指定元素并且文本內(nèi)容是text節(jié)點 |
獲取所有節(jié)點
fp = open("index.html",'r',encoding='utf-8')
html = fp.read()
tree = etree.HTML(html)
result = tree.xpath("http://*") # 獲取所有節(jié)點
print(result)
輸入:
解釋:
// 獲取當(dāng)前節(jié)點的子孫節(jié)點 * 代表匹配所有節(jié)點,//* 就代表獲取當(dāng)前節(jié)點的所有子孫節(jié)點
獲取子孫節(jié)點中的div節(jié)點
# 獲取當(dāng)前節(jié)點下的所有div的子孫節(jié)點
result = tree.xpath("http://div")
輸出:
獲取子節(jié)點
現(xiàn)在要獲取<html>下的head節(jié)點以及head節(jié)點里面的title節(jié)點
result = tree.xpath("/html/head") # 獲取head節(jié)點
print(result)
result = tree.xpath("/html/head/title") # 獲取title節(jié)點
print(result)
輸出:
解釋:這里我們采用的是 /
來進(jìn)行獲取的,每次獲取一級,依次獲取到目標(biāo)元素
獲取父親節(jié)點
通過 /
、//
可以獲取子節(jié)點或者子孫節(jié)點,現(xiàn)在我學(xué)習(xí)如何通過子節(jié)點找父節(jié)點
找出li
節(jié)點的父節(jié)點,找出li
節(jié)點的父節(jié)點的父親節(jié)點
result = tree.xpath("http://li/..")
print(result)
result = tree.xpath("http://li/../..")
print(result)
輸出:
通過輸出我們可以看到li
的父節(jié)點是ul
, ul
的父節(jié)點是div
解釋:
先通過 //li
找到li
節(jié)點在通過 ..
找到父節(jié)點
屬性匹配
找出li
標(biāo)簽中class=item01的元素
result = tree.xpath('/html/body/div/ul/li[@class="item01"]')
print(result)
輸出:
選擇屬性中有id的
result = tree.xpath('/html/body/div/ul/li[@id]')
print(result)
輸出:
解釋:
通過@
我們可以根據(jù)屬性尋找節(jié)點,可以指定屬性值,也可以直接根據(jù)屬性進(jìn)行查詢
獲取文本
獲取li
中的文字
# 直接獲取li標(biāo)簽下面所有子孫元素的文字
result = tree.xpath('/html/body/div/ul/li//text()')
print(result)
# 通過尋找子元素的方式,一級一級的找到文字
result2 = tree.xpath('/html/body/div/ul/li/a/text()')
print(result2)
輸出:
通過輸出的內(nèi)容分析我們能夠看出,直接通過li//text()
獲取到文本內(nèi)容會比li/a/text()
獲取的多,因為li//text()
或獲取li
中所有的文字包括換行,而li/a/text()
只會找出a標(biāo)簽下所有的文字
獲取屬性
有時候我們在進(jìn)行數(shù)據(jù)解析的時候會需要一些屬性值,例如我們在寫爬蟲項目的時候我們往往需要url鏈接
找出li
中id=id01
a
標(biāo)簽中 href
的值
result = tree.xpath('/html/body/div/ul/li[@id="id01"]/a/@href')
print(result)
輸出
解釋:
屬性值的獲取也是通過@ 來進(jìn)行實現(xiàn)的,@href
:獲取href的屬性值
屬性多值匹配
在實際的項目中會出現(xiàn)一個屬性值有多個值的情況出現(xiàn),例如class在實際項目中會有多個值的情況出現(xiàn)
獲取class中含有class_val1的節(jié)點
# 這種方式是錯誤的,并不會找出對應(yīng)的class中含有class_val1的節(jié)點
tree.xpath('/html/body/div/ul/li[@class="class_val1"]')
# 正確的做法 使用contains()函數(shù)
# 獲取class中含有class_val1的節(jié)點
result = tree.xpath('/html/body/div/ul/li[contains(@class,"class_val1")]')
print(result)
輸出:
解釋:
contains()函數(shù) 獲取指定屬性中包含某一屬性值的節(jié)點
使用方式contains(@屬性,"屬性值")
多屬性匹配
有時候我還需要根據(jù)多個屬性來確定一個節(jié)點
找出li
中 class中含有item01且id=id01
中a
標(biāo)簽中的文本
result = tree.xpath('/html/body/div/ul/li[contains(@class,"item01") and @id="id01"]/a/text()')
print(result)
解釋:
使用 and可以連接多個條件值
拓展類似的操作符還有
運算符 | 描述 | 實例 | 返回值 |
---|---|---|---|
or | 或 | age=10 or age=20 | 如果age等于10或者等于20則返回true反正返回false |
and | 與 | age>19 and age<21 | 如果age等于20則返回true,否則返回false |
mod | 取余 | 5 mod 2 1 | |
| | 取兩個節(jié)點的集合 | //book | //cd | 返回所有擁有book和cd元素的節(jié)點集合 |
+ | 加 | 5+4 | 9 |
- | 減 | 5-4 | 1 |
* | 乘 | 5*4 | 20 |
div | 除法 | 6 div 3 | 2 |
= | 等于 | age=10 | true |
!= | 不等于 | age!=10 | true |
< | 小于 | age<10 | true |
<= | 小于或等于 | age<=10 | true |
> | 大于 | age>10 | true |
>= | 大于或等于 | age>=10 | true |
按序選擇
在有些時候我們在選擇的時候可能匹配了多個節(jié)點,但是我們可能只需要其中的某些節(jié)點,xpath為我們提供了可以 根據(jù)索引進(jìn)行取值的操作。
注意在xpath中索引從1開始,并不是以0開始
獲取第一個li
標(biāo)簽
獲取前三個li
標(biāo)簽
獲取最后一個li
標(biāo)簽
# 獲取第一個`li`標(biāo)簽
result = tree.xpath('/html/body/div/ul/li[1]')
print(result)
# 獲取前三個`li`標(biāo)簽
result2 = tree.xpath('/html/body/div/ul/li[position()<4]')
print(result2)
# 獲取最后一個`li`標(biāo)簽
result3 = tree.xpath('/html/body/div/ul/li[last()]')
print(result3)
輸出:
解釋:
position() 返回當(dāng)前正在被處理的節(jié)點的 index 位置
last() 返回所有匹配節(jié)點的最后一個的索引
節(jié)點軸選擇
軸可定義相對于當(dāng)前節(jié)點的節(jié)點集。
(定義有點抽象,看完下面的實例就懂了)
獲取li
的所有的祖先節(jié)點
result = tree.xpath('/html/body/div/ul/li/ancestor::*')
print(result)
輸出:
獲取li
祖先節(jié)點中的div
result = tree.xpath('/html/body/div/ul/li/ancestor::div')
print(result)
輸出:
獲取li
節(jié)點的子孫元素
result = tree.xpath('/html/body/div/ul/li/child::*')
print(result)
獲取li
節(jié)點的子孫元素中a
標(biāo)簽中href="./index.html"
result = tree.xpath('/html/body/div/ul/li/child::a[@href="./index.html"]')
print(result)
解釋:
ancestor、child都稱作軸 ancestor軸就是相對當(dāng)前節(jié)點的所有祖先節(jié)點的集合,child軸就是相對當(dāng)前節(jié)點的子孫節(jié)點的集合,而后面::
后面跟著是對軸節(jié)點集合的操作 *
代表匹配所有的節(jié)點 div
代表取節(jié)點集中的div
節(jié)點,
另外還可以使用其他的篩選條件進(jìn)行篩選child::a[@href="./index.html"]
:選取子孫節(jié)點中a節(jié)點
中href="./index.html"
的節(jié)點,上面學(xué)習(xí)的篩選方式都可以在這里使用。
類似這樣的軸還有很多
軸名稱 | 結(jié)果 |
---|---|
ancestor | 選取當(dāng)前節(jié)點的所有先輩(父、祖父等)。 |
ancestor-or-self | 選取當(dāng)前節(jié)點的所有先輩(父、祖父等)以及當(dāng)前節(jié)點本身。 |
attribute | 選取當(dāng)前節(jié)點的所有屬性。 |
child | 選取當(dāng)前節(jié)點的所有子元素。 |
descendant | 選取當(dāng)前節(jié)點的所有后代元素(子、孫等)。 |
descendant-or-self | 選取當(dāng)前節(jié)點的所有后代元素(子、孫等)以及當(dāng)前節(jié)點本身。 |
following | 選取文檔中當(dāng)前節(jié)點的結(jié)束標(biāo)簽之后的所有節(jié)點。 |
namespace | 選取當(dāng)前節(jié)點的所有命名空間節(jié)點。 |
parent | 選取當(dāng)前節(jié)點的父節(jié)點。 |
preceding | 選取文檔中當(dāng)前節(jié)點的開始標(biāo)簽之前的所有節(jié)點。 |
preceding-sibling | 選取當(dāng)前節(jié)點之前的所有同級節(jié)點。 |
self | 選取當(dāng)前節(jié)點。 |
xpath軸的使用方式都是一樣的,在實際中我們只需要根據(jù)自己的需求選擇合適的軸。
總結(jié)
關(guān)于lxml和xpath的教學(xué)大概就有這么多,這類教程很多用法都不便于講解,這里只是提供一些用法,后續(xù)如果想熟練的使用xpath解析數(shù)據(jù)還需要勤加練習(xí),結(jié)合自己的實際情況進(jìn)行選擇具體的xpath,
在使用一段時間后你可能會發(fā)現(xiàn)最常用的也就最基礎(chǔ)的獲取子節(jié)點、獲取子孫節(jié)點、獲取文本、獲取屬性值。這些也足夠你解決你遇到的絕大部分問題,后面關(guān)于xpath軸的或許在實際中沒等你想到就將問題解決了。但是我還是建議你學(xué)習(xí),在我們看別人的代碼的時候別人可能會用,我們平時可以不會寫但是見到這樣的代碼的時候一定要認(rèn)識。文章來源:http://www.zghlxwxcb.cn/news/detail-420352.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-420352.html
到了這里,關(guān)于lxml&xpath一站式教學(xué)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!