这篇文章介绍selenium web driver中的xpath定位器。首先先详细介绍一下什么是xpath以及它的用法。xpath是xml path的简称,是一种寻找网页元素的语言。xml文件大家都见过吧,就长这个样子:
xml是一种结构化的语言,你看,文件上的信息错落有致,清楚明白地告诉我们书店里有两本书,一本是J.K.罗琳的《哈利波特》,另一本是刘慈欣的《三体》。path是路径的意思,顾名思义,我可以沿着一条路径找到我想要的元素。比如我想找《三体》的出版年份,先不考虑语法,那这条路径就应该是bookstore -> book[2] -> year,[2]代表第二个<book>。
你会发现网页html和它很像,也有元素、标签、值之类的东西,比如下面一段html代码:
每一个元素都用一个标签(tag)来表示,之前介绍tagName定位器说过了,我们可以用tagName来定位一个元素。有些元素还有属性,比如上面的<input>,type/id/name/class/value都是它的属性。每一个属性都有属性值,比如id="username",username就是id的属性值。如果一个元素有id、name、class这种属性,那我们完全可以直接使用相关的定位器即可。但如果没有,比如<input type="submit" class="t1" value="login">这句,xpath就可以派上用场了,因为html也可以按照xml的路径法则来寻找元素。
xpath路径分两种,一种是绝对路径,另一种是相对路径。绝对路径和相对路径这个概念大家也应该听到过,绝对路径指的是某一个资源的完整路径,比如你在C盘的films文件夹中存了一个叫video.avi的视频文件,这个文件的绝对路径就是C:\films\video.avi。对于html文档也一样
,某一个节点的绝对路径是从<html>开始一直到该节点,比如要找上面的<form>,xpath就是
绝对路径的起始标识符是“/”,但也可以出现在中间。最一开始的“/”指的是html文档本身,意思是在当前的html文档查找;中间的“/”指的是以当前节点为参照往下找第一层匹配对象。咱们还没讲轴定位,现在只限于向下查找,下篇学了轴定位还可以向上查找或是同层查找,咱们暂时先不考虑。所以,这个xpath的执行过程就是:html文档最开始的节点是<html>。以<html>为参照查看下面第一层有没有<body>,发现有,跳到<body>,这样<body>就成为了新的当前节点。接下来再以<body>为参照查找下面第一层看有没有<div>,发现有,然后又跳到<div>,这样<div>又成了新的当前节点。最后跳到<form>,就是这么一个简单的过程,永远都是以当前节点为参照。如果中间无法找到某个节点则证明xpath有错。注意,仅限于下面第一层,你写/html/form就找不到,因为form不是html的下面第一层,中间隔了body和div两层。
同理,<input>标签的绝对路径就是
总共可以找到四个input标签。大家或许也看出来了,绝对路径有一个很大的弊端,被查找的节点越深,那它的绝对路径就越长,这时如果开发网页的人稍微变动一下代码,我们的xpath就很可能出错以致无法定位元素。所以,我们一般都用相对路径来定义某个元素的xpath。
相对路径的意思是以当前节点为参照往下查找所有的指定节点,不局限于第一层。它用“//”作为起始标识符,也可以出现在中间。最一开始的“//”指的是该xpath会是一个相对路径,并且在当前的html文档查找。比如还是寻找<input>,用相对路径写xpath就可以直接写成
简单吧?意思就是从该html文档直接查找所有的input。例子中有四对input标签,都可以被找到。
如果把“//”放在中间,那它指的就是以当前节点为参照往下找所有匹配对象,不受层级限制,这也就意味着相对路径不止一种写法。比如我也可以把寻找input的xpath写成
翻译过来就是先从该html文档直接查找所有body,很明显例子中只有一对body标签,直接锁定。然后再以body为参照查找下面所有的input,有四对input标签,直接锁定,定位完成。虽然body和form中间还隔着一层div,但没关系,因为“//”不受层次制约。即便四个input不在同一层,只要它们都在body下面,那也都可以找到。比如我改一下html代码:
把后两个input从form中挪出去,你写//body//input还是可以找到所有的input。
需要注意的是,相对路径里也可以有“/”。还是寻找<input>,如果我想找上图form里的两个input,我可以把xpath写成
翻译过来就是先从该html文档直接查找所有body,然后因为是“/”,所以以body为参照往下找第一层的div,接着又是“//”,再以div为参照查找下面所有的form,最后又是“/”,以form为参照往下找第一层的input,总共有两个。
xpath还可以加入通配符,用“*”表示,指的是所有节点,比如说
意思就是先选定div下面第一层的所有节点,再以所有这些节点为参照寻找下面第一层的input。显然,div下面第一层只有form一个节点,这个星号也就只代表form。再举一个星号代表多个节点的例子:
form下面第一层有多个input,这个星号指的就是input。
这就是绝对路径和相对路径的基本用法。总之,相对路径要比绝对路径省事得多,而且也更加灵活,出错率相对低一些。我们写自动化测试代码时一般也使用相对路径写xpath。
那如果我要找的节点光凭一个标签名无法定位呢?比如我们的例子中有四个<input>标签,我想定位<input type=”submit” class=”t1” value=”login”>,可是这四对<input>都满足//div/form/input,我怎么区分呢?总不能都选出来吧?这就需要属性的帮助了。还是让form包含四个input:
第一种情况是通过完整的属性值来区分,xpath格式如下:
注意,属性前面有一个“@”符号。现在我可以把xpath修改成//div/form/input[@value="login"],因为这四者只有第三个的value属性等于login。同理,每个input其实都可以靠属性的帮助让xpath对它们唯一标识:
当然,它们也都可以用id/name/classname定位器来定位,可我们假设它们不能,只能用xpath。
第二种情况是通过部分的属性值来区分,xpath格式如下:
contains是包含、包括的意思。之前介绍java字符串时介绍过一个叫contains的方法,可以用来判断一个字符串是否包含另外一个字符串。xpath这边是一个道理,比如一个属性的属性值很长,你怕写错,就可以用contains。比如密码旁边的那个input,你可以写成:
第三种情况是有时候单凭一个属性值还不能完全解决问题,比如:
我想找第一行,但你会发现不管是用type/class/value都不能唯一定位第一行,这时就需要用两个或两个以上的属性共同参与。连接几个属性的关键字是AND和OR:
AND是与,代表前后两者都满足才可以;OR是或,代表前后两者只要满足一个即可。这点和java的逻辑运算符是一致的。显然,这个例子我们应该用AND:
第四种情况是属性是文本的时候,比如一个链接或是一个下拉列表里的文字:
把属性换成text()就可以了。
第五种情况是可以使用索引下标。比如还是这个例子:
四个input可以这么写:
注意,索引下标不是相对于整个html来说的,而是相对于某个元素而说的,比如我再次把后两个input从form中挪出去:
现在如果用索引下标写这四个input就会变成
form下面有两个input,没什么问题。可div容易出错。虽然div下面总共有四个input,但因为你用的是"/",那就意味着以div为参照找下面第一层的,只有两个input。但是如果你在div后边用"//"就不一样了,因为是找它下边所有的:
以div为参照总共有四个地方出现input,索引也要相应更改。所以,位置不一样,目标节点的上一个元素就不一样,xpath路径也就不一样。路径都不一样了自然索引下标就不一样。
如果上述五种情况都无法完成定位,那还可以用更强大的xpath轴(axes)定位方法,下篇讨论。xpath语法不复杂,勤加练习就能快速掌握。网上有很多xpath的练习工具可供选择,如果你安装了Firefox浏览器,再安装上firepath插件就可以了。安装后右键点击目标网页,再选择用firepath检查,就可以弹出firepath窗口。截图如下:
在xpath框中输入一个合法的xpath就可以看到目标节点高亮显示。
本篇知识点及注意事项:
1. xpath可以使用绝对路径和相对路径两种方法对元素定位,因为绝对路径又长又丑,所以我们用相对路径。
2. “/”可以出现在最开始,也可以出现在中间。最一开始的“/”是绝对路径的标志,指的是html文档本身,意思是在当前的html文档查找;中间的“/”指的是以当前节点为参照往下找第一层匹配对象。
3. “//”可以出现在最开始,也可以出现在中间。最一开始的“//”是相对路径的标志,意思是在当前的html文档查找;中间的“//”指的就是以当前节点为参照往下找所有匹配对象,不受层级限制。
4. xpath可以使用属性以及一些关键字配合使用。