Selenium:xPath 定位實踐

fiskeryang發表於2020-08-22

使用過selenium的朋友相信都瞭解selenium給使用者提供了幾種不同的元素定位方式。
今天在這裡我們不討論幾種定位方式的優劣,只針對性的討論xpath的使用方法與一些技巧。本人一直是堅定的xpath黨,定位方式非常靈活,而且運用熟練了之後,還可以對UI自動化的PO模式進行擴充套件。

絕對路徑vs相對路徑
相對其他定位方式來說,xpath的使用有一定的門檻,剛開始接觸時可能只會通過瀏覽器的定位元素功能直接複製xpath絕對路徑,比如這樣的

/*[@id="root"]/section/div[1]/div/div/div/form/section[1]/div[2]/ul/li[1]/button

這樣的絕對路徑xpath至少存在兩個方面的問題
1、可讀性和可維護性很差,這一長串路徑看得人眼睛都花,別說維護了。
2、健壯性差,現在的前端框架很多元素都是根據實際業務動態生成的,而頁面元素結構稍微變化,繼續使用絕對路徑就可能會定位不到元素了。
所以說,想要使用xpath進行定位,使用絕對路徑是肯定不行的。而是用相對路徑就要求我們必須對xpath有一定的瞭解,xpath的幾個關鍵知識離不開以下兩個方面
1、xpath提供的各種函式
2、xpath軸
我們再來分析一下上面這個button元素
首先它是在一個id為root的div容器裡中一個form表單的子元素
button的子元素是一個innerText為 【查 詢】的span
我們可以把上面的xpath改造一下

//div[@id='root']//span[text()='查 詢']/..

然後按F12開啟Chrome瀏覽器的控制檯,切換到elements標籤,按Ctrl+F啟用查詢對話方塊,將xpath輸入到搜尋框中,可以看到瀏覽器定位到了這個button元素
這樣我們就通過xpath的相對定位定位到了這個button元素,並且忽略掉了DOM樹中大部分中間層級

可以看到通過使用xpath的相對路徑和過濾功能使xpath表示式簡潔了很多,並且因為忽略了中間層級,對DOM樹結構的穩定性依賴降低了很多。

Xpath使用介紹
由於XML/HTML文件都是樹形結構,文件中的每一個元素物件都是樹形結構中的一個節點,xpath就是幫助我們來對樹形結構中的節點進行精確定位的語言
那麼,我們在做UI自動化時需要掌握哪些與xpath定位相關的知識點呢?

1、路徑表示式
【.】 表示當前節點,xpath以 . 開頭的話 即表示這是根節點
【..】 表示當前節點的父節點
【/】 表示選取當前節點的下一級節點
【//】 表示選取當前節點的所有下級節點
【@】 表示選取節點屬性
【text()】表示選取節點文字
2、謂語
謂語被括在方括號中,可以視為查詢元素的過濾條件,常見的有
使用節點屬性過濾 如 .//div[@title='xpath定位']
使用節點索引過濾 如 .//div[1] 索引下標從1開始
使用節點文字過濾 如 .// div[text()='xpath定位']
3、運算子
[+] 加 [-] 減 [] 乘 [div] 除
[=] 等於 [!=]不等於 [<]小於 [ >] 大於
[and] 與 [or] 或
[|] 多節點選取
**4、函式
*
xpath支援的函式非常多,我們在這裡只討論UI自動化測試中常用到的函式,
另外由於主流瀏覽器現在都不支援xpath2.0,所以我們的討論範圍僅限於xpath1.0

contains(str1,str2) 如果 str1 包含 str2,則返回 true,否則返回 false
substring(str,start,len) 返回從 start 位置開始的指定長度的子字串。第一個字元的下標是 1
string-length(str) 返回指定字串str的長度
normalize-space(str) 刪除指定字串的開頭和結尾的空白,並把內部的所有空白序列替換為一個,然後返回結果
starts-with(str1,str2) 如果 str1 以 str2 開始,則返回 true,否則返回 false
ends-with(str1,str2) 如果 str1 以 str2 結尾,則返回 true,否則返回 false
not(arg) 返回引數arg的相反的布林值
5、軸(列舉幾個常用的)
ancestor 選取當前節點的所有先輩(父、祖父等)。
preceding-sibling 選取當前節點之前的所有同級節點。
following-sibling 選取當前節點之後的所有同級節點。
軸使用語法為 : 軸名稱::元素xpath,
比如 .//div[@id='1']//following-sibling::input[@name]
表示選取 id為1的div元素之後同級的所有帶有name屬性的input元素

例項 : 用Chrome開啟獵聘的首頁 https://www.liepin.com
首先 ,嘗試定位首頁的搜尋輸入框元素

按F12開啟Chrome開發工具,檢視該元素屬性

切換到Console,輸入$x(".//input[contains(@placeholder,'輸入職位關鍵詞')]")

可以看到 定位到了兩個input元素,把滑鼠移動到第一個input元素上,搜尋欄元素啟用,第二個是一個相同的input的元素但是當前是隱藏狀態
然後,我們吧xpath改一下,指定取第一個匹配到的元素,這樣就可以精確匹配到這個搜尋輸入框了

如果不希望使用寫死索引的方式定位,我們可以再分析下這兩個input有什麼區別

上面分別是兩個input及其容器元素的結構,可以看到第二個input的容器div元素多了個style屬性,data-selector也不同,那麼我們可以再改造一下xpath
.//div[@data-selector='search-box' and not(contains(@style,'none'))]//input[contains(@placeholder,'輸入職位關鍵詞')]

這樣 ,我們就定位到了搜尋輸入框元素 ,這裡的xpath定位我們使用到了 contains函式、@屬性定位、索引定位、and 與操作 、not函式

接下來再看看下搜尋欄下面的行業分類索引連結

假如我們希望能夠通過分頁文字內容【IT·網際網路】來定位到這個a元素
xpath : .//p[@data-selector='subsite-btn']//b[text()='IT·網際網路']/..

這裡,我們使用了【..】來選取父元素,直接使用【..】來定位父元素比較簡單,但是不能加任何過濾條件,
如果還想要對父元素或更上層的元素進行過濾選擇的話需要用xpath軸ancestor

我們可以看到,xpath的相對定位是非常靈活並且健壯性較強的一種定位方式,在實際工作中也是使用的非常多的,非常推薦大家使用。

相關文章