WebDriver 提供了 8 种元素定位方法,在 Python 中,对应的方法如下:
id 定位 → find_element_by_id()
name 定位 → find_element_by_name()
tag 定位 → find_element_by_tag_name()
class 定位 → find_element_by_class_name()
link_text → find_element_by_link_text()
partial link 定位 → find_element_by_partial_link_text()
XPath 定位 → find_element_by_xpath()
CSS_selector 定位 → find_element_by_css_selector()
如果把页面上的元素看作人,那么在现实世界中如何找到某人呢?
首先,可以通过人本身的属性进行查找,例如他的姓名、手机号、身份证号等,这些都是用于区别于他人的属性。在 Web 页面上的元素也有本身的属性,例如,id、name、class name、tag name 等。其次,可以通过位置进行查找,例如,x 国、x 市、x 路、x 号。XPath 和 CSS 可以通过标签层级关系的方式来查找元素。最后,还可以借助相关人的属性来找到某人。例如,我没有小明的联系方式,但是我有他爸爸的手机号,那么通过他爸爸的手机号最终也可以找到小明。XPath 和 CSS 同样提供了相似的定位策略来查找元素。
属性定位
HTML 规定,id 在 HTML 文档中必须是唯一的,这类似于我国公民的身份证号,具有唯一性。WebDriver 提供的 id 定位方法是通过元素的 id 来查找元素的。
HTML 规定,name 用来指定元素的名称,因此它的作用更像是人的姓名。
HTML 规定,class 用来指定元素的类名,其用法与 id、name 类似。
HTML 通过 tag 来定义不同页面的元素。例如,<input>一般用来定义输入框,<a>标签用来定义超链接等。不过,因为一个标签往往用来定义一类功能,所以通过标签识别单个元素的概率很低。例如,我们打开任意一个页面,查看前端代码时都会发现大量的<div>、<input>、<a>等标签。
link 定位与前面介绍的几种定位方法有所不同,它专门用来定位文本链接。百度输入框上面的几个文字链接的代码如下。
partial link 定位是对 link 定位的一种补充,有些文字链接比较长,这个时候我们可以取文字链接的部分文字进行定位,只要这部分文字可以唯一地标识这个链接即可。
在理想状态下,一个页面当中每个元素都有唯一的 id 值和 name 值,可以通过它们来查找元素。但在实际项目中并非想象得这般美好,有时候一个元素没有 id 值和 name 值,或者页面上有多个元素属性是相同的;又或者 id 值是随机变化的,在这种情况下,如何定位元素呢?
XPath 定位
绝对路径定位
如果把元素看作人,假设这个人没有任何属性特征(手机号、姓名、身份证号),但这个人一定存在于某个地理位置,如 xx 省 xx 市 xx 区 xx 路 xx 号。对于页面上的元素而言,也会有这样一个绝对地址。
利用元素属性定位
除使用绝对路径外,XPath 还可以使用元素的属性值来定位。
//input 表示当前页面某个 input 标签,[@id=‘kw’] 表示这个元素的 id 值是 kw。如果不想指定标签名,那么可以用星号(*)代替。当然,使用 XPath 不局限于 id、name和 class 这三个属性值,元素的任意属性都可以使用,只要它能唯一标识一个元素。
层级与属性结合
如果一个元素本身没有可以唯一标识这个元素的属性值,那么我们可以查找其上一级元素。如果它的上一级元素有可以唯一标识属性的值,就可以拿来使用。
假如百度输入框没有可利用的属性值,那么可以查找它的上一级属性。例如,小明刚出生的时候没有名字,也没有身份证号,那么亲朋好友来找小明时可以先找到小明的爸爸,因为他爸爸是有很多属性特征的。找到小明的爸爸后,就可以找到小明了。通过 XPath 描述如下:find_element_by_xpath("//span[@class='bg s_ipt_wr']/input") span[@class=‘s_ipt_wr’] 通过 class 定位到父元素,后面的/input 表示父元素下面的子元素。如果父元素没有可利用的属性值,那么可以继续向上查找父元素的父元素。
使用逻辑运算符
如果一个属性不能唯一区分一个元素,那么我们可以使用逻辑运算符连接多个属性来查找元素:find_element_by_xpath("//input[@id='kw' and @class='s_ipt']")
使用 contains 方法
contains 方法用于匹配一个属性中包含的字符串。例如,span 标签的 class 属性为“bgs_ipt_wr”:find_element_by_xpath("//span[contains(@calss,'s_ipt_wr')]/input"),contains 方法只取了 class 属性中的“s_ipt_wr”部分。
使用 text()方法
text()方法用于匹配显示文本信息。例如,前面通过 link text 定位的文字链接:find_element_by_xpath("//a[text(),'新闻')]")。当然,contains 和 text()也可以配合使用:find_element_by_xpath("//a[contains(text(),'一个很长的')]")。
CSS 定位
CSS 选择器可以较为灵活地选择控件的任意属性,一般情况下,CSS 定位速度比 XPath定位速度快。CSS 选择器的更多用法可以查看 W3CSchool 网站中的 CSS 选择器参考手册(http://www.w3school.com.cn/cssref/css_selectors.asp)。
通过 class 定位
find_element_by_css_selector()方法用于在 CSS 中定位元素,点号(.)表示通过 class来定位元素。
find_element_by_css_selector(".s_ipt")find_element_by_css_selector(".s_btn")
通过 id 定位
井号(#)表示通过 id 来定位元素。
find_element_by_css_selector("#kw")find_element_by_css_selector("#su")
通过标签名定位
CSS 中,用标签名定位元素时不需要任何符号标识,直接使用标签名即可:find_element_by_css_selector("input")。
通过标签层级关系定位
find_element_by_css_selector("span > input")这种写法表示有父元素,父元素的标签名为 span。查找 span 中所有标签名为 input 的子元素。
通过属性定位
在 CSS 中可以使用元素的任意属性定位,只要这些属性可以唯一标识这个元素。对属性值来说,可以加引号,也可以不加,注意和整个字符串的引号进行区分。
find_element_by_css_selector("[autocomplete=off]")find_element_by_css_selector("[name='kw']")
find_element_by_css_selector('[type="submit"]')
组合定位
我们可以把上面的定位策略组合起来使用,这就大大加强了定位元素的唯一性。我们要定位的这个元素标签名为 input,这个元素的 class 属性为 s_ipt;并且它有一个父元素,标签名为 span。它的父元素还有父元素,标签名为 form,class 属性为 fm。我们要找的就是必须满足这些条件的一个元素。
find_element_by_css_selector("form.fm > span > input.s_ipt")find_element_by_css_selector("form#form > span > input#kw")
更多定位用法
查找 class 属性包含“s_ipt_wr”字符串的元素。find_element_by_css_selector("[class*=s_ipt_wr]") 查找 class 属性以“bg”字符串开头的元素。find_element_by_css_selector("[class^=bg]") 查找 class 属性以“wrap”字符串结尾的元素。find_element_by_css_selector("[class$=wrap]") 查找 form 标签下面第 2 个 input 标签的元素。find_element_by_css_selector("form > input:nth-child(2)")
用 By 定位元素
针对前面介绍的 8 种定位方法,WebDriver 还提供了另外一套写法,即统一调用find_element()方法,通过 By 来声明定位,并且传入对应定位方法的定位参数,具体如下。find_element()方法只用于定位元素,它需要两个参数。第一个参数是定位的类型,由By 提供(from selenium.webdriver.common.by import By);第二个参数是定位的值。
本博客摘抄自《Selenium3自动化测试实战——基于Python语言》,详细内容请购买该书进行学习