自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

肝了三天三夜,一文道盡 Python的 Xpath 解析!

開(kāi)發(fā) 前端
大家在寫(xiě)爬蟲(chóng)時(shí),往往獲取到網(wǎng)頁(yè)之后,需要從網(wǎng)頁(yè)中提取我們需要的信息。這時(shí)候就需要用到 xpath 或者 css 選擇器來(lái)定位頁(yè)面元素信息。

[[434465]]

大家在寫(xiě)爬蟲(chóng)時(shí),往往獲取到網(wǎng)頁(yè)之后,需要從網(wǎng)頁(yè)中提取我們需要的信息。這時(shí)候就需要用到 xpath 或者 css 選擇器來(lái)定位頁(yè)面元素信息。但是,由于這兩者都是非人性化的語(yǔ)法,導(dǎo)致好多人望而生畏,經(jīng)常為這個(gè)發(fā)愁。

今天我就嘗試用一篇文章來(lái)道盡 xpath 解析 HTML 的方方面面,希望大家看完這篇文章后,從此不再害怕 xpath 解析。

路徑表達(dá)式

  • nodename:選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn)
  • /:從當(dāng)前節(jié)點(diǎn)選取直接子節(jié)點(diǎn)
  • //:從當(dāng)前接點(diǎn)選取子孫節(jié)點(diǎn)
  • .:選取當(dāng)前節(jié)點(diǎn)
  • ..:選取當(dāng)前接點(diǎn)的父節(jié)點(diǎn)
  • @:選取屬性

我們先放上一段 HTML 代碼:

  1. <html> 
  2.   <head> 
  3.     <title> 
  4.       Xpath test page 
  5.     </title> 
  6.   </head> 
  7.   <body> 
  8.     <div class="navli"
  9.       <span class="nav_tit"
  10.         <a href="https://www.baidu.com/"
  11.           百度 
  12.         </a> 
  13.         <i class="group" /> 
  14.       </span> 
  15.     </div> 
  16.     <div class="navli"
  17.       <span class="nav_tit"
  18.         <a href="https://news.cctv.com/"
  19.           新聞?lì)l道 
  20.         </a> 
  21.       </span> 
  22.     </div> 
  23.     <div class="navli"
  24.       <span class="nav_tit"
  25.         <a href="https://sports.cctv.com/"
  26.           體育頻道 
  27.         </a> 
  28.       </span> 
  29.     </div> 
  30.   </body> 
  31. </html> 

接下來(lái),我們針對(duì)這段 HTML 代碼來(lái)進(jìn)行 xpath 解析。

要進(jìn)行 xpath 解析,我們先要將 HTML 文本轉(zhuǎn)化成對(duì)象:

  1. from lxml import etree 
  2.  
  3. text = ''
  4. <div> 
  5.             <ul id='ultest'
  6.                  <li class="item-0"><a href="link1.html">first item</a></li> 
  7.                  <li class="item-1"><a href="link2.html">second item</a></li> 
  8.                  <li class="item-inactive"><a href="link3.html">third item</a></li> 
  9.                  <li class="item-1"><a href="link4.html"><span>fourth item</span></a></li> 
  10.                  <li class="item-0"><a href="link5.html">fifth item</a> # 注意,此處缺少一個(gè) </li> 閉合標(biāo)簽 
  11.              </ul> 
  12.          </div> 
  13. ''
  14. # 調(diào)用HTML類(lèi)進(jìn)行初始化,這樣就成功構(gòu)造了一個(gè)XPath解析對(duì)象。 
  15. page = etree.HTML(text)     
  16. print(type(page)) 

我們可以看到打印的結(jié)果:

  1. <class 'lxml.etree._Element'

nodename

nodename 表示根據(jù)標(biāo)簽名字選取標(biāo)簽,注意只會(huì)選擇子標(biāo)簽!比如:如果是兒子的兒子則選取不到。

  1. print(page.xpath("body")) 
  2.  
  3. //[<Element body at 0x1966d1c48c0>] 
  4.  
  5. print(page.xpath("ul")) 
  6.  
  7. // [] 

這個(gè) nodename 我有點(diǎn)不是太清楚,當(dāng)我使用 body 時(shí),可以找到出 body 節(jié)點(diǎn)元素,但是使用 ul 時(shí),找不到 ul 節(jié)點(diǎn)元素,打印的是空。這個(gè)網(wǎng)上搜索也沒(méi)有什么準(zhǔn)確的答案,如果你知道這里面的原理,還請(qǐng)告訴我。

/

/ 表示從根節(jié)點(diǎn)選取一級(jí)一級(jí)篩選(不能跳)。

  1. print(page.xpath("/html")) 
  2.  
  3. // [<Element html at 0x27107f41100>] 
  4.  
  5. print(page.xpath("/body")) 
  6.  
  7. // [] 

可以看到,我選取根節(jié)點(diǎn) html ,可以打印出根節(jié)點(diǎn)元素,而我選取 body 打印時(shí),是找不到的,這個(gè)符號(hào)只能從根節(jié)點(diǎn)開(kāi)始找。

//

// 表示從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn),而不考慮它們的位置。注意:是所有符合條件的。

  1. print(page.xpath("//li")) 
  2.  
  3. // [<Element li at 0x1cd2a325780>, <Element li at 0x1cd2a325840>, <Element li at 0x1cd2a3259c0>, <Element li at 0x1cd2a325b00>, <Element li at 0x1cd2a325ac0>] 

.

. 表示選取當(dāng)前標(biāo)簽。

  1. ul = page.xpath("//ul"
  2. print(ul) 
  3. print(ul[0].xpath(".")) 
  4. print(ul[0].xpath("./li")) 
  5.  
  6. // [<Element ul at 0x1cd2a325840>] 
  7. // [<Element ul at 0x1cd2a325840>] 
  8. // [<Element li at 0x1cd2a325700>, <Element li at 0x1cd2a325b00>, <Element li at 0x1cd2a325640>, <Element li at 0x1cd2a325ac0>, <Element li at 0x1cd2a325c00>] 

我們先定位到 ul 元素節(jié)點(diǎn),這里的結(jié)果是一個(gè)列表,然后再打印當(dāng)前節(jié)點(diǎn)列表的第一個(gè) ul,接著我們打印這個(gè) ul 節(jié)點(diǎn)的子節(jié)點(diǎn) li。

..

.. 表示選取當(dāng)前標(biāo)簽的父節(jié)點(diǎn)。

  1. print(ul[0].xpath("..")) 
  2.  
  3. // [] 

這里打印第一個(gè) ul 節(jié)點(diǎn)的父元素,也就是 div 。

@

@ 表示獲取標(biāo)簽的屬性值。

  1. print(ul[0].xpath("@id")) 
  2.  
  3. // ['ultest'

我們打印第一個(gè) ul 節(jié)點(diǎn)的 id 屬性,可以看到結(jié)果是 ‘ultest’。

謂語(yǔ)

謂語(yǔ)用來(lái)查找某個(gè)或某些特定的節(jié)點(diǎn)或者包含某個(gè)指定值的節(jié)點(diǎn)。謂語(yǔ)被嵌在方括號(hào)中。

  1. //a[n] n為大于零的整數(shù),代表子元素排在第n個(gè)位置的<a>元素 
  2. //a[last()]   last()  代表子元素排在最后個(gè)位置的<a>元素 
  3. //a[last()-]  和上面同理,代表倒數(shù)第二個(gè) 
  4. //a[position()<3] 位置序號(hào)小于3,也就是前兩個(gè),這里我們可以看出xpath中的序列是從1開(kāi)始 
  5. //a[@href]    擁有href的<a>元素 
  6. //a[@href='www.baidu.com']    href屬性值為'www.baidu.com'的<a>元素 
  7. //book[@price>2]  price值大于2的<book>元素 

同樣的,我們來(lái)舉一些例子:

  1. # 第三個(gè)li標(biāo)簽 
  2. print(page.xpath('//ul/li[3]')) 
  3. # 最后一個(gè)li標(biāo)簽 
  4. print(page.xpath('//ul/li[last()]')) 
  5. # 倒數(shù)第二個(gè)li標(biāo)簽 
  6. print(page.xpath('//ul/li[last()-1]')) 
  7. # 序號(hào)小于3的li標(biāo)簽 
  8. print(page.xpath('//ul/li[position()<3]')) 
  9. # 有class屬性的li標(biāo)簽 
  10. print(page.xpath('//li[@class]')) 
  11. # class屬性為item-inactive的li標(biāo)簽 
  12. print(page.xpath("//li[@class='item-inactive']")) 

獲取文本

text()

我們用text()獲取某個(gè)節(jié)點(diǎn)下的文本:

  1. print(page.xpath('//ul/li/a/text()')) 
  2.  
  3. // ['first item''second item''third item''fourth item''fifth item'

string()

我們用string()獲取某個(gè)節(jié)點(diǎn)下所有的文本:

  1. print(page.xpath('string(//ul)')) 

輸出內(nèi)容為:

  1. first item 
  2. second item 
  3. third item 
  4. fourth item 
  5. fifth item # 注意,此處缺少一個(gè)  閉合標(biāo)簽 

fifth item # 注意,此處缺少一個(gè) 閉合標(biāo)簽

通配符

  • * 任意元素
  • @* 任意屬性

* 表示匹配任何元素節(jié)點(diǎn):

  1. print(page.xpath('//li/*')) 
  2.  
  3. // [<Element a at 0x208931f0f00>, <Element a at 0x208931f0f40>, <Element a at 0x208931f0c40>, <Element a at 0x208931f0d80>, <Element a at 0x208931ff080>] 

@* 表示匹配任何屬性節(jié)點(diǎn):

  1. print(page.xpath('//li/@*')) 
  2.  
  3. // ['item-0''item-1''item-inactive''item-1''item-0'

或運(yùn)算

通過(guò)在路徑表達(dá)式中使用"|"運(yùn)算符,可以實(shí)現(xiàn)選取若干個(gè)路徑。

  1. # 選取所有的li和a節(jié)點(diǎn) 
  2. print(page.xpath("//li|//a")) 
  3.  
  4. // [<Element li at 0x29bb7190ac0>, <Element a at 0x29bb7190b00>, <Element li at 0x29bb7190f00>, <Element a at 0x29bb7190dc0>, <Element li at 0x29bb7190fc0>, <Element a at 0x29bb7190e00>, <Element li at 0x29bb7190f80>, <Element a at 0x29bb71b1080>, <Element li at 0x29bb71b1040>, <Element a at 0x29bb7190cc0>] 

函數(shù)

xpath內(nèi)置很多函數(shù)。更多函數(shù)查看https://www.w3school.com.cn/xpath/xpath_functions.asp。

  • contains(string1,string2)
  • starts-with(string1,string2)
  • text()
  • last()
  • position()
  • node()

contains

有的時(shí)候,class作為選擇條件的時(shí)候不合適@class='....' 這個(gè)是完全匹配,當(dāng)網(wǎng)頁(yè)樣式發(fā)生變化時(shí),class或許會(huì)增加或減少像active的class。用contains就能很方便。

  1. print(page.xpath("//*[contains(@class, 'item-inactive')]")) 
  2.  
  3. // [] 

starts-with

  1. print(page.xpath("//*[starts-with(@class, 'item-inactive')]")) 
  2. // [<Element li at 0x1a297641d00>] 

其他幾個(gè)函數(shù),我們?cè)谏厦媸褂眠^(guò)。注意,并不是所有的 xpath 函數(shù)python都會(huì)支持,比如 ends-with(string1,string2) 和 upper-case(string) 就不支持。

節(jié)點(diǎn)軸選擇

ancestor軸

調(diào)用 ancestor 軸,獲取所有祖先節(jié)點(diǎn)。其后需要跟兩個(gè)冒號(hào),然后是節(jié)點(diǎn)的選擇器。返回結(jié)果:第一個(gè)li節(jié)點(diǎn)的所有祖先節(jié)點(diǎn)。

  1. print(page.xpath('//li[1]/ancestor::*')) 
  2.  
  3. // [, , , ] 

attribute軸

調(diào)用 attribute 軸,獲取所有屬性值。返回結(jié)果:li節(jié)點(diǎn)的所有屬性值。

  1. print(page.xpath('//li[1]/attribute::*')) 
  2.  
  3. // ['item-0'

child軸

調(diào)用 child 軸,獲取所有直接子節(jié)點(diǎn)。返回結(jié)果:選取 href 屬性為 link1.html 的 a 子節(jié)點(diǎn)。

  1. print(page.xpath('//li[1]/child::a[@href="link1.html"]')) 
  2.  
  3. // [<Element a at 0x13972af5b40>] 

descendant軸

調(diào)用 descendant 軸,獲取所有子孫節(jié)點(diǎn)。同時(shí)加了限定條件。返回結(jié)果:選取 li 節(jié)點(diǎn)下的子孫節(jié)點(diǎn)里的 span 節(jié)點(diǎn)。

  1. print(page.xpath('//li[4]/descendant::span')) 
  2.  
  3. // [<Element span at 0x1a4d5700d00>] 

following軸

調(diào)用 following 軸,獲取當(dāng)前節(jié)點(diǎn)之后的所有節(jié)點(diǎn)。

  1. print(page.xpath('//li[4]/following::*[2]')) 
  2.  
  3. // [<Element a at 0x1583f8c0d00>] 

following-sibling軸

調(diào)用 following-sibling 軸,獲取當(dāng)前節(jié)點(diǎn)之后的所有同級(jí)節(jié)點(diǎn)。

  1. print(page.xpath('//li[4]/following-sibling::*')) 
  2.  
  3. // [] 

總結(jié)

到這里,我們的 xpath 學(xué)習(xí)之路就結(jié)束了,文章中基本涵蓋了大家需要用的的 xpath 解析方法。大家看一遍沒(méi)記住不要緊,以后遇到此類(lèi)解析直接搬出這篇文章對(duì)照著寫(xiě)就行。

 

責(zé)任編輯:武曉燕 來(lái)源: Python技術(shù)
相關(guān)推薦

2014-08-04 13:56:42

安卓概念

2022-01-12 10:57:59

網(wǎng)絡(luò)

2021-11-23 23:13:11

數(shù)據(jù)庫(kù)安全工具

2021-04-30 05:45:41

多線程Java基礎(chǔ)面試題

2020-11-16 09:02:38

Python開(kāi)發(fā)工具

2020-01-07 14:24:18

人工智能機(jī)器學(xué)習(xí)技術(shù)

2021-01-04 14:59:50

AIAI技術(shù)機(jī)器學(xué)習(xí)

2020-11-24 10:13:02

Redis集群數(shù)據(jù)庫(kù)

2020-01-30 10:30:32

AI 數(shù)據(jù)人工智能

2021-05-14 14:01:31

加密貨幣網(wǎng)絡(luò)安全加密錢(qián)包

2024-01-29 09:04:15

Wi-Fi數(shù)據(jù)設(shè)備

2025-04-07 08:20:00

ORMPython代碼

2011-09-30 09:29:19

TechCruch創(chuàng)業(yè)2010年

2024-09-19 09:12:50

RAG系統(tǒng)技術(shù)

2020-06-30 08:27:56

Python開(kāi)發(fā)工具

2024-03-28 10:08:31

自動(dòng)駕駛工具

2021-04-04 22:58:20

互聯(lián)網(wǎng)IP網(wǎng)絡(luò)協(xié)議

2024-08-05 13:00:00

2022-08-31 09:39:32

自動(dòng)駕駛芯片技術(shù)

2023-02-24 09:55:17

自動(dòng)駕駛神經(jīng)網(wǎng)絡(luò)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)