对象(元素)的定位和操作是自动化测试的核心部分,其中操作又是建立在定位的基础上的,因此元
素定位就显得非常重要。 (本书中用到的对象与元素同为一个事物)
一个对象就像是一个人,他会有各种的特征(属性) ,如比我们可以通过一个人的身份证号、姓名或
者他的住址找到这个人。那么一个元素也有类似的属性,我们可以通过这种唯一区别于其它元素的属性来
定位这个元素。当然,除了要操作元素时需要定位元素外,有时候我们只是为了获得元素的属性(class 属
性,name 属性) 、text 或数量也需要定位元素。
webdriver 提供了一系列的元素定位方法,常用的有以下几种
 id
 name
 class name
 tag name
 link text
 partial link text
 xpath
 css selector
分别对应 python webdriver 中的方法为:
find_element_by_id()
find_element_by_name()
find_element_by_class_name()
find_element_by_tag_name()
find_element_by_link_text()
find_element_by_partial_link_text()
find_element_by_xpath()
find_element_by_css_selector()
2.1 id 和 name 定位
id 和 name 是我们最常用的定位方式,因为大多数元素都有这两个属性,而且在对控件的 id 和 name
命名时一般使其有意义也会取不同的名字。通过这两个属性使我们找一个页面上的属性变得相当容易。
<input id="gs_htif0" class="gsfi" aria-hidden="true" dir="ltr">
<input type="submit" name="btnK" jsaction="sf.chk" value="Google 搜索">
<input type="submit" name="btnI" jsaction="sf.lck" value=" 手气不错 ">
通过元素中所带的 id 和 name 属性对元素进行定位:
id=”gs_htif0”
find_element_by_id("gs_htif0")
name=”btnK”
find_element_by_name("btnK")
name=”btnI”
find_element_by_name("btnI")
2.2 tag name 和 class name 定位
不是所有的前端开发人员都喜欢为每一个元素添加 id 和 name 两个属性,但除此之外你一定发现了一
个元素不单单只有 id 和 name,它还有 class 属性;而且每个元素都会有标签。
<div id="searchform" class="jhp_big" style="margin-top:-2px">
<form id="tsf" onsubmit="return name="f" method="GET" action="/search">
<input id="kw" class="s_ipt" type="text" name="wd" autocomplete="off">
通过元素中带的 class 属性对元素进行定位:
class=”jhp_big”
find_element_by_class_name("jhp_big")
class=”s_ipt”
find_element_by_class_name("s_ipt")
通过 tag 标签名对对元素进行定位:
<div>
find_element_by_tag_name("div")
<form>
find_element_by_tag_name("form")
<input>
find_element_by_tag_name("input")
tag name 定位应该是所有定位方式中最不靠谱的一种了,因为在一个页面中具有相同 tag name 的元
素极其容易出现。
2.3 link text 与 partial link text 定位
有时候需要操作的元素是一个文字链接,那么我们可以通过 link text 或 partial link text 进行元素
定位。
<a href="http://news.baidu.com" name="tj_news">新 闻</a>
<a href="http://tieba.baidu.com" name="tj_tieba">贴 吧</a>
<a href="http://zhidao.baidu.com" name="tj_zhidao">一个很长的文字连接</a>
通过 link text 定位元素:
find_element_by_link_text("新 闻")
find_element_by_link_text("贴 吧")
find_element_by_link_text("一个很长的文字连接")
通 partial link text 也可以定位到上面几个元素:
find_element_by_partial_link_text("新")
find_element_by_partial_link_text("吧")
find_element_by_partial_link_text("一个很长的")
当一个文字连接很长时,我们可以只取其中的一部分,只要取的部分可以唯一标识元素。一般一个页
面上不会出现相同的文件链接,通过文字链接来定位元素也是一种简单有效的定位方式。
下面介绍 xpath 与 CSS 定位相比上面介绍的方式来说比较难理解,但他们的灵活性与定位能力比上
面的方式要强大。
2.4 XPath 定位
XPath 是一种在 XML 文档中定位元素的语言。因为 HTML 可以看做 XML 的一种实现,所以 selenium 用
户可是使用这种强大语言在 web 应用中定位元素。
XPath 扩展了上面 id 和 name 定位方式,提供了很多种可能性,比如定位页面上的第三个多选框。
<html class="w3c">
<body>
<div class="page-wrap">
<div id="hd" name="q">
<form target="_self" action="http://www.so.com/s">
<span id="input-container">
<input id="input" type="text" x-webkit-speech="" autocomplete="off"
suggestwidth="501px" >
我们看到的是一个有层级关系页面,下面我看看如果用 xpath 来定位最后一个元素。
用绝对路径定位:
find_element_by_xpath("/html/body/div[2]/form/span/input")
当我们所要定位的元素很难找到合适的方式时,都可以通这种绝对路径的方式位,缺点是当元素在很
多级目录下时,我们不得不要写很长的路径,而且这种方式难以阅读和维护。
相对路径定位:
find_element_by_xpath("//input[@id=’input’]") #通过自身的 id 属性定位
find_element_by_xpath("//span[@id=’input-container’]/input") #通过上一级目录的id属性定位
find_element_by_xpath("//div[@id=’hd’]/form/span/input") #通过上三级目录的 id 属性定位
find_element_by_xpath("//div[@name=’q’]/form/span/input")#通过上三级目录的 name 属性定位
通过上面的例子,我们可以看到 XPath 的定位方式非常灵活和强大的,而且 XPath 可以做布尔逻辑运
算,例如://div[@id=’hd’ or @name=’q’]
当然,它的缺陷也非常明显:1、性能差,定位元素的性能要比其它大多数方式差;2、不够健壮,XPath
会随着页面元素布局的改变而改变;3. 兼容性不好,在不同的浏览器下对 XPath 的实现是不一样的。
通过我们第一章中介绍的 firebug 的 HTML 和 firePath 可以非常方便的通过 XPath 方式对页面元素进
行定位。
打开 firefox 浏览器的 firebug 插件,点击插件左上角的鼠标箭头,再点击页面上的元素,firebug
插件的 HTML 标签页将看到页面代码,鼠标移动到元素的标签上(如图图3.1,<imput>)将显示当前元素的
绝对路径。

图3.1
/html/body/div[5]/div/div/from/input
或者直接在元素上右击弹出快捷菜单,选择 Copy XPath,将当前元素的 XPath 路径拷贝要脚本
本中(如图3.2) 。

图3.2
firePath 工具的使用就更加方便和快捷了,选中元素后,直接在 XPath 的输入框中显示当前元素的
XPath 的定位信息(如图3.3) 。

图3.3
3.2.5 CSS 定位
CSS(Cascading Style Sheets)是一种语言,它被用来描述 HTML 和 XML 文档的表现。CSS 使用选
择器来为页面元素绑定属性。这些选择器可以被 selenium 用作另外的定位策略。
CSS 可以比较灵活选择控件的任意属性,一般情况下定位速度要比 XPath 快,但对于初学者来说比较
难以学习使用,下面我们就详细的介绍 CSS 的语法与使用。
CSS 选择器的常见语法:
* 通用元素选择器,匹配任何元素
E 标签选择器,匹配所有使用 E 标签的元素
.info class 选择器,匹配所有 class 属性中包含 info 的元素
#footer id 选择器,匹配所有 id 属性等于 footer 的元素
E,F 多元素选择器,同时匹配所有 E 元素或 F 元素,E 和 F 之间用逗号分

E F 后代元素选择器,匹配所有属于 E 元素后代的 F 元素,E 和 F 之间用
空格分隔
E > F 子元素选择器,匹配所有 E 元素的子元素 F
E + F 毗邻元素选择器,匹配紧随 E 元素之后的同级元素 F (只匹配第一
个)
E ~ F 同级元素选择器,匹配所有在 E 元素之后的同级 F 元素
E[att='val'] 属性 att 的值为 val 的 E 元素 (区分大小写)
E[att^='val'] 属性 att 的值以 val 开头的 E 元素 (区分大小写)
E[att$='val'] 属性 att 的值以 val 结尾的 E 元素 (区分大小写)
E[att*='val'] 属性 att 的值包含 val 的 E 元素 (区分大小写)
E[att1='v1'][att2*='v2'] 属性 att1 的值为 v1,att2 的值包含 v2 (区分大小写)
E:contains('xxxx') 内容中包含 xxxx 的 E 元素
E:not(s) 匹配不符合当前选择器的任何元素
例如下面一段代码:
<div class="formdiv">
<form name="fnfn">
<input name="username" type="text"></input>
<input name="password" type="text"></input>
<input name="continue" type="button"></input>
<input name="cancel" type="button"></input>
<input value="SYS123456" name="vid" type="text">
<input value="ks10cf6d6" name="cid" type="text">
</form>
<div class="subdiv">
<ul id="recordlist">
<p>Heading</p>
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>
</div>
</div>
通过 CSS 语法进行匹配的实例:
locator 匹配
css=div
css=div.formdiv
<div class="formdiv">
css=#recordlist
css=ul#recordlist
<ul id="recordlist">
css=div.subdiv p
css=div.subdiv > ul > p
<p>Heading</p>
css=form + div <div class="subdiv">
css=p + li
css=p ~ li
二者定位到的都是 <li>Cat</li>
但是 storeCssCount 的时候,前者得到 1,后者得到 4
css=form > input[name=username] <input name="username">
css=input[name$=id][value^=SYS] <input value="SYS123456" name="vid" type="hidden">
css=input:not([name$=id][value^=SYS]) <input name="username" type="text"></input>
css=li:contains('Goa') <li>Goat</li>
css=li:not(contains('Goa')) <li>Cat</li>
css 中的结构性定位
结构性定位就是根据元素的父子、同级中位置来定位,css3标准中有定义一些结构性定位伪类如
nth-of-type,nth-child,但是使用起来语法很不好理解,这里就不做介绍了。
Selenium 中则是采用了来自 Sizzle 的 css3定位扩展,它的语法更加灵活易懂。
Sizzle Css3的结构性定位语法:
E:nth(n)
E:eq(n)
在其父元素中的 E 子元素集合中排在第 n+1 个的 E 元素 (第一个 n=0)
E:first 在其父元素中的 E 子元素集合中排在第 1 个的 E 元素
E:last 在其父元素中的 E 子元素集合中排在最后 1 个的 E 元素
E:even 在其父元素中的 E 子元素集合中排在偶数位的 E 元素 (0,2,4…)
E:odd 在其父元素中的 E 子元素集合中排在奇数的 E 元素 (1,3,5…)
E:lt(n) 在其父元素中的 E 子元素集合中排在 n 位之前的 E 元素 (n=2,则匹配 0,1)
E:gt(n) 在其父元素中的 E 子元素集合中排在 n 位之后的 E 元素 (n=2, 在匹配 3,4)
E:only-child 父元素的唯一一个子元素且标签为 E
E:empty 不包含任何子元素的 E 元素,注意,文本节点也被看作子元素
例如下面一段代码:
<div class="subdiv">
<ul id="recordlist">
<p>Heading</p>
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>
</div>
匹配示例:
locator 匹配
css=ul > li:nth(0) <li>Cat</li>
css=ul > *:nth(0)
css=ul > :nth(0)
<p>Heading</p>
css=ul > li:first <li>Cat</li>
css=ul > :first <p>Heading</p>
css=ul > *:last
css=ul > li:last
<li>Goat</li>
css=ul > li:even Cat, Car
css=ul > li:odd Dog, Goat
css=ul > :even <p>Heading</p>
css=ul > p:odd [error] not found
css=ul > li:lt(2) <li>Cat</li>
css=ul > li:gt(2) <li>Goat</li>
css=ul > li:only-child
css=ul > :only-child
css=ul > *:only-child
[error] not found (ul 没有 only-child)
css=div.subdiv > :only-child <ul id="recordlist">
… … … …
</ul>
Sizzle Css3还提供一些直接选取 form 表单元素的伪类:
:input: Finds all input elements (includes textareas, selects, and buttons).
:text, :checkbox, :file, :password, :submit, :image, :reset, :button: Finds the input element
with the specified input type (:button also finds button elements).
下面是一些 XPATH 和 CSS 的类似定位功能比较(缺乏一定的严谨性) 。
定位方式 XPath CSS
标签 //div div
By id //div[@id='eleid'] div#eleid
By class //div[@class='eleclass']
//div[contains(@class,'eleclass')]
div.eleclass
By 属性 //div[@title='Move mouse here'] div[title=Move mouse here]
div[title^=Move]
div[title$=here]
div[title*=mouse]
定位子元素 //div[@id='eleid']/*
//div/h1
div#eleid >*
div#eleid >h1
定位后代元素 //div[@id='eleid']//h1 div h1
By index //li[6] li:nth(5)
By content //a[contains(.,'Issue 1164')] a:contains(Issue 1164)
通过对比,我们可以看到,CSS 定位语法比 XPath 更为简洁,定位方式更多灵活多样;不过对 CSS 理
解起来要比 XPath 较难;但不管是从性能还是定位更复杂的元素上,CSS 优于 XPath,笔者更推荐使用 CSS
定位页面元素。
关于自动化的定位问题
自动化测试的元素定位一直是困扰自动化测试新手的一个障碍,因为我们在自动化实施过程中会碰到
各式各样的对象元素。虽然 XPath 和 CSS 可以定位到复杂且比较难定位的元素,但相比较用 id 和 name 来
说增加了维护成本和学习成本,相比较来说 id/name 的定位方式更直观和可维护,有新的成员加入的自动
化时也增加了人员的学习成本。所以,测试人员在实施自动化测试时一定要做好沟通,规范前端开发人员
对元素添加 id/name 属性,或者自己有修改 HTML 代码的权限。

转:python webdriver API 之简单对象的定位的更多相关文章

  1. 转:python webdriver API 之操作测试对象

    一般来说,所有有趣的操作与页面交互都将通过 WebElement 接口,包括上一节中介绍的对象定位,以及本节中需要介绍的常对象操作.webdriver 中比较常用的操作元素的方法有下面几个: cle ...

  2. 转:python webdriver API 之鼠标事件

    前面例子中我们已经学习到可以用 click()来模拟鼠标的单击操作,而我们在实际的 web 产品测试中 发现,有关鼠标的操作,不单单只有单击,有时候还要和到右击,双击,拖动等操作,这些操作包含在Act ...

  3. 转:python webdriver API 之定位一组对象

    webdriver 可以很方便的使用 find_element 方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,WebElement 接口同样提供了定位一组元素的方法 find_eleme ...

  4. 转:python webdriver API 之定位 frame 中的对象

    在 web 应用中经常会出现 frame 嵌套的应用,假设页面上有 A.B 两个 frame,其中 B 在 A 内,那么定位 B 中的内容则需要先到 A,然后再到 B.switch_to_frame  ...

  5. 转:python webdriver API 之层级定位

    在实际的项目测试中,经常会有这样的需求:页面上有很多个属性基本相同的元素 ,现在需要具体定位到其中的一个.由于属性基本相当,所以在定位的时候会有些麻烦,这时候就需要用到层级定位.先定位父元素,然后再通 ...

  6. 转:python webdriver API 之调用 JavaScript

    当 webdriver 遇到没法完成的操作时,笔者可以考虑借用 JavaScript 来完成,比下下面的例子,通过 JavaScript 来隐藏页面上的元素.除了完成 webdriver 无法完成的操 ...

  7. 转:python webdriver API 之 获取对象的属性

    获取测试对象的属性能够帮我们更好的进行对象的定位.比如页面上有很多标签为 input 元素,而我们需要定位其中 1 个有具有 data-node 属性不一样的元素.由于 webdriver 是不支持直 ...

  8. 转:python webdriver API 之下载文件

    webdriver 允许我们设置默认的文件下载路径.也就是说文件会自动下载并且存在设置的那个目录中.要想下载文件,首选要先确定你所要下载的文件的类型.要识别自动文件的下载类型可以使用 curl ,如图 ...

  9. 转:python webdriver API 之上传文件

    文件上传操作也比较常见功能之一,上传功能操作 webdriver 并没有提供对应的方法,关键上传文件的思路.上传过程一般要打开一个系统的 window 窗口,从窗口选择本地文件添加.所以,一般会卡在如 ...

随机推荐

  1. Lazarus中system.length说明

    在system单元中我们有Length专门用来获取字符串宽度和数组宽度,下面例子来介绍他的功能. 定义: function Length(   S: AStringType ):Integer; fu ...

  2. html5之canvas初解

    <canvas> 元素本身并没有绘制能力(它仅仅是图形的容器) - 必须使用脚本来完成实际的绘图任务. getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属 ...

  3. C++ 中static 使用大全

    /// 静态全局变量 :只能在当前cpp中访问到  static int s_global = 0; void funcA() {      /// 静态局部变量 (函数静态变量) 初始化过一次就不会 ...

  4. [qemu] 挂载qcow2文件,qcow2里边还有个lvm

    环境:archlinux 背景:在虚拟机里玩dpdk,把挂载HugePage(hugetlbfs)的命令写入fstab的时候,写错了,无法启动,需要把qcow2挂起来改一下. 方法:使用qemu-nb ...

  5. VB动态添加WebBrowser控件,并拦截弹出窗口(不用引用任何组件)

    新建空白窗体,然后粘帖下面代码: Option ExplicitPublic WithEvents br As VBControlExtender Private Sub br_ObjectEvent ...

  6. ios 消息传递机制

    引用文章 一.KVO 1.当对象中的某个属性值发生了改变,可以对这些值的观察者做出通知. 2.接受者(会接收到值发生改变的消息) 必须知道发送者(值将发生改变的那个对象). 3.接收者同样还需要知道发 ...

  7. ManualResetEvent和AutoResetEvent的区别实例

    ManualResetEvent和AutoResetEvent的作用可以理解为在线程执行中插入停顿点flag终止程序运行,然后通过设置flag的状态来使得程序继续运行. 两者的区别是:ManualRe ...

  8. nginx常用变量

    $args, 请求中的参数; $content_length, HTTP请求信息里的”Content-Length”; $content_type, 请求信息里的”Content-Type”; $do ...

  9. HDFS中高可用性HA的讲解

    HDFS Using QJM HA使用的是分布式的日志管理方式 一:概述 1.背景 如果namenode出现问题,整个HDFS集群将不能使用. 是不是可以有两个namenode呢 一个为对外服务-&g ...

  10. 正则表达式lastIndex属性浅析

    有这样一段代码: var newDateStr = " 11 13:48:18"; var reg = new RegExp("[0-9]+","g& ...