本节主要结合众多自动化测试案例介绍元素定位实战,如单个元素定位、多个元素定位、By类定位及引用JavaScript、JQuery辅助定位来加强元素定位实战技巧。在笔者看来,元素定位在自动化测试中非常重要。
WebDriver提供了多种内置定位方法,如id、name、class、link_text、partial_link_text、tag、xpath和css定位等。下面介绍一个百度首页案例。按F12键,会出现Chrome调试工具,单击调试工具上方的小箭头,定位到文本框位置上。在HTML页面下方显示的是页面文本框对应的HTML元素。拆分HTML元素,如图2.11所示。
图2.11 百度首页HTML元素拆分
在上面的案例中,百度文本框对应的元素是<input id="kw" name="wd" class="s_ipt" value maxlength="255" autocomplete="off" >,其中=(等号)左侧的id、name、class、value maxlength和autocomplete等都是元素的属性,就像人有身份证、姓名和身高等属性一样;等号右侧的kw、wd、s_ipt、255、off等都是属性值,就像人的身份证号、姓名和身高等。Selenium工具就是通过识别这些属性来进行测试的。
1. 通过find_element_by_id()定位
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_id("kw").send_keys('大道至简') driver.quit()
2. 通过find_element_by_name()定位
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_name("wd").send_keys('大道至简') driver.quit()
3. 通过find_element_by_class_name()定位
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_class_name("s_ipt").send_keys('大道至简') driver.quit()
上述3个案例中,分别使用了id、name、class_name来定位百度文本框。send_keys()是一个方法,表示向文本框中输入内容。在元素定位中,如果元素本身有id、name属性,则直接使用id、name定位,一般来说,id、name属性值都是唯一的。相反,在使用class定位时,要检查class_name属性值在页面中是否唯一。如果不唯一,尽量不要用class去定位。举个简单的例子,一个班级里有两个叫张飞的同学,喊张飞时,这两个同学都会一起站起来,这样就会产生冲突。
通过浏览器自带的调试工具来验证属性的唯一性。按F12键,再按Ctrl+F组合键,搜索指定的元素属性值。如图2.12所示,class属性值在整个页面显示数量只有1个,这时就可以使用class来定位了。有些情况下,class属性值即使是唯一的,可能也会定位报错,这时就需要考虑其他定位方法。
图2.12 Chrome调试工具界面
4. 通过find_element_by_xpath()定位
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_xpath("//input[@id='kw']").send_keys('大道至简') driver.quit()
//表示相对路径,input标签是文本框的所在标签,@id=kw是文本框元素id的属性值。当然,也可以把id换成其他的定位,如name等。
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_xpath("//form[@id='form']/span/input").send_keys('大道至简') driver.quit()
//form[@id= 'form']表示父类元素,/表示下一级标签,/span/input表示span标签下的input标签,如图2.13所示。
图2.13 父子关系定位界面演示图
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_xpath("//input[@id='kw' and @class='s_ipt']").send_keys('大道 至简') driver.quit()
//input表示HTML页面相对路径下的input标签;@id='kw' and @class='s_ipt'是input标签的两个属性,通过id和class两个属性加强元素的唯一性。
5. 通过find_element_by_css_selector()定位1
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_css_selector("input#kw").send_keys('大道至简') driver.quit()
input#kw表示input标签下id属性值是kw的元素。在css定位中,id简写用“#”来表示,class属性简写用“.”来表示。
6. 通过find_element_by_css_selector()定位2
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.baidu.com') driver.find_element_by_css_selector("form#form>span>input").send_keys('大道至简') driver.quit()
form#form表示form标签下id属性值是form的元素。在css定位中,层级关系用“>”来表示。span>input表示span标签下的input标签。有时为了简洁,也可以不写“>”,直接写成form#form span input。
有时定位的元素属性值或标签名并不是唯一的,如一个页面有多个相同的type属性值或多个相同的标签名,如图2.14所示。
图2.14 多个元素属性界面
示例如下:
from selenium import webdriver driver = webdriver.Chrome() driver.get('file:///' + os.path.abspath('checkbox.html')) driver.find_elements_by_css_selector("input[type='checkbox']")[0].click() driver.quit()
如图2.14所示,整个页面中有3个相同的input标签,且input标签下的type属性值checkbox都是一样的。这种情况可以使用find_elements_by_css_seletor()方法定位,该方法返回一个列表对象。通过Python索引下标来获取要定位的元素。[0]表示第一个input标签下的checkbox属性值,[1]表示第二个input标签下的checkbox属性值。
再看一个多个标签定位案例,如图2.15所示。
图2.15 百度首页调试界面
示例如下:
from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get("https://www.baidu.com") tag = dr.find_elements_by_tag_name('input') for t in tag: if t.get_attribute('autocomplete') == 'off': t.send_keys('fighter007') driver.find_element_by_id('su').click() dr.quit()
如图2.15所示,当页面中有多个input标签时,可以通过标签本身的属性来定位。先获取所有input标签,然后通过for循环遍历每一个对象,最后判断获取的对象中autocomplete属性等于off的元素。
使用By类定位,需要先导入By类。元素定位中的id、name、xpath、class、link_text和css分别在By类定位的语法是By.ID、By.NAME、By.XPATH、By.CLASS_NAME、By.LINK_TEXT和By.CSS_SELECTOR,示例如下:
from selenium import webdriver from selenium.webdriver.common.by import By # 导入By类 driver = webdriver.Chrome() driver.get("https://www.baidu.com") driver.find_element(By.ID,'kw').send_keys('大道至简') driver.find_element(By.ID,'kw').click()
By类定位的统一语法是find_element(By.ID,'kw'),即通过id定位百度文本框,kw是文本框的id属性值。By类中的元素定位方法要注意区分大小写。
JavaScript提供了多种元素定位方式,如getElementsByClassName()、getElementByID()、getElementsByName()、getElementsByTagName()和document.querySelectorAll()等。除getElementByID()定位返回单个elements元素定位外,其他的定位方式都是返回list对象,如图2.16所示。
图2.16 简书登录界面
示例如下:
from selenium import webdriver import time as t dr = webdriver.Chrome() dr.get('https://www.jianshu.com/sign_in') t.sleep(2) # 单击“注册”按钮 js_register = 'document.getElementById("js-sign-up-btn").click();' dr.execute_script(js_register) t.sleep(2)
使用document.getElementById()方法定位“注册”按钮,其中execute_script()方法用于调用js方法来执行JavaScript脚本。
# 单击“登录”按钮 js_class = 'document.getElementsByClassName("active")[0].click();' dr.execute_script(js_class) t.sleep(2)
使用getElementsByClassName()方法定位“登录”按钮,该方法返回一个list对象,其中[0]表示获取第一个class属性的元素。
js_input = 'document.getElementsByTagName("input")[2].value="username";' dr.execute_script(js_input) t.sleep(2)
使用getElementsByTagName()方法定位账号文本框,其中[2]表示获取整个页面的第三个input标签,value="username"表示向文本框输入账号为username。
# 使用js 标签名定位输入密码框 js_passwd = 'document.getElementsByTagName("input")[3].value="password";' # [3]索引值为3 dr.execute_script(js_passwd) t.sleep(2)
使用document.getElementsByTagName()方法定位密码文本框,其中[3]表示获取整个页面的第四个input标签,value="password"表示向文本框输入密码为password。
JQuery是JavaScript中的一个库,JQuery中的css选择器经常会用于元素定位中的策略,示例如下:
# 定位登录链接 js_class = 'document.getElementsByClassName("active")[0].click();' dr.execute_script(js_class) t.sleep(2) # 定位账号文本框,输入“username” js_input = 'document.getElementsByTagName("input")[2].value="username";' dr.execute_ script(js_input) t.sleep(2) # 定位密码文本框,输入“password” # js_passwd = 'document.getElementsByTagName("input")[3].value="password";' dr.execute_script(js_passwd) t.sleep(2) # 使用css选择器定位“登录”按钮 css_btn = 'document.querySelectorAll(".sign-in-button")[0].click();' dr.execute_script(css_btn)
JQuery定位语法可以统一用document.querySelectorAll()来表示,该方法返回的是一个list对象,其中.sign-in-button表示“登录”按钮本身的class属性,[0]表示返回第一个元素对象。