Xpath
文章參考:https://www.cnblogs.com/mxjhaima/p/13775844.html#%E6%A1%88%E4%BE%8B
安裝
pip install lxml
引用
from lxml import etree
獲取文檔樹對象
通過Xpath 獲取文檔的對象,獲取到對象後,可以通過文檔的對象去去獲取到樹中的元素。
文本轉化文檔樹對象
def strToEleObj():
doc = '''
<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>
'''
# 把文本轉換成一個文檔樹對象
html = etree.HTML(doc)
result = etree.tostring(html)
print(str(result, 'utf-8'))
文件轉化文檔樹對象
def fileToEleObj():
# 讀取外部文件 index.html
html = etree.parse('./index.html')
# pretty_print=True 會格式化輸出
result = etree.tostring(html, pretty_print=True) # pretty_print=True 會格式化輸出
print(result)
節點、元素、屬性、內容
xpath 的思想是通過 路徑表達 去尋找節點。節點包括元素,屬性,和內容
路徑表達式
/ 根節點,節點分隔符,
// 任意位置
. 當前節點
.. 父級節點
@ 屬性
示例
from lxml import etree
'''
路徑表達式
'''
def get_el_list():
doc = '''
<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>
'''
# 把文本轉換成一個文檔樹對象
html = etree.HTML(doc)
# 獲取當前節點
print('獲取當前節點---> ', html.xpath('.'))
# 獲取 根節點 標籤 ,當前元素無根節點 通過 打印 etree.tostring(html) ,會發現根節點爲 <html> </html> 包裹的內容 ,上一行獲取的當前節點爲 html
print('獲取 根節點 標籤---> ', html.xpath('/'))
# 獲取 li 標籤
print('獲取 li 標籤---> ', html.xpath('//li'))
# 獲取 li 下的 a 標籤屬性
print('獲取li下的 a 標籤屬性----> ', html.xpath('//li/a/@href'))
# 獲取 p 標籤 ,此標籤不存在 返回結果爲空數組
print('獲取 p 標籤----> ', html.xpath('//p '))
輸出結果
獲取當前節點---> [<Element html at 0x2a989854200>]
獲取 根節點 標籤---> []
獲取 li 標籤---> [<Element li at 0x2a9898ece40>, <Element li at 0x2a9899240c0>, <Element li at 0x2a989924180>, <Element li at 0x2a9899241c0>, <Element li at 0x2a989924200>]
獲取li下的 a 標籤屬性----> ['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
獲取 p 標籤----> []
說明
- 將doc 轉換成 文檔對象後,爲 <html> </html> 包裹的內容;故獲取到的當前的節點對象爲HTML;
- 當前節點爲HTML,無根節點故返回爲空數組即:[];
- 查詢不存在的節點時,返回空數組即:[]
通配符
* 任意元素
@* 任意屬性
node() 任意子節點(元素,屬性,內容)
示例
'''
通配符
'''
from lxml import etree
def get_el_by_anyChar():
doc = '''
<div>
<ul class="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>
'''
# 把文本轉換成一個文檔樹對象
html = etree.HTML(doc)
# 獲取 ul 下的所有子節點
print('獲取 ul 下的所有子節點---> ', html.xpath('//ul/node()'))
# 獲取 任意元素[所有的]
print('獲取 ul 下 任意元素[所有的]---> ', html.xpath('//ul/*'))
# 獲取 任意屬性 [所有的]
print('獲取 ul 下 任意屬性[所有的]---> ', html.xpath('//ul/@*'))
輸出結果
獲取 ul 下的所有子節點---> ['\n ', <Element li at 0x1d4792b5e80>, '\n ', <Element li at 0x1d4792b5e00>, '\n ', <Element li at 0x1d4792b5f00>, '\n ', <Element li at 0x1d4792b5f40>, '\n ', <Element li at 0x1d4792b5ec0>, ' 閉合標籤\n ']
獲取 任意元素---> [<Element li at 0x1d47928dd80>, <Element li at 0x1d4792b5e80>, <Element li at 0x1d4792b5fc0>, <Element li at 0x1d4792b5e00>, <Element li at 0x1d4792b5f00>]
獲取 任意屬性---> ['ul']
謂語
//a[n] n爲大於零的整數,代表子元素排在第n個位置的<a>元素
//a[last()] last() 代表子元素排在最後個位置的<a>元素
//a[last()-] 和上面同理,代表倒數第二個
//a[position()<3] 位置序號小於3,也就是前兩個,這裏我們可以看出xpath中的序列是從1開始
//a[@href] 擁有href的<a>元素
//a[@href='www.baidu.com'] href屬性值爲'www.baidu.com'的<a>元素
//book[@price>2] price值大於2的<book>元素
示例
from lxml import etree
def get_el_by_wei():
doc = '''
<div>
<ul class="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>
'''
# 把文本轉換成一個文檔樹對象
html = etree.HTML(doc)
# 獲取第一個 li / a 元素 裏面的文本
print('獲取第一個 ---> ', html.xpath('//li[1]/a/text()'))
# 獲取最後一個 li / a 元素 裏面的文本
print('獲取最後一個 ---> ', html.xpath('//li[last()]/a/text()'))
# 獲取倒數第二個 li / a元素 裏面的文本
print('獲取 倒數第二個---> ', html.xpath('//li[last()-1]/a/text()'))
# 獲取位置序號小於3,也就是前兩個 li / a元素 裏面的文本
print('獲取位置序號小於3 ---> ', html.xpath('//li[position()<3]/a/text()'))
# 獲取擁有href的<a>元素下的文本
print('獲取第一個 ---> ', html.xpath('//a[@href]/text()'))
# 獲取 a 標籤下 href = link3.html的a元素下的文本 注意 不是 == 而是 =
print('獲取 a 標籤下 href = link3.html的<a>元素---> ', html.xpath('//a[@href="link3.html"]/text()'))
# 獲取 ul class == ul 的
print('獲取 ul class == ul ---> ', html.xpath('//ul[@class="ul"]'))
多個路徑
用| 連接兩個表達式,可以進行 或匹配
//book/title | //book/price
示例
from lxml import etree
def get_el_mutil_path():
doc = '''
<div>
<ul class="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>
'''
# 把文本轉換成一個文檔樹對象
html = etree.HTML(doc)
# 獲取li 下 class = item-inactive 或者 item-1
print('獲取li 下 class = item-inactive 或者 item-1 ---> ', html.xpath('//li[@class="item-inactive"] | //li[@class="item-1"] '))
輸出結果
獲取li 下 class = item-inactive 或者 item-1 ---> [<Element li at 0x1b490955f40>, <Element li at 0x1b490966200>, <Element li at 0x1b490966180>]
函數
更多函數查看https://www.w3school.com.cn/xpath/xpath_functions.asp
contains(string1,string2)
starts-with(string1,string2)
# 文本
text()
# 最後一個
last()
# 位置
position()
# 回去所有節點
node()
'''
函數
'''
from lxml import etree
def get_el_func():
doc = '''
<div>
<ul class="ul" >
<li class="item-0 active"><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>
'''
# 把文本轉換成一個文檔樹對象
html = etree.HTML(doc)
# 匹配 class 包含 active 的 元素
print(html.xpath("//*[contains(@class,'active')]"))
# 獲取所有 li / a 文本
print(html.xpath("//li/a/text()"))
# 獲取最後一個 li / a 文本
print(html.xpath("//li[last()]/text()"))
# 獲取位置爲1的li /a 文本 ,節點時從1開始 而不是0
print(html.xpath("//li[position()=1]/a/text()"))
輸出結果
[<Element li at 0x23ea36d0400>, <Element li at 0x23ea36d0180>]
['first item', 'second item', 'third item', 'fourth item', 'fifth item']
[' # 注意,此處缺少一個 ']
['first item']
實戰信息
獲取某電影網站電影名稱、簡單描述、圖片
import requests
from lxml import etree
'''
獲取電影信息列表
'''
def get_moive_info_list(url):
# 定義頭部信息
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
res = requests.get(url, headers=headers)
# res.text 返回的是 文本
html = res.text
print('輸出響應信息->',html)
# 將文本轉換成文檔對象
selector = etree.HTML(html)
# 返回是電影名列表
title_list = selector.xpath('//a[@class="pic-pack-outer"]/h3/text()')
print('電影名稱列表:',title_list)
# 獲取簡單描述
desc_list = selector.xpath('//a[@class="pic-pack-outer"]/p/text()')
print('電影名稱簡單描述:', desc_list)
# 圖片
img_list = selector.xpath('//a[@class="pic-pack-outer"]/img/@src')
print('圖片列表:', img_list)
if __name__ == '__main__':
url = 'https://xxxxxxx/vod/list/n_1_t_25/o1p1.html'
get_moive_info_list(url)
輸出結果
輸出響應信息-> <!DOCTYPE html>
·······
</body>
</html>
電影名稱列表: ['辣媽犟爸', '五月梨花香', '歲歲平安',.....]
電影名稱簡單描述: ['年輕村官奮鬥歷程', '脫貧致富振興家鄉', .....]
圖片列表: ['https://image11.m1905.cn/uploadfile/2022/0804/thumb_1_150_203_20220804094442559303.jpg', .... 'https://image11.m1905.cn/uploadfile/2016/0926/thumb_1_150_85_20160926105222739343.jpg']