在使用selenium webdriver進行元素定位時,一般使用findElement或findElements方法結合By類返回的元素句柄來定位元素。其中By類的經常使用定位方式共八種:By.id()、 By.name()、By.tagName()、By.className()、 By.linkText()、 By.partialLinkText()、 By.xpath()、By.cssSelector()。php
在實際項目-運營管理平臺中,我主要用到的是By.id()、By.cssSelector()、By.linkText()共三種,其中By.cssSelector()的使用比較多。css
無論採用哪種定位方式,都要保證代碼在頁面中找到的元素是惟一的,保證可以準確找到對應的元素。html
現分別介紹以下:java
一、 By.id()程序員
【添加】按鈕的頁面源碼以下:web
<button id="create_btn" type="button" class="btn btn-xs btn-primary">添加</button>瀏覽器
要引用該button並點擊它,代碼有兩種寫法,兩種寫法實現的效果是同樣的,只是1.2寫法讓代碼簡化好看一些,代碼以下:ide
1.1 性能
WebElement Create_btn = driver.findElement(By.id("create_btn")); Create_btn.click();
1.2 設計
driver.findElement(By.id("create_btn")).click();
二、 By.name()
登陸頁面用戶名的頁面源碼以下:
<input name="username" id="username" class="form-control" placeholder="用戶名" type="text">
當咱們要用name屬性來引用這個input並輸入用戶名時,代碼以下:
1.1
WebElement Username_input = driver.findElement(By.name("username ")); Username_input.sendKeys("admin");
1.2
driver.findElement(By.name("username")).sendKeys("admin");
三、 By.className()
className屬性是利用元素的css樣式表所引用的僞類名稱來進行元素查找的方法。對於任何HTML頁面的元素來講,通常程序員或頁面設計師會給元 素直接賦予一個樣式屬性或者利用css文件裏的僞類來定義元素樣式,使元素在頁面上顯示時可以更加美觀。通常css樣式表可能會長成下面這個樣子:
.form-control {
border-radius: 0;
box-shadow: none;
border-color: #d2d6de;
}
定義好後,就能夠在頁面元素中引用上述定義好的樣式,登陸頁面用戶名的頁面源碼以下:
<input name="username" id="username" class="form-control" placeholder="用戶名" type="text">
若是此時咱們要經過className屬性來查找該input並輸入用戶名的話,就可使用className屬性了,代碼以下:
WebElement Username_input = driver.findElement(By.className("form-control")); Username_input.sendKeys("admin");
注意:使用className來進行元素定位時,有時會碰到同一個樣式屬性被不一樣的input元素引用,出現定位元素不惟一的狀況,則採用這種方式不適合了(以下圖)。對於這種狀況則能夠找出惟一點採用By.cssSelector()方式來定位。
四、 By.cssSelector()
cssSelector這種元素定位方式跟xpath比較相似,但執行速度較快,並且各類瀏覽器對它的支持都至關到位,因此功能也是蠻強大的。
下面是一些常見的cssSelector的定位方式:
定位id爲flrs的div元素,能夠寫成:#flrs 注:至關於xpath語法的//div[@id=’flrs’]
定位id爲flrs下的a元素,能夠寫成 #flrs > a 注:至關於xpath語法的//div[@id=’flrs’]/a
定位id爲flrs下的href屬性值爲/forexample/about.html的元素,能夠寫成: #flrs > a[href=」/forexample/about.html」]
若是須要指定多個屬性值時,能夠逐一加在後面,如#flrs > input[name=」username」][type=」text」]。
明白基本語法後,咱們來嘗試用cssSelector方式來引用
4.1【添加】按鈕,若是【添加】按鈕的id是惟一的,那代碼以下:
WebElement Create_btn = driver.findElement(By.cssSelector("#create_btn"));
Create_btn.click();
4.2用cssSelector方式來引用登陸頁面用戶名的input,若是該input的name是惟一的,那代碼以下:
WebElement Username_input = driver.findElement(By.cssSelector(".username")); Username_input.sendKeys("admin");
4.3數據列表的頁面源碼以下:
針對這種數據列表的狀況,要通常建議結合使用findElements方法來使用。好比咱們如今要查找數據列表中有多少行數據記錄,就能夠用tr這個tagName來進行查找,代碼以下:
List<WebElement> datalis=driver.findElements(By.cssSelector("#data_table tbody > tr")); System.out.println(datalis.size()); //打印出tr的個數
必須注意層級關係,這個不能省略。
4.4 cssSelector還有一個用處是定位使用了複合樣式表的元素。
button代碼以下:
<button id="J_sidebar_login" class="btn btn_big btn_submit" type="submit">登陸</button>
cssSelector引用元素代碼以下:
driver.findElement(By.cssSelector("button.btn.btn_big.btn_submit"));
這樣就能夠順利引用到使用了複合樣式的元素了。
此外,cssSelector還有一些高級用法,若是熟練後能夠更加方便地幫助咱們定位元素,如咱們能夠利用^用於匹配一個前綴,$用於匹配一個後綴,*用於匹配任意字符。例如:
匹配一個有id屬性,而且id屬性是以」id_prefix_」開頭的超連接元素:a[id^='id_prefix_']
匹配一個有id屬性,而且id屬性是以」_id_sufix」結尾的超連接元素:a[id$='_id_sufix']
匹配一個有id屬性,而且id屬性中包含」id_pattern」字符的超連接元素:a[id*='id_pattern']
其實,cssSelector的定位方式還有好多好多,具體你們能夠參考下Jquery的「選擇器」。
五、 By.linkText()
這個方法比較直接,即經過超文本連接上的文字信息來定位元素,這種方式通常專門用於定位頁面上的超文本連接。一般一個超文本連接會長成這個樣子:
<a href="/chadmin/backend/web/index.php?r=admin-module%2Findex">菜單管理</a>
咱們定位這個元素時,可使用下面的代碼進行操做:
WebElement menuLink = driver.findElement(By.linkText("菜單管理")); menuLink.click();
六、 By.partialLinkText()
這個方法是上一個方法的擴展。當你不能準確知道超連接上的文本信息或者只想經過一些關鍵字進行匹配時,可使用這個方法來經過部分連接文字進行匹配。代碼以下:
WebElement menuLink = driver.findElement(By.partialLinkText("菜單")); menuLink.click();
七、 By.tagName()
該方法能夠經過元素的標籤名稱來查找元素。該方法跟以前兩個方法的區別是,這個方法搜索到的元素一般不止一個,因此通常建議結合使用 findElements方法來使用。好比咱們如今要查找頁面上有多少個button,就能夠用button這個tagName來進行查找,代碼以下:
List<WebElement> buttons = driver.findElements(By.tagName("button")); System.out.println(buttons.size()); //打印出button的個數
另外,在使用tagName方法進行定位時,還有一個地方須要注意的是,一般有些HTML元素的tagName是相同的。好比單選框、複選框、文本框和密碼框的元素標籤都是input,此時單靠tagName沒法準確地獲得咱們想要的元素,須要結合type屬性才能過濾出咱們要的元素。示例代碼以下:
List<WebElement> allInputs = driver.findElements(By.tagName("input")); //只打印全部文本框的值 for(WebElement e: allInputs){ if (e.getAttribute(「type」).equals(「text」)){ System.out.println(e.getText().toString()); //打印出每一個文本框裏的值 } }
八、 By.xpath()
這個方法是很是強大的元素查找方式,使用這種方法幾乎能夠定位到頁面上的任意元素。在正式開始使用XPath進行定位前,咱們先了解下什麼是 XPath。XPath是XML Path的簡稱,因爲HTML文檔自己就是一個標準的XML頁面,因此咱們可使用XPath的語法來定位頁面元素。
假設咱們如今以圖(1)所示HTML代碼爲例,要引用對應的對象,XPath語法以下:
圖(1)
絕對路徑寫法(只有一種),寫法以下:
引用頁面上的form元素(即源碼中的第3行):/html/body/form[1]
注意:1. 元素的xpath絕對路徑可經過firebug直接查詢。2. 通常不推薦使用絕對路徑的寫法,由於一旦頁面結構發生變化,該路徑也隨之失效,必須從新寫。3. 絕 對路徑以單/號表示,而下面要講的相對路徑則以//表示,這個區別很是重要。另外須要多說一句的是,當xpath的路徑以/開頭時,表示讓Xpath解析 引擎從文檔的根節點開始解析。當xpath路徑以//開頭時,則表示讓xpath引擎從文檔的任意符合的元素節點開始進行解析。而當/出如今xpath路 徑中時,則表示尋找父節點的直接子節點,當//出如今xpath路徑中時,表示尋找父節點下任意符合條件的子節點,無論嵌套了多少層級(這些下面都有例 子,你們能夠參照來試驗)。弄清這個原則,就能夠理解其實xpath的路徑能夠絕對路徑和相對路徑混合在一塊兒來進行表示,想怎麼玩就怎麼玩。
下面是相對路徑的引用寫法:
查找頁面根元素://
查找頁面上全部的input元素://input
查找頁面上第一個form元素內的直接子input元素(即只包括form元素的下一級input元素,使用絕對路徑表示,單/號)://form[1]/input
查找頁面上第一個form元素內的全部子input元素(只要在form元素內的input都算,無論還嵌套了多少個其餘標籤,使用相對路徑表示,雙//號)://form[1]//input
查找頁面上第一個form元素://form[1]
查找頁面上id爲loginForm的form元素://form[@id='loginForm']
查找頁面上具備name屬性爲username的input元素://input[@name='username']
查找頁面上id爲loginForm的form元素下的第一個input元素://form[@id='loginForm']/input[1]
查找頁面具備name屬性爲contiune而且type屬性爲button的input元素://input[@name='continue'][@type='button']
查找頁面上id爲loginForm的form元素下第4個input元素://form[@id='loginForm']/input[4]
Xpath功能很強大,因此也能夠寫得更加複雜一些。
在這裏,我不想講解太多Xpath。由於xpath這種定位方式,webdriver會將整個頁面的全部元素進行掃描以定位咱們所須要的元素,因此這是一個很是費時的操做,若是你的腳本中大量使用xpath作元素定位的話,將致使你的腳本執行速度大大下降,因此請慎用。
九、 使用經驗總結
總結一下,各類方式在選擇的時候應該怎麼選擇:
1. 當頁面元素有id屬性時,最好儘可能用id來定位。但因爲現實項目中不少程序員其實寫的代碼並不規範,會缺乏不少標準屬性,這時就只有選擇其餘定位方法。
2. xpath很強悍,但定位性能不是很好,因此仍是儘可能少用。若是確實少數元素很差定位,能夠選擇cssSelector。
3. 當要定位一組元素相同元素時,也能夠考慮用cssSelector。
4. 當有連接須要定位時,能夠考慮linkText或partialLinkText方式。
參文:http://testng.org/doc/documentation-main.html