对于html来说,不管用什么浏览器打开,他的架构是不变的,所以对于编写自动化测试程序来说,基于什么浏览器开发,差异不大,所以这里推荐使用chrome 65或以后版本浏览器,之所以推荐这个浏览器,是因为它可以不用安装任何插件,就可以很方便的提供定位相关的功能。
chrome浏览器可以用F12调出调试窗口,用ctrl + F可以调出选择器和xpath搜索输入框,在搜索时可以显示搜索到结果的个数,如果搜索的结果个数比较多,说明对应的选择器或者xpath有问题,因为结果不唯一,除非希望保存的结果是一个集合。
一、CSS选择器定位
1.使用标签名查找元素
这个比较简单,但是基本上不会用。也就是说如果一个页面中该类型的标签只有一个,那么只要定位该标签就好了。比如一个页面中只有一个input标签,那么只要将这个个input用于定位就行了
2. 使用ID选择器查找元素
缺点:
a. 如果页面的ID不是惟一的,或者会动态变化,不太适合使用这个选择器
b. 如果ID是惟一的,但是对应元素的其他属性是变化的,比如name,text等会变化,也不太适合使用多条件判断
需要注意的是,在元素定位过程中,如果定位的元素不是惟一的,都是会出错的,除非查找的是多个元素组成的list
语法: tag[attribute='value']
tag就是html中的标签,可以是input,p, a等等
attribute标识属性,对应css选择器来说,它的属性是id或者class
value就是属性的值,一般用单引号包含
<div id="bdSug_1521883224738" class="bdSug_wpr" style="display: none;"></div>
比如需要定位这一行,可以使用:
#bdSug_1521883224738
div[id='bdSug_1521883224738']
div#bdSug_1521883224738
一般来说,一个DOM的ID都是惟一的,但是如果多个不同的标签使用了相同的ID,那么可以在定位的时候也指定标签,以保持定位惟一,这里需要注意的是,虽然在匹配id的时候可以不用完全匹配,但是在写代码的时候尽量完整
3. 使用类选择器查找元素
ID用点标识,class用#标识
(1)完全匹配
<div id="myCarousel" class="slide" data-ride="carousel">
#myCarousel 或 div[id='myCarousel'] 或 div#myCarousel
.slide 或 div[class='slide'] 或 div.slide
<div class="carousel-item csdn-tracking-statistics" data-mod="popu_465" data-dsm="post">
div[class='carousel-item csdn-tracking-statistics']
这里需要注意的是,class这种写法并不支持部分匹配,如果上式写成div[class='carousel-item']将会定位失败,即使少个尾部空格也不行。
这种写法要求写出标签中的所有class完整值
(2)部分匹配
那如果一个位置上包含多个class属性的时候应该怎么定位呢?可以使用追加属性的方法。
.carousel-item.csdn-tracking-statistics
这表示满足第一个class的同时满足第二个class属性的值。如果这还不能惟一定位,那就只好找相对定位的方法了
这种写法要求写出标签中的部分class完整值
(3)通配
上面两种匹配方式都要求用户在匹配class的时候使用完整的class属性值,但是通配可以做到更灵活的匹配
^表示文本开头
$表示文本结尾
*表示任意文本
语法: tag[attribute<wildcard>='value'] 其中wildcard表示通配符
<div class="carousel-inner" role="listbox">
<div class="carousel-item csdn-tracking-statistics" data-mod="popu_465" data-dsm="post">
<div class="carousel-item carousel-inner csdn-tracking-statistics" data-mod="popu_465" data-dsm="post">
如果要匹配这三行可以用 div[class^='carousel']
如果要匹配后面两行用 div[class$='statistics']
如果要匹配其中包含inner的行,用 div[class*='inner']
上面介绍了使用id和class进行定位,其实这并不是最厉害的,厉害的是这两个属性的定位方法可以拓展到其他属性上,比如:
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.imooc.com/">
可以使用 link[rel^='alt'] 进行定位
<meta name="mobile-agent" content="format=xhtml" ;="" url="https://m.imooc.com/">
使用 mata[name$='agent'] 定位
<a href="/" target="_self" title="首页"><img title="慕课网" src="/static/img/index/logo.png"></a>
使用 a[title='首页'] 定位
里面的img使用 img[title='慕课网'] 定位
4. 用CSS定位子节点
father>son[attribute='value']>grandson[attribute='value']
<div class="carousel-item csdn-tracking-statistics next left" data-mod="popu_465" data-dsm="post">
<a href="http://blog.csdn.net/dqcfkyqdxym3f8rb0/article/details/79643977" target="_blank">
<img src="//csdnimg.cn/feed/20180321/6c98086f1d03ee4f653afaab114f163e.jpg">
</a>
<a href="http://blog.csdn.net/dqcfkyqdxym3f8rb0/article/details/79643977" target="_blank">
<div class="carousel-caption">
机器学习大神迈克尔 · 乔丹:我讨厌将机器学习称为AI </div>
</a>
<a href="http://blog.csdn.net/dqcfkyqdxym3f8rb0/article/details/79643977" target="_blank" style="display:block;">
<div class="cover"></div>
</a>
</div>
定位子节点也可以叫相对定位,也就是说在用CSS定位时,有些元素不能通过一次性直接完成定位,需要通过定位其惟一的父节点,然后再相对定位到子节点上。其中比较常见的有table,list以及一些并列的元素。
比如对于上面这些<a>标签是并列的,如果要定位第二个<a>标签可以用 div > a > .carousel-caption
二、XPATH定位
一般来说上面的定位方法不够用的时候,就会拿出终极武器xpath进行定位了,因为xpath定位并不需要它的属性是惟一的,或者是固定不变的,不管在哪里,它总能找到它。
1. 基本语法
语法: //tag[@attribute='vale'] 有没有发现,xpath定位的时候,属性的前面多一个@
xpath的语法就不介绍了,可以网上查查,这里主要说明几个:
/ 表示父节点的下一个节点
// 表示父节点的下面某个节点
* 用于通配标签名,切记不要用来通配节点路径
div > p > li > a > span
p > li
h > a
比如有这样一个html层级嵌套结构,div下面有三个p标签, 如果父节点是 div,那么 div/ 后面接的只能是 p或者h标签, div// 后面接的可以是除div意外的任意一个标签。以下这些写法是对的:
//div/p/li
//div/h/a
//div//li//span
这种写法是错的: //div/a //div/p/span
2. 用text和contains构建xpath
语法: 完全匹配 //tag[text()='value']
部分匹配 //tag[contains(attribute, 'value')]
<ul class="nav-item">
<li class="set-btn visible-xs-block js-header-avator"><a href="/u/1372187" target="_self"><img width="40" height="40" src="//img4.mukewang.com/5333a2320001acdd02000200-100-100.jpg"></a></li>
<li>
<a href="/course/list" target="_self">免费课程</a>
</li>
<li><a href="//class.imooc.com" class="program-nav " target="_self">职业路径<i class="icn-new"></i></a></li>
<li>
<a href="//coding.imooc.com" target="_self">实战</a>
</li>
<li><a href="/wenda" target="_self">猿问</a></li>
<li><a href="/article" target="_self">发现</a></li>
<li class="visible-xs-block"><a href="/user/setprofile" target="_self">我的设置</a></li>
<li class="visible-xs-block"><a href="/passport/user/logout?referer=//www.imooc.com" target="_self">退出</a></li>
</ul>
比如要定位text为“发现”这个标签,可以用 //ul//a[text()='发现'] 进行定位, 但是text的内容必须完整的写过来
当然也可以使用部分匹配: //a[contains(text(), '免费')] 用于匹配在a标签种text带有‘免费’的位置
也可以判断其他属性的值是否包含关键字:
//a[contains(@class, 'program')] //a[contains(@href, 'article')]
不仅如此,它还支持多条件合并:
<a href="/wenda/detail/383123" target="_blank" class="wenda-tit">【有奖问答】与大咖交流前端JS与框架开发,免费赢取前端图书(11.28-12.4)</a>
它可以用多个条件进行定位: //a[contains(@href, 'detail')
and contains(@class, 'tit')
and contains(text(), '大咖')]
3. 用starts-with构建xpath
语法: //tag[starts-with(attribute, 'value')] 查找属性值以value开头的位置
<a href="/wenda/detail/383123" target="_blank" class="wenda-tit">【有奖问答】与大咖交流前端JS与框架开发,免费赢取前端图书(11.28-12.4)</a>
//a[starts-with(text(), '【有奖问答】')]
//a[starts-with(@class, 'wenda')]
//a[starts-with(@href, '/wenda')]
4. 查找父节点、前面平级节点、后面平级节点
父节点 = //parent::<tag>
前面平级节点 = //preceding-sibling::<tag>
后面平级节点 = //following-sibling::<tag>
<ul class="nav-item">
<li class="set-btn visible-xs-block js-header-avator"><a href="/u/1372187" target="_self"><img width="40" height="40" src="//img4.mukewang.com/5333a2320001acdd02000200-100-100.jpg"></a></li>
<li>
<a href="/course/list" target="_self">免费课程</a>
</li>
<li><a href="//class.imooc.com" class="program-nav " target="_self">职业路径<i class="icn-new"></i></a></li>
<li>
<a href="//coding.imooc.com" target="_self">实战</a>
</li>
<li><a href="/wenda" target="_self">猿问</a></li>
<li><a href="/article" target="_self">发现</a></li>
<li class="visible-xs-block"><a href="/user/setprofile" target="_self">我的设置</a></li>
<li class="visible-xs-block"><a href="/passport/user/logout?referer=//www.imooc.com" target="_self">退出</a></li>
</ul>
父节点:
ul_xpath = "//a[text()= '职业路径']//parent::li//parent::ul"
父节点应该会比较好理解,但是前平级节点和后平级节点可能会不好理解,它的意思就是,基于当前节点,往前的平级节点,或者往后的平级节点。
前面平级节点:
第一个和第二个<li>标签 = "//a[text()= '职业路径']//parent::li//preceding-sibling::li"
第一个<li>标签 = "//a[text()= '职业路径']//parent::li//preceding-sibling::li[1]"
第二个<li>标签 = "//a[text()= '职业路径']//parent::li//preceding-sibling::li[2]"
后面平级节点:
第一个和第二个<li>标签 = "//a[text()= '职业路径']//parent::li//following-sibling::li"
第四个<li>标签 = "//a[text()= '职业路径']//parent::li//following-sibling::li[1]"
第五个<li>标签 = "//a[text()= '职业路径']//parent::li//following-sibling::li[2]"
关于定位的,到这里基本上就够了,这里总结一下吧,在定位的时候:
如果id是惟一的,用id定位最快;
如果name或其他属性是惟一的,则用其他属性;
如果上面不行,则用CSS的组合选择器定位;
最终没招了,用xpath吧!!
但是,这也不是绝对的,具体问题具体分析吧!在我看来,只要哪些定位方式受html变动影响比较小的,或者即使变了也不会影响定位的,这种定位方式是优先选择的,对于自动化测试,并不要求代码能执行多快,应该多保证这些代码怎么能够提高通用性、拓展性以及项目间的可移植性。