Xpath 詳解

什么是 Xpath?

Xpath 是一種用在 XML 文檔中定位元素的語言,同樣也支持 HTML 元素的解析。

所謂 Xpath,是指 XML path language。path 就是路徑,那么 Xpath 主要是通過路徑來查找元素。

我們通過下面一張小圖來了解一下 HTML 中的結構:

HTML 的結構就是樹形結構,HTML 是根節(jié)點,所有的其他元素節(jié)點都是從根節(jié)點發(fā)出的。其他的元素都是這棵樹上的節(jié)點Node,每個節(jié)點還可能有屬性和文本。
而路徑就是指某個節(jié)點到另一個節(jié)點的路線。

節(jié)點之間存在各種關系:

  • 父節(jié)點(Parent): HTML 是 body 和 head 節(jié)點的父節(jié)點;
  • 子節(jié)點(Child):head 和 body 是 HTML 的子節(jié)點;
  • 兄弟節(jié)點(Sibling):擁有相同的父節(jié)點,head 和 body 就是兄弟節(jié)點。title 和 div 不是兄弟,因為他們不是同一個父節(jié)點。
  • 祖先節(jié)點(Ancestor):body 是 form 的祖先節(jié)點,爺爺輩及以上??;
  • 后代節(jié)點(Descendant):form 是 HTML 的后代節(jié)點,孫子輩及以下??。

Xpath 中的絕對路徑從 HTML 根節(jié)點開始算,相對路徑從任意節(jié)點開始。

通過開發(fā)者工具,我們可以拷貝到 Xpath 的絕對路徑和相對路徑代碼:

但是由于拷貝出來的代碼缺乏靈活性,也不全然準確。大部分情況下,都需要自己定義 Xpath 語句,因此 Xpath 語法還是有必要學習。

絕對路徑:

Xpath 中最直觀的定位策略就是絕對路徑。

以百度中的輸入框和按鈕為例,通過拷貝出來的 full Xpath:

/html/body/div[2]/div/div/div/div/form/span/input

這就是一個絕對路徑我們可以看出,絕對路徑是從根節(jié)點/html開始往下,一層層的表示出來直到需要的節(jié)點為止。

這明顯不是理智的選項,因此了解以下即可,不用往心里去。

相對路徑

除了絕對路徑,Xpath 中更常用的方式是相對路徑定位方法,以“//”開頭。

相對路徑可以從任意節(jié)點開始,一般我們會選取一個可以唯一定位到的元素開始寫,可以增加查找的準確性。

相對路徑可以通過以下的方式來定位元素:

基本定位語法

定位語法主要依賴于以下特殊符號:

表達式 說明 舉例
/ 從根節(jié)點開始選取 /html/div/span
// 從任意節(jié)點開始選取 //input
. 選取當前節(jié)點
.. 選取當前節(jié)點的父節(jié)點 //input/.. 會選取 input 的父節(jié)點
@ 選取屬性,或者根據屬性選取 //input[@data] 選取具備 data 屬性的 input 元素
//@data 選取所有 data 屬性
* 通配符,表示任意節(jié)點或任意屬性

元素屬性定位

屬性定位是通過 @ 符號指定需要使用的屬性。

  1. 根據元素是否具備某個屬性查找元素
//*[@data-recordid]

選取包含data-recordid屬性的所有節(jié)點??梢远ㄎ坏揭韵略兀?/p>

<tr role="row" data-boundview="gridview-1029" data-recordid="B36BCA33" ></tr>
  1. 根據屬性是否等于某值查找元素
//span[@role='img']

選取屬性 role 的屬性值為 img 的所有節(jié)點??梢远ㄎ坏揭韵略兀?/p>

<span role="img" class="x-btn-icon-el" unselectable="on" style=""></span>

注意,屬性值必須要加引號,單雙引號都可以。

層級屬性結合定位

遇到某些元素無法精確定位的時候,可以查找其父級及其祖先節(jié)點,找到有確定的祖先節(jié)點后通過層級依次向下定位。

以下面的結構為例:


<form action="search" id="form" method="post">
    <span class="bg">
        <span class="soutu">搜索</span>
    </span>
    <span class="soutu">
        <input type="text" name="key" id="su">
    </span>
</form>
  1. 根據層級向下找,從 form 找到綠色的 span:
//form[@id="form"]/span/span
  1. 查找某元素內部的所有元素,選取 form 元素內部的所有 span:
//form[@id="form"]//span

第二個雙斜杠,表示選取內部所有的 span,不管層級關系

  1. 使用星號找不特定的元素
//*[@id="form"]//*[@type="text"]

選取 id 屬性為 form 的任意屬性內部,并且 type 屬性為 text 的任意元素。這里會找到 input。

  1. 使用..從下往上找,根據 input 查找其父節(jié)點 span:
//input[@name="key"]/..

注意最后的兩個點,找到 input 節(jié)點的上級節(jié)點,如果還要再往上再加 /..

  1. 找同級節(jié)點:
    比如我們想通過第一個 span 標簽去 找 div 標簽。樹形結構中,兄弟節(jié)點之間的關系是通過父節(jié)點建立起來的。所以可以先找到父節(jié)點,再通過父節(jié)點找同級節(jié)點。
//span[@class="bg"]/../div

先通過/..找到 span 的父節(jié)點,再通過父節(jié)點找到 div。

使用謂語定位

謂語是 Xpath 中用于描述元素位置。主要有數字下標、最后一個子元素last()、元素下標函數position()。

  1. 使用下標的方式,從 form 找到 input :
//form[@id="form"]/span[2]/input

Xpath 中的下標從 1 開始。

  1. 查找最后一個子元素,選取 form 下的最后一個 span:
//form[@id="form"]/span[last()]
  1. 查找倒數第幾個子元素,選取 form 下的倒數第一個 span:
//form[@id="form"]/span[last()-1]
  1. 使用 position() 函數,選取 from 下第二個 span:
//form[@id="form"]/span[position()=2]
  1. 使用 position() 函數,選取下標大于 2 的 span:
//form[@id="form"]/span[position()>2]

使用邏輯運算符

如果元素的某個屬性無法精確定位到這個元素,我們還可以用邏輯運算符 and 連接多個屬性進行定位,以百度輸入框為例。

  1. 使用 and
//*[@name='wd' and @class='s_ipt']

查找 name 屬性為 wd 并且 class 屬性為 s_ipt 的任意元素

  1. 使用 or
//*[@name='wd' or @class='s_ipt']

查找 name 屬性為 wd 或者 class 屬性為 s_ipt 的任意元素,取其中之一滿足即可。

  1. 使用|,同時查找多個路徑,取
//form[@id="form"]//span | //form[@id="form"]//input

選取 form 下所有的 span 和所有的 input。

使用文本定位

使用文本定位,是 Xpath 中的一大特色。在自動化測試中,為了讓代碼的可讀性更高,可以使用文本的方式。

以下一個案例:

部分網頁結構如下:

<tr>
  <td valign="top">
    <input type="radio" name="payment" value="1" checked="" iscod="0">
  </td>
  <td valign="top">
    <strong>支付寶</strong>
  </td>
</tr>

其實我們需要點的是前的單選框,但是單選框沒有任何特殊的標識,不夠靈活。我們可以通過后面的名稱,如(支付寶、余額支付等)來找到其對應行的 radio,再去點擊。

我們就需要先通過文本定位到“支付寶”,再去找其同一行(tr)的 input 節(jié)點。如果理不清楚,我們可以先畫一個結構圖:

紅色箭頭表示查找路徑,先定位到“支付寶”所在的 strong,再定位 td -> tr -> td - >input 。那么要定位“支付寶”文本,就需要用到 Xpath 中的函數 text()string(),注意是函數,所以括號不能少。

text():當前元素節(jié)點包含的文本內容;
表達式//div[text()="文本"],能找到:

<div>文本</div>

不能找到:

<div><span>文本</span></div>

string():當前元素節(jié)點內部所有節(jié)點元素的文本內容。表達式//div[string()="文本"]上述兩種情況都能找到。

好,接著寫上面的內容。先通過 //strong[text()="支付寶"]定位到“支付寶”所在的元素 strong,再找上級 td -> tr,再向下找:

//strong[text()="支付寶"]/../../td[1]/input

也可以寫為:

//td[string()="支付寶"]/../td[1]/input

使用部分匹配函數

Xpath 中有提供了幾個函數,用來進行部分匹配。

函數 說明 舉例
contains 選取屬性或者文本包含某些字符 //div[contains(@id, 'data')] 選取 id 屬性包含 data 的 div 元素
//div[contains(string(), '支付寶')] 選取內部文本包含“支付寶”的 div 元素
starts-with 選取屬性或者文本以某些字符開頭 //div[starts-with(@id, 'data')] 選取 id 屬性以 data 開頭的 div 元素
//div[starts-with(string(), '銀聯(lián)')] 選取內部文本以“銀聯(lián)”開頭的 div 元素
ends-with 選取屬性或者文本以某些字符開頭 //div[ends-with(@id, 'require')] 選取 id 屬性以 require 結尾的 div 元素
//div[ends-with(string(), '支付')] 選取內部文本以“支付”結尾的 div 元素

驗證 Xpath

驗證 xpath 有兩種方法:

  1. 在開發(fā)者工具的 Elements 中按Ctrl + F,在搜索框中輸入 Xpath:
  1. 在開發(fā)者工具的 Console 中使用 $x()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容