pythonUI自动化之Xpath元素定位003
前言:
元素定位有很多种方式,id、class、css等等,但为了系统的稳定性,后续少维护代码,使用Xpath是明智的方法。
我们在找属性时,注意尽量找不会发生产变动,具有唯一的标签。
Xpath分为(绝对路径)和(相对路径),两个方法各有千秋:
(绝对路径)定位:根据元素的位置来定位元素,缺点是元素位置发生变动,维护工作量巨大。不建议的大量使用
(相对路径)定位:根据元素的唯一特征来定位,支持逻辑运算。相对于(绝对路径)后期维护工作量小。可广泛应用至自动化中。
以下是Xpath 表达式的作用符号。需要注意的是/如果是放在最前面,表示根节点,如果不是,则表示下一节点。
这里已“百度一下”按钮为例演示,首先是xpath语法的标准格式://标签名[@属性名=属性值]
首先按F12调出开发者模式,然后按Ctrl+F进入查询模式。在下图中,input是标签名,value是属性名,“百度一下”是属性值。
所以最简单的语法便是://input[@value="百度一下"]
接下来我们来升级一下语法:逻辑运算格式,可以使用and之外还可以使用or
//*[@属性名=属性值 and @属性名=属性值] #*是代表匹配所有标签,不建议使用。
//input[@属性名=属性值 or @属性名=属性值]
XPath提供了多种比较运算符,如 =(等于)、!=(在XPath 2.0及更高版本中)、//book[not(@price=35)](旧版1.0版本中)、<(小于)、<=(小于或等于)、>(大于)和>=(大于或等于)。但是,请注意,并非所有XPath处理器都支持XPath 2.0或更高版本,其中!=是在XPath 2.0中引入的。
在以上基础上加上文本定位:
格式://标签名[@属性名="属性值" and text()="文本"] #此为完全匹配
格式2://标签名[contains(text(),"部分文本内容")] #此为部分匹配。如果是app, 则需要加@,并且把括号去掉, 如//标签名[contains(@text,"部分文本内容")]
//标签名[contains(@属性名,"部分属性值")] #属性值部分匹配。
加上层级条件:
格式://父标签[@父属性名="父属性值"]//子标签[@子属性名="子属性值"] #中间的//意思是匹配以下所有标签,如果是/,则表示的是下一个节点标签。
加上同级条件:在上面的标签属于哥哥,在下面的标签属于弟弟。
定位的元素如果属于哥哥:preceding-sibling
//标签1[@属性名1="属性值1"]/preceding-sibling::标签2[@属性名2="属性值2"]
定位的元素如果属于弟弟:following-sibling
//标签1[@属性名1="属性值1"]/following-sibling::标签2[@属性名2="属性值2"]
由子节点定位父节点,示例://span[text()="子节点元素"]/..
轴定位
XPath轴(XPath Axes)可定义某个相对于当前节点的节点集:
1、child 选取当前节点的所有子元素
2、parent 选取当前节点的父节点
3、descendant 选取当前节点的所有后代元素(子、孙等)
示例://div[@id="aabbc"]/descendant::span[text()="订单"]
4、ancestor 选取当前节点的所有先辈(父、祖父等)
5、descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身
6、ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身
7、preceding-sibling 选取当前节点之前的所有同级节点
8、following-sibling 选取当前节点之后的所有同级节点
9、preceding 选取文档中当前节点的开始标签之前的所有节点
10、following 选取文档中当前节点的结束标签之后的所有节点
11、self 选取当前节点
12、attribute 选取当前节点的所有属性
13、namespace 选取当前节点的所有命名空间节点
descendant-or-self跟descendant类似,多了节点本身。
经验分享:
1. 下拉框:
可以先点击“下拉框”让它弹出选项,再对选项进行“点击”选取。这类操作在某些场景下依旧会出现定位不到,最保险的方法是 “点击”下拉框 > “输入”想要的值 > “点击”搜索出来的值。如果下拉框没有搜索功能,则只能模拟鼠标滑动事件来解决。
2. 关于窗口切换:
某些场景下,窗口切换是需要加上“等待时间”的,否则窗口会切换失败。原因是因为窗口句柄没有加载出来就切换了,但是加上固定等待时间会显示非常lou,你可以写一个循环语句来判断窗口是否切换成功,或者写一个try解释器。
如何切换窗口?
wid1 = wd.window_handles #获取所有窗口句柄
wd.switch_to.window(wid1[2]) #切换到最新的窗口句柄
#切换会旧窗口
driver.switch_to.window(self.driver.window_handles[1]) # 切换到新页签
driver.close() # 关闭当前新页签
driver.switch_to.window(self.driver.window_handles[0]) # 然后切换回原始页签
3. 关于iframe:
某些人分不清iframe和窗口的区别。 窗口相当于另一个浏览器页签,iframe是嵌套在html中的另一个页签。两者的定位方式都大同小异,都是得先切换到新页签,才能对页签里面的元素操作。
元素在不同“窗口”这很好判断,视觉上就可以判断出来。但是元素是否处于不同iframe却不好判断,虽然你看着两个按钮都在同一个界面,但他们可能并不同属一个iframe,你可以通过往下查看定位元素的父父...级元素,如果出现iframe,则说明当前定位元素出现别的iframe中。
如何切换iframe?
iframe=driver.find_elements_by_xpath(“//iframe[@id="123"]”) #定位iframe框架
driver.switch_to.frame(iframe) #切换到iframe框架
driver.find_elements_by_xpath(“//input[@id="123"]”).click() #对iframe里的元素操作
driver.switch_to.default_content() #退出iframe