Selenium中使用xpath的定位分享
1、XPATH是什么
XPATH是一门在XML文档中查找信息的语言,XPATH可用来在XML文档中对元素和属性进行遍历,主流的浏览器都支持XPATH,因为HTML页面在DOM中表示为XHTML文档。
XPATH语言是基于XML文档的树结构,并提供了浏览树的能力,通过多样的标准来选择节点。
Selenium WebDriver支持使用XPATH表达式来定位元素。
XPATH和CSS选择器最重要的区别是XPATH可以向前和向后查询DOM结构的元素,而CSS选择器只能向前查询,这意味着XPATH可以通过子元素来定位父元素!
2、xpath定位元素的几种方式
1)绝对路径:
从DOM结构树的开始一直写到你需要定位的那个节点
ps:这样的情况基本只有一种情况才会出现,那就是所有的标签都重复,所有的属性都重复,不然打死我也不用这个办法。
2)相对路径:
eg:"//span"
其中 ‘//’ 标识忽略前面的所有节点,直接定位当前节点(例子的中当前节点为:span)
3)切片引索定位:
eg:"//span[0]"== or =="//span[-1]"
相对路径获取的节点往往不仅仅只存在一个,可能返回的是多个节点,使用下标 [0] 进行切片引索可以过滤部分节点或直接定位所需节点;这里为什么用过滤这个词,请自己实践://div[12] 和 //div 试试
4)使用节点属性引索定位:
eg:"//*[@name='name']"
* 标识匹配任何元素节点; @ 标识选取属性; name=‘name’ 表示选取节点属性name的值为name的节点属性;
5)使用节点谓语引索定位:
eg://*[text()="5)使用节点谓语引索定位:"]
text() 是xpath的谓语之一,也是应用场景多的谓语之一,其表示选取节点text字段为: 5)使用节点谓语引索定位: 的节点属性
6)利用xpath逻辑运算符进行定位节点
eg1://*div[@name='name' **and** @size='4' **and** @multiple="multiple"]
and 运算符组合节点属性进行引索匹配,定位节点
eg2://*div[@type='displayed' **or** @type='hidden']
or 运算符组合刷选多变节点属性进行匹配引索
(例子1 中利用三个节点属性并存的条件进行精确定位节点,在xpath运算符中,会以Hash计算方式分成三次进行定位节点,可以说其实是非常快的;例子2 中通常的应用场景是对某一按钮的定位,通过选中和非选中两种状态定位同一节点元素,这样可以省去一些事)
7)运用xpath轴的节点集进行反向定位
eg:.//*[@class="define"]//ancestor::div
这个就是css做不到的地方;反向定位:定位 class属性value为define的节点他的所有长辈节点通过: ancestor:: 控制;并筛选出节点标签为div的所有符合条件的节点。
这里拓展一下xpath轴“运算符”:
轴名称 | 对应情况 |
---|---|
ancestor | 选取当前节点的所有先辈(父、祖父等) |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身 |
attribute | 选取当前节点的所有属性 |
child | 选取当前节点的所有子元素 |
descendant | 选取当前节点的所有后代元素(子、孙等) |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身 |
following | 选取文档中当前节点的结束标签之后的所有节点 |
namespace | 选取当前节点的所有命名空间节点 |
parent | 选取当前节点的父节点 |
preceding | 选取文档中当前节点的开始标签之前的所有节点 |
preceding-sibling | 选取当前节点之前的所有同级节点 |
self | 选取当前节点 |
巧用这些xpath语句任何一个节点都是可以直接定位的。
有人说xpath定位慢,不如id,不如name…那是因为你只会给绝对路径而已。
前端哪里有那么多时间去给你添加id,添加name,靠人不如靠自己。
3、xpath使用思路
1)节点元素无id,无唯一name;请使用xpath;
eg:
<link rel="preload" href="https://addasdasdator.js?domain=www.wqwrqqe1231l.com.cn" as="script">
//link[@rel="preload" and @as="script"]
请注意这里不要使用 //* 开头;请使用 .// 或 //
* 是匹配任何节点元素的属性/谓语的意思;这么说吧,其实 //* 是 ==//[@*]==的一种简写。
2)节点元素需要集合或包含多种可能性,请使用xpath;
eg:需求–请定位一次性定位含字段的节点元素
<div class="show-pollution">
<span class="show-airParm polution-level-0">
<em class="show-polution-name">优</em>
<em class="show-polution-num">28</em>
</span><span class="show-vertical">|</span>
</div>
<div class="unknown-city">
<span class="unknown-icon"></span>
<span class="unknown-text">查看天气信息,</span>
<span class="unknown-setting">设置城市</span>
</div> </div>
//*[@class="show-pollution" or class="unknown-city"]//descendant::text()
3)节点元素是表格内部元素,相信我,请使用xpath;
eg:
<table class="dataintable">
<tbody>
<tr>
<th style="width:25%;">表达式</th>
<th>描述</th>
</tr>
<tr>
<td>nodename</td>
<td>选取此节点的所有子节点。</td>
</tr>
<tr>
<td>/</td>
<td>从根节点选取。</td>
</tr>
<tr>
<td>//</td>
<td>从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。</td>
</tr>
<tr>
<td>.</td>
<td>选取当前节点。</td>
</tr>
<tr>
<td>..</td>
<td>选取当前节点的父节点。</td>
</tr>
<tr>
<td>@</td>
<td>选取属性。</td>
</tr>
</tbody>
</table>
当节点元素谓语表单结构之内,使用xpath可以一次性定位所有节点,通过语句设置筛选条件达到获取表格中的任意节点元素,方便后期维护;此处有遇到表单结构过于大的那种可以考虑使用迭代器和生成器结合使用,从而减小内存消耗。
4)节点元素是非常规属性,请使用xpath;
eg:定位下面的<span>
标签所代表的节点元素
<div>
<h2>定位下面的"span"标签所代表的节点元素</h2>
<p>定位下面的"span"标签所代表的节点元素</p>
<span><?xml version="1.0" encoding="ISO-8859-1"?><bookstore><book><titlelang="eng">HarryPotter</title><price>29.99</price></book><book><titlelang="eng">LearningXML</title><price>39.95</price></book></bookstore>
</span>
</div>
//*[text()="定位下面的"span"标签所代表的节点元素"]//parent::*/pre
个人觉得其实css和xpath精通一种就够了,为啥呢,因为原理都是利用节点的属性和层级关系在构建定位节点元素的表达式;至于到底哪个好,看你个人了。