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使用索引號定位
索引號定位,以‘//’開頭,具體格式為
xxx.By.xpath("//標籤[x]")
具體例子:
//form/div[1]:表示 form 下的第一個 div //form/div[last()]:表示 form 下的最後一個 div //form/div[last()-1]:表示 form 下的倒數第二個 div
具體步驟:
在被測試百度網頁中,按照巨集哥在上卷中5.2中的方法 (1)查詢輸入框並輸入“北京巨集哥”,如下圖所示:(2)查詢“百度一下”按鈕,如下圖所示:(3)點選“百度一下”按鈕。
XPath表示式:
(1)//form/span/input[1]
(2)//form/span[2]/input[1]
java定位語句:
(1)WebElement SearchBox = driver.findElement(By.xpath( "//form/span/input[1]" ));
(2)WebElement SearchButton = driver.findElement(By.xpath("//form/span[2]/input[1]"));
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月4日 */ 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( "//form/span/input[1]" )); SearchBox.sendKeys("北京巨集哥"); WebElement SearchButton = driver.findElement(By.xpath("//form/span[2]/input[1]")); 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.執行程式碼後電腦端的瀏覽器的動作,如下小視訊所示:
根據元素型別在頁面中出現的先後順序,可以使用序號來查詢指定的頁面元素。本例項的XPath表示式表示查詢頁面中第二個出現的span中的input元素,即被測試頁面上的按鈕元素。 如果使用span/input[1],會發現固定位出輸入框和按鈕元素,這是因為頁面中含有兩個span節點,每個span節點都包含input元素,XPath在查詢的時候,把每個span節點都當作相同的其實層級開始查詢,所以input[1]能查出兩個元素。
因此在使用序號進行頁面定位元素的時候,需要注意網頁HTML程式碼中是否包含多個層級完全相同的程式碼結構。如果使用XPath表示式同時定位多個頁面元素,將定位到多個元素儲存到List物件中。
在實際使用中,如果元素經常有新增或減少的情況,不建議使用索引號定位的方式,因為頁面的變化會導致使用索引號的XPath表示式定位失敗。
5.3使用頁面屬性定位
標籤屬性定位,相對比較簡單,也要求屬效能夠定位到唯一一個元素,如果存在多個相同條件的標籤,預設只是第一個,具體格式:
xxx.By.xpath("//標籤[@屬性='屬性值']")
屬性判斷條件:最常見為id,name,class等等,目前屬性的類別沒有特殊限制,只要能夠唯一標識一個元素都是可以的
具體例子:
xxx.By.xpath("//a[@href='/industryMall/hall/industryIndex.html']")
xxx.By.xpath("//input[@value='確定']")
xxx.By.xpath("//div[@class = 'submit']/input")
(1)當某個屬性不足以唯一區別某一個元素時,也可以採取多個條件組合的方式,具體例子
xxx..By.xpath("//input[@type='name' and @name='kw1']")
(2)當標籤屬性很少,不足以唯一區別元素時,但是標籤中間中間存在唯一的文字值,也可以定位,其具體格式
xxx.By.xpath("//標籤[contains(text(),'文字值')]")
具體例子:
xxx.By.xpath("//iunpt[contains(text(),'型號:')]")
注意:儘量在html中複製此段文字,避免因為肉眼無法分辨的字元導致定位失敗
(3) 其他的屬性值如果太長,也可以採取模糊方法定位,直接上示例
xxx.By.xpath(“//a[contains(@href, ‘logout')]”)
(4)XPath 關於網頁中的動態屬性的定位,例如,ASP.NET應用程式中動態生成id屬性值,可以有以下四種方法:
- starts-with例子: //input[starts-with(@id,'ctrl')] 解析:匹配以ctrl開始的屬性值 - ends-with 例子://input[ends-with(@id,'userName')] 解析:匹配以userName結尾的屬性值 - contains() 例子://input[contains(@id,'userName')] 解析:匹配含有userName屬性值
當然,如果上面的單一方法不能完成定位,也可以採取組合式定位 類似
("//input[@id='kw1']//input[start-with(@id,'nice']/div[1]/form[3])
(5) .//和//的區別
//是指從全文上下文中搜尋//後面的節點,而.//則是指從前面的節點的子節點中進行查詢
(6) 選取若干路徑|
這個符號用於在一個xpath中寫多個表示式用,用|分開,每個表示式互不干擾,意思是一個xpath可以匹配多個不同條件的元素,例如:如下圖所示,xpath可以匹配到滿足條件的i標籤元素和滿足條件的span標籤元素。
//i[@class='c-icon'] | //span[@class='hot-refresh-text']
具體步驟:
在被測試百度網頁中,按照巨集哥在上卷中5.2中的方法 (1)查詢輸入框並輸入“北京巨集哥”,(2)查詢“百度一下”按鈕,(3)點選“百度一下”按鈕。因為上卷中的相對路徑巨集哥已經用了id,在這裡巨集哥就是用一下其他的屬性。
XPath表示式:
(1)//input[@name='wd'] (2)//input[@value='百度一下']
java定位語句:
(1)WebElement searchBox = driver.findElement(By.xpath( "//input[@name='wd']" ));
(2)WebElement SearchButton = driver.findElement(By.xpath("//input[@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月4日 */ 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[@name='wd']" )); SearchBox.sendKeys("北京巨集哥"); WebElement SearchButton = driver.findElement(By.xpath("//input[@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.執行程式碼後電腦端的瀏覽器的動作,如下小視訊所示:
在定位頁面元素的時候,會遇到各種結構複雜的網頁,並且經常出現無法使用ID,name等方式進行定位。有不想使用感覺對路徑的定位方式,也沒法搞清使用什麼序號來定位元素,那麼則推薦使用屬性值定位元素的方法。
被測試網頁的元素一般都包含各種各樣的屬性值,並且很多屬性值具有唯一性。因此非常建議使用相對路徑結合屬性值定位的方式來編寫XPath定位表示式,基於此定位方法可以解決大部分的頁面元素定位問題。
5.4使用XPath的軸(Axis)進行元素定位
使用Aixs方法可依據在文件書中的元素相對位置關係進行定位。先找到一個相對好定位的元素,再根據這個元素和要定位的相對位置進行定位,可以解決一些元素難以定位的問題。
5.4.1軸示意圖
5.4.2XPath常用的關鍵字
XPath常用的關鍵字如下所示:
XPath軸關鍵字 |
軸含義 |
例項 |
表示式解釋 |
ancestor |
選取當前節點的所有先輩(父、祖父等) |
//img[@alt=’div2-img2’]/ancestor::div |
查詢alt屬性值為div2-img的圖片,並基於圖片位置找到它的上級div頁面元素。 |
ancestor-or-self |
選取當前節點的所有先輩(父、祖父等)以及當前節點本身 |
//img[@alt=’div2-img2’]/ ancestor-or-self::* |
查詢alt屬性值為div2-img的圖片,並基於圖片位置找到它全部上級元素,包括它本身。 |
attribute |
選取當前節點的所有屬性 |
//img[@alt=’div2-img2’]/ attribute::* |
查詢alt屬性值為div2-img的圖片並返回該節點下的所有屬性節點 |
child |
選取當前節點的所有子元素。 |
//div[@id=’div1’]/child::img |
查詢ID屬性為div1的div頁面元素,並基於div的位置找到它下層節點中的img頁面元素 |
descendant |
選取當前節點的所有後代元素(子、孫等)。 |
//div[@name=’div2’]/ descendant::img |
查詢name屬性值為div2的元素,並基於div位置找到它下級的所有節點中的img頁面元素。 |
descendant-or-self |
選取當前節點的所有後代元素(子、孫等)以及當前節點本身。 |
//div[@name=’div2’]/ descendant::div |
查詢name屬性值為div2的元素,並基於div位置找到它下級的(包括自己)所有節點中的div頁面元素。其實就是它本身。 |
following |
選取文件中當前節點的結束標籤之後的所有節點。 |
//div[@id=’div1’]/ following::img |
查詢到ID屬性值為div1的div頁面,並基於div找到它後面節點中的img頁面元素 |
parent |
選取當前節點的父節點。 |
//img[@alt=’div2-img2’]/ parent::div |
查詢到alt屬性值為div2-img的圖片並基於圖片位置找到它上一級的div頁面元素。 |
preceding |
選擇當前節點前面的所有節點 |
//img[@alt=’div2-img2’]/preceding::div |
查詢alt屬性值為div2-img2的照片頁面元素,並基於圖片的位置找到它前面節點中的div頁面元素。 |
preceding-sibling |
選取當前節點之前的所有同級節點。 |
//img[@alt=’div2-img2’]/ preceding-sibling::a[1] |
查詢alt屬性值為div2-img2的照片頁面元素,並基於圖片的位置找到它前面同級節點中的第二個連結頁面元素 |
self |
選取當前節點。 |
|
|
5.4.3使用方法
軸名稱::節點測試[謂語]
例如:
//form/div[last()-1]/ancestor::div[@class='modal-content']
5.4.4實踐
1.descendant表示取當前節點的所有後代元素,巨集哥演示定位百度首頁的“百度一下”按鈕,如下圖所示:
可以看到,input標籤的父元素是span標籤,而span標籤的父元素是form標籤,所以可以通過先定位form標籤,然後利用descendant定位input標籤
xpath路徑如下:
//定位思路: //(1)form[@id='form']表示找到id屬性為'form'的<form>標籤, //(2)descendant::input表示找到<form>標籤的所有後代<input>標籤, //(3)然後通過[@id='su']精準定位到id屬性為'su'的<input>標籤 xpath= "//form[@id='form']/descendant::input[@id='su']"
把路徑放到瀏覽器控制檯,按下Ctrl+F,然後輸入xpath路徑,檢視一下,確實定位到了標籤(在執行程式之前,可以通過這種方式來驗證一下寫的xpath路徑是否正確)
2.following表示選取當前節點結束標籤之後的所有節點
注意這裡說的是“結束標籤之後”,所以在用這個軸進行定位時要看清目標標籤的與輔助定位標籤的層級關係,所以上例中就不能通過標籤結合following來定位,因為標籤在標籤裡面;
分析一下:input標籤的上級是一個span標籤,這個span標籤上面也有一個span標籤,可以通過它(span)來定位
//定位思路: //(1)span[@id='s_kw_wrap']表示定位到id屬性為s_kw_wrap的<span>標籤, //(2)following::input[@id='su']表示找到<span>結束標籤(即</span>)後的所有input標籤, //(3)然後通過[@id='su']精準定位到id屬性為'su'的<input>標籤 xpath= "//span[@id='s_kw_wrap']/following::input[@id='su']"
按上邊的方法,巨集哥再次驗證一下,成功定位到“百度一下”按鈕,如下圖所示:
3.parent可指定要查詢的當前節點的直接父節點
例如,父節點是個div,即可寫成parent::div,如果要找的元素不是直接父元素,則不可使用parent,可使用ancestor,代表父輩、祖父輩等節點,child::表示直接子節點元素,following-sibling只會標識出當前節點結束標籤之後的兄弟節點,而不包含其他子節點;
以https://www.guru99.com/這個網站為例,如下圖所示:
定位網頁中的python:
//定位思路: //(1)先定位Java,然後找到Java的父節點li, //(2)然後再找li的兄弟節點,即包含Python的那個li標籤, //(3)然後再找li的孩子節點,也就是a標籤 xpath="//a[text()='Java']/parent::li/following-sibling::li/child::a[text()='Python']" //或者 xpath="//a[text()='Java']/parent::li/following-sibling::li[2]/a"
巨集哥這裡就不做驗證了,有興趣或者不信的小夥伴或者童鞋們,可以按照巨集哥的方法自己驗證一下。
6.小結
好了,今天分享的前邊兩種xpath的定位方法比較簡單,第三種比較難一點,不過慢慢積累經驗時間久了也就那麼回事。今天到此巨集哥就分享完了。後邊還有一些,敬請期待。
7.擴充
① Xpath 定位擴充套件
使用通過子節點定位父節點
..代表父節點;../..爺爺節點
//span[contains(text(),'1.jpg')]/..
② Xpath 還支援布林定位
Xpath = //input[@id='kw1' and @name='wd']
可以 and ,當然也可以 or :
Xpath = //input[@id='kw1' or @name='wd']