在使用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