《手把手教你》系列技巧篇(十五)-java+ selenium自动化测试-元素定位大法之By xpath中卷(详细教程)

简介: 【4月更文挑战第7天】按宏哥计划,本文继续介绍WebDriver关于元素定位大法,这篇介绍定位倒数二个方法:By xpath。xpath 的定位方法, 非常强大。使用这种方法几乎可以定位到页面上的任意元素。xpath 是XML Path的简称, 由于HTML文档本身就是一个标准的XML页面,所以我们可以使用Xpath 的用法来定位页面元素。XPath 是XML 和Path的缩写,主要用于xml文档中选择文档中节点。基于XML树状文档结构,XPath语言可以用在整棵树中寻找指定的节点。

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']


每天学习一点,今后必成大神-

往期推荐(由于跳转参数丢失了,所有建议选中要访问的右键,在新标签页中打开链接即可访问):

Appium自动化系列,耗时80天打造的从搭建环境到实际应用精品教程测试

Python接口自动化测试教程,熬夜87天整理出这一份上万字的超全学习指南

Python+Selenium自动化系列,通宵700天从无到有搭建一个自动化测试框架

Java+Selenium自动化系列,仿照Python趁热打铁呕心沥血317天搭建价值好几K的自动化测试框架

Jmeter工具从基础->进阶->高级,费时2年多整理出这一份全网超详细的入门到精通教程

Fiddler工具从基础->进阶->高级,费时100多天吐血整理出这一份全网超详细的入门到精通教程

Pycharm工具基础使用教程

相关文章
|
7月前
|
Java 测试技术 Python
《手把手教你》系列基础篇(八十)-java+ selenium自动化测试-框架设计基础-TestNG依赖测试-番外篇(详解教程)
【6月更文挑战第21天】本文介绍了TestNG中测试方法的依赖执行顺序。作者通过一个实际的自动化测试场景展示了如何设计测试用例:依次打开百度、搜索“selenium”、再搜索“selenium+java”。代码示例中,`@Test`注解的`dependsOnMethods`属性用于指定方法间的依赖,确保执行顺序。如果不设置依赖,TestNG会按方法名首字母排序执行。通过运行代码,验证了依赖关系的正确性。
75 4
|
6月前
|
测试技术 API Android开发
《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)
【7月更文挑战第15天】这是关于自动化测试框架中Selenium API二次封装的教程总结。教程中介绍了如何设计一个支持不同浏览器测试的页面基类(BasePage),该基类包含了对Selenium方法的二次封装,如元素的输入、点击、清除等常用操作,以减少重复代码。此外,页面基类还提供了获取页面标题和URL的方法。
133 2
|
6月前
|
存储 Web App开发 Java
《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)
【7月更文挑战第13天】这篇文章介绍了如何在Java中创建一个简单的自定义日志系统,以替代Log4j或logback。
308 5
|
6月前
|
Web App开发 XML Java
《手把手教你》系列基础篇(九十六)-java+ selenium自动化测试-框架之设计篇-跨浏览器(详解教程)
【7月更文挑战第14天】这篇教程介绍了如何使用Java和Selenium构建一个支持跨浏览器测试的自动化测试框架。设计的核心是通过读取配置文件来切换不同浏览器执行测试用例。配置文件中定义了浏览器类型(如Firefox、Chrome)和测试服务器的URL。代码包括一个`BrowserEngine`类,它初始化配置数据,根据配置启动指定的浏览器,并提供关闭浏览器的方法。测试脚本`TestLaunchBrowser`使用`BrowserEngine`来启动浏览器并执行测试。整个框架允许在不同浏览器上运行相同的测试,以确保兼容性和一致性。
118 3
|
6月前
|
设计模式 测试技术 Python
《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
【7月更文挑战第10天】Page Object Model (POM)是Selenium自动化测试中的设计模式,用于提高代码的可读性和维护性。POM将每个页面表示为一个类,封装元素定位和交互操作,使得测试脚本与页面元素分离。当页面元素改变时,只需更新对应页面类,减少了脚本的重复工作和维护复杂度,有利于团队协作。POM通过创建页面对象,管理页面元素集合,将业务逻辑与元素定位解耦合,增强了代码的复用性。示例展示了不使用POM时,脚本直接混杂了元素定位和业务逻辑,而POM则能解决这一问题。
74 6
|
6月前
|
设计模式 Java 测试技术
《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
【7月更文挑战第12天】在本文中,作者宏哥介绍了如何在不使用PageFactory的情况下,用Java和Selenium实现Page Object Model (POM)。文章通过一个百度首页登录的实战例子来说明。首先,创建了一个名为`BaiduHomePage1`的页面对象类,其中包含了页面元素的定位和相关操作方法。接着,创建了测试类`TestWithPOM1`,在测试类中初始化WebDriver,设置驱动路径,最大化窗口,并调用页面对象类的方法进行登录操作。这样,测试脚本保持简洁,遵循了POM模式的高可读性和可维护性原则。
57 2
|
6月前
|
XML Java 测试技术
《手把手教你》系列基础篇(九十一)-java+ selenium自动化测试-框架设计基础-Logback实现日志输出-下篇(详解教程)
【7月更文挑战第9天】在Java项目中,使用Logback配置可以实现日志按照不同包名输出到不同的文件,并且根据日志级别分开记录。
105 4
|
6月前
|
XML 测试技术 数据格式
《手把手教你》系列基础篇(八十五)-java+ selenium自动化测试-框架设计基础-TestNG自定义日志-下篇(详解教程)
【7月更文挑战第3天】TestNG教程展示了如何自定义日志记录。首先创建一个名为`TestLog`的测试类,包含3个测试方法,其中一个故意失败以展示日志。使用`Assert.assertTrue`和`Reporter.log`来记录信息。接着创建`CustomReporter`类,继承`TestListenerAdapter`,覆盖`onTestFailure`, `onTestSkipped`, 和 `onTestSuccess`,在这些方法中自定义日志输出。
60 6
|
6月前
|
Java 测试技术 Apache
《手把手教你》系列基础篇(八十六)-java+ selenium自动化测试-框架设计基础-Log4j实现日志输出(详解教程)
【7月更文挑战第4天】Apache Log4j 是一个广泛使用的 Java 日志框架,它允许开发者控制日志信息的输出目的地、格式和级别。Log4j 包含三个主要组件:Loggers(记录器)负责生成日志信息,Appenders(输出源)确定日志输出的位置(如控制台、文件、数据库等),而 Layouts(布局)则控制日志信息的格式。通过配置 Log4j,可以灵活地定制日志记录行为。
68 4
|
6月前
|
Java 关系型数据库 测试技术
《手把手教你》系列基础篇(八十九)-java+ selenium自动化测试-框架设计基础-Logback实现日志输出-上篇(详解教程)
【7月更文挑战第7天】Apache Log4j2的安全漏洞促使考虑使用logback作为替代的日志框架。Logback由log4j创始人设计,提供更好的性能,更低的内存使用,并且能够自动重载配置文件。它分为logback-core、logback-classic(实现了SLF4J API)和logback-access(用于Servlet容器集成)三个模块。配置涉及Logger、Appender(定义日志输出目的地)和Layout(格式化日志)。
64 1