【WEB自动化】【第一节】【Xpath和CSS元素定位】

目前自动化测试开始投入WEB测试,使用RF及其selenium库,模拟对WEB页面进行操作,此过程中首先面对的问题就是对WEB页面元素的定位,几乎所有的关键字都需要传入特定的WEB页面元素,因此掌握常用的WEB元素定位方法是WEB测试人员最基本的技能。本文主要结合个人在实践中的应用,将常用的XPATHCSS的元素定位方法进行汇总和总结,以便于引导WEB测试人员快速入门。

1. HTML基础知识

前端页面主要使用HTML进行元素排版,使用CSS进行样式设计,使用JS实现交互。在WEB测试中,熟悉HTML文档基本架构对后续的元素定位是不可或缺的。

一张图展示HTML基本架构:

 

HTML 的结构就是树形结构,HTML 是根节点,所有的其他元素节点都是从根节点发出的。其他的元素都是这棵树上的节点Node,每个节点还可能有属性和文本。而路径就是指某个节点到另一个节点的路线。

节点之间存在各种关系:

  • 父节点(Parent)HTML body head 节点的父节点;
  • 子节点(Child)head body HTML 的子节点;
  • 兄弟节点(Sibling):拥有相同的父节点,head body 就是兄弟节点。title div 不是兄弟,因为他们不是同一个父节点。
  • 祖先节点(Ancestor)body form 的祖先节点,爷爷辈及以上
  • 后代节点(Descendant)form HTML 的后代节点,孙子辈及以下

更多的HTML知识需要查阅相关资料和书籍。

2. XPATH方式进行WEB元素定位

 2.1 XPATH基本定位语法

定位语法主要依赖于以下特殊符号:

表达式

说明

举例

/

从根节点开始选取

/html/div/span

//

从任意节点开始选取

//input

.

选取当前节点

 

..

选取当前节点的父节点

//input/.. 会选取 input 的父节点

@

选取属性,或者根据属性选取

//input[@data] 选取具备 data 属性的 input 元素
//@data 选取所有 data 属性

*

通配符,表示任意节点或任意属性

 

 

2.2 绝对路径:

Xpath 中最直观的定位策略就是绝对路径。可以通过浏览器的开发者工具copyWEB元素的绝对路径,绝对路径是从根节点/html开始往下,一层层的表示出来直到需要的节点为止。以监控平台的WEB首页的登录按钮为例:

/html/body/div[2]/div/div[2]/form/div[5]/a[2]/span

这就是一个绝对路径。

2.3 相对路径:

除了绝对路径,Xpath 中更常用的方式是相对路径定位方法,以“//”开头。相对路径可以从任意节点开始,一般我们会选取一个可以唯一定位到的元素开始写,可以增加查找的准确性。

//a[@onclick="doLogin();return false;"]/span


2.4 元素属性定位

属性定位是通过 @ 符号指定需要使用的属性。

根据元素是否具备某个属性查找元素://a[@onclick]

根据属性是否等于某值查找元素://a[@onclick="doLogin();return false;"]

注意,属性值必须要加引号,单双引号都可以。

实践中最为常用的属性当属idnameclass了,且前两个属性一般作为元素的唯一标示符使用,因此通过idname属性进行元素定位,通常表示式简单且运行速度快。

例如定位WEB首页中的用户名输入框和密码输入框,可用id进行定位:

//input[@id="loginname"]

//input[@id="loginpsw"]

 

2.5 层级属性结合定位

遇到某些元素无法精确定位的时候,可以查找其父级及其祖先节点,找到有确定的祖先节点后通过层级依次向下定位。

根据层级向下找://div/a[@onclick="doLogin();return false;"]/span

查找某元素内部的所有元素://div//a[@onclick]

第二个双斜杠,表示选取内部所有的满足条件的a,不关心层级关系。

使用星号找不特定的元素://*[@*="doLogin();return false;"],这里会找到登录按钮。

使用..从下往上找,根据子节点查找其父节点://span[text()="Login"]/..

注意最后的两个点,找到 span 节点的上级节点,如果还要再往上再加 /..

找同级节点://span[text()="Login"]/../../a
    树形结构中,兄弟节点之间的关系是通过父节点建立起来的。所以可以先找到父节点,再通过父节点找同级节点。

 

2.6 使用谓语定位

谓语是 Xpath 中用于描述元素位置的语句。主要有数字下标、最后一个子元素last()、元素下标函数position()
    ①使用下标的方式:此处有坑,见疑难问题解决。

注意:Xpath 中的下标从 1 开始。

②查找最后一个子元素://form/div[last()]

③查找倒数第2个子元素://form/div[last()-1]

④使用 position() 函数,选取 from 下第2div//form/div[position()=2]

⑤使用 position() 函数,选取form下下标大于2div//form/div[position()>2]或//form/div[position()>=3]

 

2.7 使用逻辑运算符

如果元素的某个属性无法精确定位到这个元素,我们还可以用逻辑运算符 and or 连接多个属性进行定位,也可以用 | 连接多个路径

①使用 and //input[@id="loginname" and @type="text"]

②使用 or //span[text()="Login" or text()="登录"]

③使用 | //input[@id="loginname"] | //input[@id="loginpsw"]

 

2.8 使用文本定位

使用文本定位,是 Xpath 中的一大特色。在自动化测试中,为了让代码的可读性更高,可以使用文本的方式需要用到 Xpath 中的函数 text() string() ,注意是函数,所以括号不能少。

text():当前元素节点包含的文本内容,而不会包含节点元素的文本内容

string():当前元素节点内部所有节点元素的文本内容,如有多个节点元素包含多个文本内容,则按层级顺序将各节点元素的文本内容进行拼接后返回

例如,我们的WEB首页中,登录按钮元素周围的HTML代码如下:

    <a href="#" onclick="doLogin();return false;" style="float: right;color: white;">

        <span>Login</span>

        <i class="icon-circle-arrow-right"></i>

    </a>

 

text()方法://span[text()="Login"]能定位到按钮区域,//a[text()="Login"]则不能;

string()方法://span[string()="Login"]和//a[string()="Login"]均能定位到按钮区域。

 

2.9 使用部分匹配函数

Xpath中提供了几个函数,用来进行部分匹配。

函数

说明

举例

contains

选取属性或者文本包含某些字符

//div[contains(@id, 'data')] 选取 id 属性包含 data div 元素
//div[contains(string(), '支付宝')] 选取内部文本包含支付宝div 元素

starts-with

选取属性或者文本以某些字符开头

//div[starts-with(@id, 'data')] 选取 id 属性以 data 开头的 div 元素
//div[starts-with(string(), '银联')] 选取内部文本以银联开头的 div 元素

ends-with

选取属性或者文本以某些字符开头

//div[ends-with(@id, 'require')] 选取 id 属性以 require 结尾的 div 元素
//div[ends-with(string(), '支付')] 选取内部文本以支付结尾的 div 元素


    其中,ends-with()仅在xpath2.0中支持,而目前RFselenium库、chrome浏览器都只支持xpath1.0,以查找WEB首页的密码输入框元素(包含id"loginpsw")为例:

//*[contains(@id, "loginpsw")]        能匹配到

//*[starts-with(@id, "loginpsw")]    能匹配到

//*[ends-with(@id, "loginpsw")]       不能匹配到

//*[substring(@id, string-length(@id) - string-length('loginpsw') +1) = 'loginpsw']   能匹配到,实现了ends-with功能

 

2.10 实践中疑难问题解决:

①通过Xpath查找某个节点下某一级下的子节点,而不关注具体层级:

//div[@id="hisevent"]//button[@id="event_searchBT"]  查找指定div下任一子级的特定button(使用//

②通过Xpath如何获取文档中第几个匹配节点://name[3]表示所有位置3name(//name)[3]才是你要的,所有name的第3个。

(//div[@id="hisevent"]//input)[2]

//div[@id="hisevent"]//input[position()=2]

需要在所有匹配中定位时,先用()括起来,或使用postion()函数。

③通过xpath由子节点元素查找父节点元素或祖先节点:

//a[span[text()="Login"]]

//div[@id="hisevent"]//table[tbody[contains(@id, "list")]]

 

参考:https://www.jianshu.com/p/6a0dbb4e246a

      https://www.cnblogs.com/hanmk/p/8997786.html

 

3. CSS方式进行WEB元素定位

3.1 CSS选择器基础知识

CSS选择器分4大类:基本选择器、属性选择器、伪类选择器、伪元素选择器。

注意:选择器总是从左至右解析,不要私自添加()优先运算

其中基本选择器主要包括以下四类符号:

1) 标签选择器:使用标签名称进行标识,如divap

2) ID选择器:使用#进行标识;

3) 类选择器:使用.进行标识;

4) 通配符选择器:使用*进行标识。

其余属性选择器、伪类选择器、伪元素选择器都可归为扩展选择器。

选择器

例子

例子描述

CSS版本

选择器分类

.class

.intro

选择 class="intro" 的所有元素。

1

基本选择器

#id

#firstname

选择 id="firstname" 的所有元素。

1

基本选择器

*

*

选择所有元素。

2

基本选择器

element

p

选择所有 <p> 元素。

1

基本选择器

element,element

div,p

选择所有 <div> 元素和所有 <p> 元素。

1

基本选择器

element element

div p

选择 <div> 元素内部的所有 <p> 元素。

1

基本选择器

element>element

div>p

选择父元素为 <div> 元素的所有 <p> 元素。

2

基本选择器

element+element

div+p

选择紧接在 <div> 元素之后的所有 <p> 元素。

2

基本选择器

[attribute]

[target]

选择带有 target 属性所有元素。

2

属性选择器

[attribute=value]

[target=_blank]

选择 target="_blank" 的所有元素。

2

属性选择器

[attribute~=value]

[title~=flower]

选择 title 属性包含单词 "flower" 的所有元素。

2

属性选择器

[attribute|=value]

[lang|=en]

选择 lang 属性值以 "en" 开头的所有元素。

2

属性选择器

:link

a:link

选择所有未被访问的链接。

1

伪类选择器

:visited

a:visited

选择所有已被访问的链接。

1

伪类选择器

:active

a:active

选择活动链接。

1

伪类选择器

:hover

a:hover

选择鼠标指针位于其上的链接。

1

伪类选择器

:focus

input:focus

选择获得焦点的 input 元素。

2

伪类选择器

:first-letter

p:first-letter

选择每个 <p> 元素的首字母。

1

伪元素选择器

:first-line

p:first-line

选择每个 <p> 元素的首行。

1

伪元素选择器

:first-child

p:first-child

选择属于父元素的第一个子元素的每个 <p> 元素。

2

伪元素选择器

:before

p:before

在每个 <p> 元素的内容之前插入内容。

2

伪元素选择器

:after

p:after

在每个 <p> 元素的内容之后插入内容。

2

伪元素选择器

:lang(language)

p:lang(it)

选择带有以 "it" 开头的 lang 属性值的每个 <p> 元素。

2

伪元素选择器

element1~element2

p~ul

选择前面有 <p> 元素的每个 <ul> 元素。

3

基本选择器

[attribute^=value]

a[src^="https"]

选择其 src 属性值以 "https" 开头的每个 <a> 元素。

3

属性选择器

[attribute$=value]

a[src$=".pdf"]

选择其 src 属性以 ".pdf" 结尾的所有 <a> 元素。

3

属性选择器

[attribute*=value]

a[src*="abc"]

选择其 src 属性中包含 "abc" 子串的每个 <a> 元素。

3

属性选择器

:first-of-type

p:first-of-type

选择属于其父元素的首个 <p> 元素的每个 <p> 元素。

3

伪元素选择器

:last-of-type

p:last-of-type

选择属于其父元素的最后 <p> 元素的每个 <p> 元素。

3

伪元素选择器

:only-of-type

p:only-of-type

选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。

3

伪元素选择器

:only-child

p:only-child

选择属于其父元素的唯一子元素的每个 <p> 元素。

3

伪元素选择器

:nth-child(n)

p:nth-child(2)

选择属于其父元素的第二个子元素的每个 <p> 元素。

3

伪元素选择器

:nth-last-child(n)

p:nth-last-child(2)

同上,从最后一个子元素开始计数。

3

伪元素选择器

:nth-of-type(n)

p:nth-of-type(2)

选择属于其父元素第二个 <p> 元素的每个 <p> 元素。

3

伪元素选择器

:nth-last-of-type(n)

p:nth-last-of-type(2)

同上,但是从最后一个子元素开始计数。

3

伪元素选择器

:last-child

p:last-child

选择属于其父元素最后一个子元素每个 <p> 元素。

3

伪元素选择器

:root

:root

选择文档的根元素。

3

伪类选择器

:empty

p:empty

选择没有子元素的每个 <p> 元素(包括文本节点)。

3

伪类选择器

:target

#news:target

选择当前活动的 #news 元素。

3

伪类选择器

:enabled

input:enabled

选择每个启用的 <input> 元素。

3

伪类选择器

:disabled

input:disabled

选择每个禁用的 <input> 元素

3

伪类选择器

:checked

input:checked

选择每个被选中的 <input> 元素。

3

伪类选择器

:not(selector)

:not(p)

选择非 <p> 元素的每个元素。

3

伪类选择器

::selection

::selection

选择被用户选取的元素部分。

3

伪类选择器

 

参考:https://www.w3school.com.cn/cssref/css_selectors.ASP

      https://blog.csdn.net/luanpeng825485697/article/details/76935715

      https://blog.csdn.net/DYD850804/article/details/80997251

 

3.2 CSS选择器实战

下面以WEB的历史操作记录页面为例进行实践。

 

直接给出查找此页面中结束时间选框的定位语句,再进行分析:

div#hisevent input.form-control.input-medium[type="text"][onfocus*="WdatePicker"]:nth-child(2)

(可在文本编辑器放大查看)

①先从任意div标签的元素出发查找,直到其具备id属性(#)值为hisevent

②查找①的div元素内部的input标签元素,使用空格进行隔离。此处需要注意,关于标签层级,CSS有两个最基本的查找语法:ele1>ele2ele1 ele2,类似于Xpath///,前者代表ele1ele2为父子节点关系,后者代表ele1内部包含ele2,而不在乎具体层级;

③查找的input元素须包含值为"form-control input-medium"的类(class)属性,使用圆点进行标识。这里注意,该元素的class的值中包含一个空格,在选择器表达式里,空格已经有了具体含义;在书写包含空格的class属性时,直接将空格替换为圆点即可事实上class属性值中的空格表示此元素能匹配多个class样式表,即样式复用,同时具有先后关系。参考:

https://blog.csdn.net/liuhehe123/article/details/81608225

https://www.cnblogs.com/guxin/p/css-multi-class-selector.html

④在找到包含指定类的input标签元素后,进一步通过属性进行筛选,最基础的表达式为[name=value],实践中发现value用不用引号包围均可;如果想通过多个属性(“与”的关系)来精确定位元素,可以直接连接多个属性表达式,如[type="text"][onfocus*="WdatePicker"]。参考:

https://cloud.tencent.com/developer/ask/27977

⑤通过以上一番操作,定位到的元素仍然有两个,分别是起始时间框和结束时间框,二者位于同一级,是兄弟节点关系,要定位到第二个节点,使用:nth-child(2)即可,其原意为归属于父节点的第n个子节点。对同级节点定位方法参考:

https://blog.csdn.net/hcwbr123/article/details/80846862

 

3.3 实践中疑难问题解决:

①属性选择器部分匹配:~= |= *= ^= $= 的区别:

 ~= 、|= 按完整单词进行匹配,完整单词指整个的单词、以空格或-分隔的单词;

 *= ^= $= 按字符串进行匹配,显然此类方法更易用且更常用。举例

div#hisevent button[onclick^='do'][onclick$='()'][onclick*='Eventsearch']

此句意为:包含属性onclick的值以do开头、以()结尾、含Eventsearch子串的button

②通过ele1,ele2可以“或”方式获取多个元素,如何以“或”方式进行多个属性的模糊匹配?如在①中,想以“或”方式匹配多个属性语句?

③通过元素文本定位元素:此路不通!Content selectors were deprecated! No more content selectors since CSS3. :contains() was dropped.

④通过子元素找父元素:目前似乎还不支持!有一个CSS伪类 :has() 支持这个功能,但还处于草案阶段。

 

4. 实践验证

验证XpathCSS元素定位语句,可使用浏览器的开发者工具辅助:

在开发者工具的Elements中按Ctrl + F,在搜索框中输入Xpath或CSS语句;

在开发者工具的Console中使用 $x()和$()$x()传入Xpath语句,$()传入CSS语句,注意,元素定位(或称查找、选择器)语句需要使用单引号或双引号包围

 

posted @ 2020-05-08 16:34  小黄鱼的圈子  阅读(479)  评论(0编辑  收藏  举报