1.簡介

按巨集哥計劃,本文繼續介紹WebDriver關於元素定位大法,這篇介紹定位倒數二個方法:By xpath。xpath 的定位方法, 非常強大。  使用這種方法幾乎可以定位到頁面上的任意元素。

2.什麼是xpath?

xpath 是XML Path的簡稱, 由於HTML文件本身就是一個標準的XML頁面,所以我們可以使用Xpath 的用法來定位頁面元素。

XPath 是XML 和Path的縮寫,主要用於xml文件中選擇文件中節點。基於XML樹狀文件結構,XPath語言可以用在整棵樹中尋找指定的節點。XPath 定位和CSS定位相比有更大的靈活性。XPath 在文件樹中某個節點既可以向前搜尋,也可以向後搜尋,CSS定位只能在文件樹中向前搜尋,但XPath的定位速度比CSS 慢一些。

3.xpath定位的缺點

xpath 這種定位方式, webdriver會將整個頁面的所有元素進行掃描以定位我們所需要的元素, 這是個非常費時的操作, 如果指令碼中大量使用xpath做元素定位的話, 指令碼的執行速度可能會稍慢。

4.常用定位方法(8種)

(1)id
(2)name
(3)class name
(4)tag name
(5)link text
(6)partial link text
(7)xpath(今天講解)
(8)css selector

5.自動測試實戰

以百度首頁為例,將xpath的各種定位方法一一講解和分享一下。

5.1大致步驟

1.訪問度娘首頁。

2.通過xpath定位到元素,點選一下。

5.2模糊定位starts-with關鍵字

有一種特殊的情況:頁面元素的屬性值會被動態地生成,即每次看到的頁面元素屬性值是不一樣的,這種頁面元素會加大定位的難度,使用模糊屬性值定位方法可以部分解決問題。

XPath常用的函式如下:

Starts-with()
定位表示式的例項://img[starts-with(@alt,'div1')]

這個例項表示查詢圖片alt屬性開始位置包含‘div1’關鍵字的頁面元素。

start-with定位,以‘//’開頭,具體格式為

xxx.By.xpath("//標籤[starts-with(@屬性,'內容')]")

具體例子:

//input[starts-with(@name,'name1')]     查詢name屬性中開始位置包含'name1'關鍵字的頁面元素

具體步驟:

在被測試百度網頁中, 按照巨集哥在上卷中5.2中的方法 (1)查詢輸入框並輸入“北京巨集哥”,(2)查詢“百度一下”按鈕,(3)點選“百度一下”按鈕。

XPath表示式:

(1)//input[starts-with(@name,'wd')]

(2)//input[starts-with(@value,'百度一下')]

java定位語句:

(1)WebElement searchBox = driver.findElement(By.xpath( "//input[starts-with(@name,'wd')]" ));

(2)WebElement SearchButton = driver.findElement(By.xpath("//input[starts-with(@value,'百度一下')]"));
5.2.1程式碼設計

5.2.2參考程式碼
package lessons;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver; /**
* @author 北京-巨集哥
*
* 《手把手教你》系列技巧篇(十四)-java+ selenium自動化測試-元素定位大法之By xpath下篇(詳細教程)
*
* 2021年8月5日
*/
public class ByXpath { public static void main(String [] args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驅動路徑 WebDriver driver = new ChromeDriver ();
//最大化視窗
driver.manage().window().maximize();
driver.get("http://wwww.baidu.com"); //By xpath 定位
WebElement SearchBox = driver.findElement(By.xpath( "//input[starts-with(@name,'wd')]" )); SearchBox.sendKeys("北京巨集哥"); WebElement SearchButton = driver.findElement(By.xpath("//input[starts-with(@value,'百度一下')]")); SearchButton .click(); //定位到文字,將文字高亮顯示
//建立一個JavascriptExecutor物件
JavascriptExecutor js =(JavascriptExecutor)driver; //新聞文字高亮顯示顏色
js.executeScript ( "arguments[0].setAttribute('style', arguments[1]);",SearchBox,"background: orange; border: 2px solid red;"); Thread.sleep (5000); driver.quit();
} }
5.2.3執行程式碼

1.執行程式碼,右鍵Run AS->java Application,控制檯輸出,如下圖所示:

2.執行程式碼後電腦端的瀏覽器的動作,如下小視訊所示:

5.3模糊定位contains關鍵字

Contains()
定位表示式的例項://img[contains(@alt,'g1')]

這個例項表示查詢圖片alt屬性包含‘g1’關鍵字的頁面元素。Contains()函式屬於XPath函式的高階用法,使用的場景比較多,頁面元素的屬性值只要具有固定不變的幾個關鍵字,就可以在元素屬性經常發生一定程度的變化的時候,依然可以使用Contains函式進行定位。

索引號定位,以‘//’開頭,具體格式為:

xxx.By.xpath("//標籤[contains(@屬性,'內容')]")

具體例子:

//input[contains(@name,'na')]         查詢name屬性中包含na關鍵字的頁面元素

具體步驟:

在被測試百度網頁中, 按照巨集哥在上卷中5.2中的方法 (1)查詢輸入框並輸入“北京巨集哥”,(2)查詢“百度一下”按鈕,(3)點選“百度一下”按鈕。

XPath表示式:

(1)//input[contains(@name,'wd')]

(2)//input[contains(@value,'百度一下')]

java定位語句:

(1)WebElement searchBox = driver.findElement(By.xpath( "//input[contains(@name,'wd')]" ));

(2)WebElement SearchButton = driver.findElement(By.xpath("//input[contains(@value,'百度一下')]"));
5.3.1程式碼設計

5.3.2參考程式碼
package lessons;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver; /**
* @author 北京-巨集哥
*
* 《手把手教你》系列技巧篇(十四)-java+ selenium自動化測試-元素定位大法之By xpath下篇(詳細教程)
*
* 2021年8月5日
*/
public class ByXpath { public static void main(String [] args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驅動路徑 WebDriver driver = new ChromeDriver ();
//最大化視窗
driver.manage().window().maximize();
driver.get("http://wwww.baidu.com"); //By xpath 定位
WebElement SearchBox = driver.findElement(By.xpath( "//input[contains(@name,'wd')]" )); SearchBox.sendKeys("北京巨集哥"); WebElement SearchButton = driver.findElement(By.xpath("//input[contains(@value,'百度一下')]")); SearchButton .click(); //定位到文字,將文字高亮顯示
//建立一個JavascriptExecutor物件
JavascriptExecutor js =(JavascriptExecutor)driver; //新聞文字高亮顯示顏色
js.executeScript ( "arguments[0].setAttribute('style', arguments[1]);",SearchBox,"background: orange; border: 2px solid red;"); Thread.sleep (5000); driver.quit();
} }
5.3.3執行程式碼

1.執行程式碼,右鍵Run AS->java Application,控制檯輸出,如下圖所示:

2.執行程式碼後電腦端的瀏覽器的動作,如下小視訊所示:

5.4text() 函式 文字定位

使用text()函式可以定位到包含某些關鍵字的頁面元素。

文字內容的定位是利用 html 的 text 欄位進行定位的方法,可以看做是屬性值定位的衍生
//button[text()='下一步']
由於 “下一步” 這幾個字是瀏覽器介面就可以看到的,我們稱為 “所見即所得”,這種特徵改的可能性非常小,所以非常未定,優先推薦使用。
與屬性值類似,文字內容也支援 starts-with 和 contains 模糊匹配。

text()函式文字定位,以‘//’開頭,具體格式為:

xxx.By.xpath("//標籤[text()='文字']")

或者

xxx.By.xpath("//標籤[contains(text(),'文字')]")

具體例子:

查詢所有文字為"百度搜索" 的元素
driver.findElement(By.xpath("//*[text()='百度搜索']"));
查詢所有文字為“搜尋” 的超連結 
driver.findElement(By.xpath("//a[contains(text(),'搜尋')]"));

具體步驟:

在被測試百度網頁中, 按照巨集哥在上卷中5.2中的方法 (1)查詢“百度熱搜”,(2)點選“百度熱搜”按鈕。

XPath表示式:

(1)//a/div[text()='百度熱搜']
   //或者
(2)//a/div[contains(text(),'百度熱搜')]

java定位語句:

(1)WebElement searchBox = driver.findElement(By.xpath( "//a/div[text()='百度熱搜']" )); 
  //或者
(2)WebElement SearchButton = driver.findElement(By.xpath("//a/div[contains(text(),'百度熱搜')]"));

第一個表示式是查詢包含“百度搜索”的連結頁面元素,要精確匹配。第二個表示式則是搜尋包含“百度”兩個字的連結頁面元素,實現了根據關鍵字內容匹配。

使用文字匹配模式進行定位,為定位複雜的頁面元素提供過一種強大的定位模式,遇到定位問題的時候,可以優先考慮使用這個方法。

5.4.1程式碼設計

5.4.2參考程式碼
package lessons;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver; /**
* @author 北京-巨集哥
*
* 《手把手教你》系列技巧篇(十四)-java+ selenium自動化測試-元素定位大法之By xpath下篇(詳細教程)
*
* 2021年8月5日
*/
public class ByXpath { public static void main(String [] args) throws InterruptedException { System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驅動路徑 WebDriver driver = new ChromeDriver ();
//最大化視窗
driver.manage().window().maximize();
driver.get("http://wwww.baidu.com"); //By xpath 定位
WebElement HotButton = driver.findElement(By.xpath("//a/div[text()='百度熱搜']")); HotButton.click(); //定位到文字,將文字高亮顯示
//建立一個JavascriptExecutor物件
JavascriptExecutor js =(JavascriptExecutor)driver; //新聞文字高亮顯示顏色
js.executeScript ( "arguments[0].setAttribute('style', arguments[1]);",HotButton,"background: orange; border: 2px solid red;"); Thread.sleep (5000); driver.quit();
} }
5.4.3執行程式碼

1.執行程式碼,右鍵Run AS->java Application,控制檯輸出,如下圖所示:

2.執行程式碼後電腦端的瀏覽器的動作,如下小視訊所示:

6.小結

Xpath的功能非常強大,不僅能夠完成介面定位的任務,而且能保證穩定性,實際自動化測試中,能夠識別介面元素是重要的,更重要的是要保證版本間的穩定性,減少指令碼的維護工作。
如下規則請參考:
(1)特徵越少越好
(2)特徵越是介面可見的越好
(3)不能使用絕對路徑
(4)避免使用索引號
(5)擅用 console 除錯(後邊巨集哥會簡單講解一下)
(6)相對路徑,屬性值,文字內容,Axis 可以任意組合,當然屬性值和文字內容的模糊匹配也支援和上述方式任意組合,Axis 可以巢狀使用。
通過 Xpath 的各種方式組合,能夠解決 selenium 自動化測試中介面定位的全部問題,可以說:有了 Xpath,再也不用擔心元素定位了。

好了,今天到這裡關於xpath定位的常見方法基本上都介紹和分享講解過了。下一篇巨集哥講解最後一種元素定位方法。

7.拓展

7.1. 函式

1.count:統計

'count(//li[@data])' #節點統計

2.concat:字串連線

'concat(//li[@data="one"]/text(),//li[@data="three"]/text())'

3.local-name:解析節點名稱

'local-name(//*[@id="testid"])' #local-name解析節點名稱,標籤名稱

4.contains(string1,string2):如果 string1 包含 string2,則返回 true,否則返回 false

'//h3[contains(text(),"H3")]/a/text()')[0] #使用字元內容來輔助定位

5.not:布林值(否)

'count(//li[not(@data)])' #不包含data屬性的li標籤統計

6.string-length:返回指定字串的長度

#string-length函式+local-name函式定位節點名長度小於2的元素
'//*[string-length(local-name())<2]/text()')[0]

7.組合拳2

#contains函式+local-name函式定位節點名包含di的元素
'//div[@id="testid"]/following::div[contains(local-name(),"di")]'

8.or:多條件匹配

'//li[@data="one" or @code="84"]/text()' #or匹配多個條件

#也可使用|
'//li[@data="one"]/text() | //li[@code="84"]/text()' #|匹配多個條件

9.組合拳3:floor + div除法 + ceiling

#position定位+last+div除法,選取中間兩個
'//div[@id="go"]/ul/li[position()=floor(last() div 2+0.5) or position()=ceiling(last() div 2+0.5)]/text()'

10.組合拳4隔行定位:position+mod取餘

#position+取餘運算隔行定位
'//div[@id="go"]/ul/li[position()=((position() mod 2)=0)]/text()')

7. 2數值比較

1.<:小於 、 >:大於

#所有li的code屬性小於200的節點
'//li[@code<200]/text()'

2.div:對某兩個節點的屬性值做除法

'//div[@id="testid"]/ul/li[3]/@code div //div[@id="testid"]/ul/li[1]/@code'

3.組合拳4:根據節點下的某一節點數量定位

#選取所有ul下li節點數大於5的ul節點
'//ul[count(li)>5]/li/text()'