Selenium Webdriver元素定位的八种常用方式(小结)


Posted in Python onJanuary 13, 2021

在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合By类返回的元素句柄来定位元素。其中By类的常用定位方式共八种,现分别介绍如下。

1. By.name()

假设我们要测试的页面源码如下:

<button id="gbqfba" aria-label="Google Search" name="btnK" class="gbqfba"><span id="gbqfsa">Google Search</span></button>

当我们要用name属性来引用这个button并点击它时,代码如下:

public class SearchButtonByName {
    public static void main(String[] args){
        WebDriver driver = new FirefoxDriver();
        driver.get("http://www.forexample.com");
        WebElement searchBox = driver.findElement(By.name("btnK"));
        searchBox.click();
    }
}

2. By.id()

页面源码如下:

<button id="gbqfba" aria-label="Google Search" name="btnK" class="gbqfba"><span id="gbqfsa">Google Search</span></button>

要引用该button并点击它时,代码如下:

public class SearchButtonById {

    public static void main(String[] args){

      WebDriver driver = new FirefoxDriver();

      driver.get("http://www.forexample.com");

      WebElement searchBox = driver.findElement(By.id("gbqfba"));

      searchBox.click();

    }

}

3. By.tagName()

该方法可以通过元素的标签名称来查找元素。该方法跟之前两个方法的区别是,这个方法搜索到的元素通常不止一个,所以一般建议结合使用findElements方法来使用。比如我们现在要查找页面上有多少个button,就可以用button这个tagName来进行查找,代码如下:

public class SearchPageByTagName{

   public static void main(String[] args){

      WebDriver driver = new FirefoxDriver();
      driver.get("http://www.forexample.com");
      List<WebElement> buttons = driver.findElements(By.tagName("button"));

      System.out.println(buttons.size()); //打印出button的个数

  }

}

另外,在使用tagName方法进行定位时,还有一个地方需要注意的是,通常有些HTML元素的tagName是相同的,如下图(1)所示。

Selenium Webdriver元素定位的八种常用方式(小结)

从图中我们可以看到,单选框、复选框、文本框和密码框的元素标签都是input,此时单靠tagName无法准确地得到我们想要的元素,需要结合type属性才能过滤出我们要的元素。示例代码如下:

public class SearchElementsByTagName{

    public static void main(String[] args){

      WebDriver driver = new FirefoxDriver();

      driver.get("http://www.forexample.com");

      List<WebElement> allInputs = driver.findElements(By.tagName("input"));

      //只打印所有文本框的值

      for(WebElement e: allInputs){

         if (e.getAttribute(“type”).equals(“text”)){

         System.out.println(e.getText().toString()); //打印出每个文本框里的值

         }

      }

    }

}

4. By.className()

className属性是利用元素的css样式表所引用的伪类名称来进行元素查找的方法。对于任何HTML页面的元素来说,一般程序员或页面设计师会给元素直接赋予一个样式属性或者利用css文件里的伪类来定义元素样式,使元素在页面上显示时能够更加美观。一般css样式表可能会长成下面这个样子:

.buttonStyle{

  width: 50px;

  height: 50px;

  border-radius: 50%;

  margin: 0% 2%;

}

定义好后,就可以在页面元素中引用上述定义好的样式,如下:

<button name="sampleBtnName" id="sampleBtnId" class="buttonStyle">I'm Button</button>

如果此时我们要通过className属性来查找该button并操作它的话,就可以使用className属性了,代码如下:

public class SearchElementsByClassName{

  public static void main(String[] args){

    WebDriver driver = new FirefoxDriver();

    driver.get("http://www.forexample.com");

    WebElement searchBox = driver.findElement(By.className("buttonStyle"));

    searchBox.sendKeys("Hello, world");

  }

}

注意:使用className来进行元素定位时,有时会碰到一个元素指定了若干个class属性值的“复合样式”的情况,如下面这个button:<button type="submit">登录</button>。这个button元素指定了三个不同的css伪类名作为它的样式属性值,此时就必须结合后面要介绍的cssSelector方法来定位了,稍后会有详细例子。

5. By.linkText()

这个方法比较直接,即通过超文本链接上的文字信息来定位元素,这种方式一般专门用于定位页面上的超文本链接。通常一个超文本链接会长成这个样子:

<a href="/intl/en/about.html" rel="external nofollow" >About Google</a>

我们定位这个元素时,可以使用下面的代码进行操作:

public class SearchElementsByLinkText{

  public static void main(String[] args){

    WebDriver driver = new FirefoxDriver();

    driver.get("http://www.forexample.com");

    WebElement aboutLink = driver.findElement(By.linkText("About Google"));

    aboutLink.click();

  }

}

6. By.partialLinkText()

这个方法是上一个方法的扩展。当你不能准确知道超链接上的文本信息或者只想通过一些关键字进行匹配时,可以使用这个方法来通过部分链接文字进行匹配。代码如下:

public class SearchElementsByPartialLinkText{

  public static void main(String[] args){

    WebDriver driver = new FirefoxDriver();

    driver.get("http://www.forexample.com");

    WebElement aboutLink = driver.findElement(By.partialLinkText("About"));

    aboutLink.click();

  }

}

注意:使用这种方法进行定位时,可能会引起的问题是,当你的页面中不止一个超链接包含About时,findElement方法只会返回第一个查找到的元素,而不会返回所有符合条件的元素。如果你要想获得所有符合条件的元素,还是只能使用findElements方法。

7. By.xpath()

这个方法是非常强大的元素查找方式,使用这种方法几乎可以定位到页面上的任意元素。在正式开始使用XPath进行定位前,我们先了解下什么是XPath。XPath是XML Path的简称,由于HTML文档本身就是一个标准的XML页面,所以我们可以使用XPath的语法来定位页面元素。

假设我们现在以图(2)所示HTML代码为例,要引用对应的对象,XPath语法如下:

Selenium Webdriver元素定位的八种常用方式(小结)

绝对路径写法(只有一种),写法如下:

引用页面上的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功能很强大,所以也可以写得更加复杂一些,如下面图(3)的HTML源码。

Selenium Webdriver元素定位的八种常用方式(小结)

如果我们现在要引用id为“J_password”的input元素,该怎么写呢?我们可以像下面这样写:

WebElement password = driver.findElement(By.xpath("//*[@id='J_login_form']/dl/dt/input[@id='J_password']"));

也可以写成:

WebElement password = driver.findElement(By.xpath("//*[@id='J_login_form']/*/*/input[@id='J_password']"));

这里解释一下,其中//*[@id=' J_login_form']这一段是指在根元素下查找任意id为J_login_form的元素,此时相当于引用到了form元素。后面的路径必须按照源码的层级依次往下写。按照图(3)所示代码中,我们要找的input元素包含在一个dt标签内,而dt又包含在dl标签内,所以中间必须写上dl和dt两层,才到input这层。当然我们也可以用*号省略具体的标签名称,但元素的层级关系必须体现出来,比如我们不能写成//*[@id='J_login_form']/input[@id='J_password'],这样肯定会报错的。

前面讲的都是xpath中基于准确元素属性的定位,其实xpath作为定位神器也可以用于模糊匹配。比如下面图(4)所示代码:

Selenium Webdriver元素定位的八种常用方式(小结)

这段代码中的“退出”这个超链接,没有标准id元素,只有一个rel和href,不是很好定位。不妨我们就用xpath的几种模糊匹配模式来定位它吧,主要有三种方式,举例如下。

a. 用contains关键字,定位代码如下:

driver.findElement(By.xpath(“//a[contains(@href, ‘logout')]”));

这句话的意思是寻找页面中href属性值包含有logout这个单词的所有a元素,由于这个退出按钮的href属性里肯定会包含logout,所以这种方式是可行的,也会经常用到。其中@后面可以跟该元素任意的属性名。

b. 用start-with,定位代码如下:

driver.findElement(By.xpath(“//a[starts-with(@rel, ‘nofo')]));

这句的意思是寻找rel属性以nofo开头的a元素。其中@后面的rel可以替换成元素的任意其他属性。

c. 用Text关键字,定位代码如下:

driver.findElement(By.xpath(“//*[text()='退出']));

这个方法可谓相当霸气啊。直接查找页面当中所有的退出二字,根本就不用知道它是个a元素了。这种方法也经常用于纯文字的查找。

另外,如果知道超链接元素的文本内容,也可以用

driver.findElement(By.xpath(“//a[contains(text(), '退出')]));

这种方式一般用于知道超链接上显示的部分或全部文本信息时,可以使用。

最后,关于xpath这种定位方式,webdriver会将整个页面的所有元素进行扫描以定位我们所需要的元素,所以这是一个非常费时的操作,如果你的脚本中大量使用xpath做元素定位的话,将导致你的脚本执行速度大大降低,所以请慎用。

8. 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方式来引用图(3)中选中的那个input对象,代码如下:

WebElement password = driver.findElement(By.cssSelector("#J_login_form>dl>dt>input[id=' J_password']"));

同样必须注意层级关系,这个不能省略。

cssSelector还有一个用处是定位使用了复合样式表的元素,之前在第4种方式className里面提到过。现在我们就来看看如何通过cssSelector来引用到第4种方式中提到的那个button。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']

最后再总结一下,各种方式在选择的时候应该怎么选择:

1. 当页面元素有id属性时,最好尽量用id来定位。但由于现实项目中很多程序员其实写的代码并不规范,会缺少很多标准属性,这时就只有选择其他定位方法。

2. xpath很强悍,但定位性能不是很好,所以还是尽量少用。如果确实少数元素不好定位,可以选择xpath或cssSelector。

3. 当要定位一组元素相同元素时,可以考虑用tagName或name。

4. 当有链接需要定位时,可以考虑linkText或partialLinkText方式。

参考资料:

《Selenium Webdriver Practical Guide》

到此这篇关于Selenium Webdriver元素定位的八种常用方式(小结)的文章就介绍到这了,更多相关Selenium Webdriver元素定位内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python实现的Kmeans++算法实例
Apr 26 Python
Python数组条件过滤filter函数使用示例
Jul 22 Python
基python实现多线程网页爬虫
Sep 06 Python
Python中最大最小赋值小技巧(分享)
Dec 23 Python
对python中的for循环和range内置函数详解
Apr 17 Python
Django中使用session保持用户登陆连接的例子
Aug 06 Python
python3.6、opencv安装环境搭建过程(图文教程)
Nov 05 Python
动态设置django的model field的默认值操作步骤
Mar 30 Python
Jupyter加载文件的实现方法
Apr 14 Python
如何解决安装python3.6.1失败
Jul 01 Python
Django如何实现密码错误报错提醒
Sep 04 Python
python中使用asyncio实现异步IO实例分析
Feb 26 Python
基于python+selenium自动健康打卡的实现代码
Jan 13 #Python
Python爬虫scrapy框架Cookie池(微博Cookie池)的使用
Jan 13 #Python
matplotlib交互式数据光标实现(mplcursors)
Jan 13 #Python
Python 生成短8位唯一id实战教程
Jan 13 #Python
python uuid生成唯一id或str的最简单案例
Jan 13 #Python
全网最全python库selenium自动化使用详细教程
Jan 12 #Python
[原创]赚疯了!转手立赚800+?大佬的python「抢茅台脚本」使用教程
Jan 12 #Python
You might like
全国FM电台频率大全 - 22 重庆市
2020/03/11 无线电
PHP cron中的批处理
2008/09/16 PHP
php中的三元运算符使用说明
2011/07/03 PHP
静态的动态续篇之来点XML
2006/08/15 Javascript
点击隐藏页面左栏或右栏实现js代码
2013/04/01 Javascript
JS验证日期的格式YYYY-mm-dd 具体实现
2013/06/29 Javascript
jQuery添加/改变/移除CSS类及判断是否已经存在CSS
2014/08/20 Javascript
轻松实现Bootstrap图片轮播
2020/04/20 Javascript
纯js实现瀑布流布局及ajax动态新增数据
2016/04/07 Javascript
JQuery validate插件Remote用法大全
2016/05/15 Javascript
简单了解JavaScript操作XPath的一些基本方法
2016/06/03 Javascript
AngularJS国际化详解及示例代码
2016/08/18 Javascript
Vue-Router实现页面正在加载特效方法示例
2017/02/12 Javascript
微信小程序商城项目之商品属性分类(4)
2017/04/17 Javascript
详解webpack es6 to es5支持配置
2017/05/04 Javascript
Vue实现动态显示textarea剩余字数
2017/05/22 Javascript
JS实现元素上下左右移动效果
2017/10/18 Javascript
mpvue跳转页面及注意事项
2018/08/03 Javascript
vue配置接口域名方法总结
2019/05/12 Javascript
Swiper.js实现移动端元素左右滑动
2019/09/08 Javascript
layui table复选框禁止某几条勾选的实例
2019/09/20 Javascript
微信小程序新闻网站详情页实例代码
2020/01/10 Javascript
[09:37]DOTA2卡尔工作室 英雄介绍圣堂刺客篇
2013/06/13 DOTA
python实现简易通讯录修改版
2018/03/13 Python
Python读取txt内容写入xls格式excel中的方法
2018/10/11 Python
Python第三方Window模块文件的几种安装方法
2018/11/22 Python
Python 合并多个TXT文件并统计词频的实现
2019/08/23 Python
python requests包的request()函数中的参数-params和data的区别介绍
2020/05/05 Python
史蒂夫·马登加拿大官网:Steve Madden加拿大
2017/11/18 全球购物
教师个人自我鉴定
2014/02/08 职场文书
医学生求职信
2014/07/01 职场文书
2014年银行信贷员工作总结
2014/12/08 职场文书
护士工作心得体会
2016/01/25 职场文书
Oracle 临时表空间SQL语句的实现
2021/09/25 Oracle
Grafana可视化监控系统结合SpringBoot使用
2022/04/19 Redis
在虚拟机中安装windows server 2008的图文教程
2022/06/28 Servers