WebDriver属于Selenium体系中设计出来操作浏览器的一套API,站在WebDriver的角度,因为它针对多种编程语言都实现了一遍这套API,所以它可以支持多种编程语言;站在编程语言的角度,WebDriver是Python的一个用于实现Web自动的第三方库。
我们在做WEB自动化时,最根本的就是操作页面上的元素,首先我们要能找到这些元素,然后才能操作这些元素。工具或代码无法像我们测试人员一样用肉眼来分辨页面上的元素。那么我们怎么来定位他们呢?
在学习元素定位之前,我们最好能懂一点html的知识。.
一、查看页面元素
1、用谷歌浏览器打开百度首页,点击右上角>更多工具>开发者工具,就可以看到整个页面的html代码了;
2、百度首页,点击右键->检查,也可以查看整个页面的html代码了。
点击框中左上角的箭头图标,移动鼠标到百度搜索框,就可以自动定位到百度搜索框的HTML代码了,查看到搜索框的属性,我们可以看到搜索框有id,name,class等属性。
二、元素定位
常见的有8种:
1、id定位: find_element_by_id()
从上面定位到的搜索框属性中,有个id="kw"的属性,我们可以通过这个id定位到这个搜索框
代码:
# coding = utf-8
from time import sleep
from selenium import webdriver
# 启动浏览器
driver = webdriver.Chrome()
# 打开百度首页
driver.get('http://www.baidu.com/')
# 通过id定位搜索框,并输入selenium
driver.find_element_by_id('kw').send_keys('selenium')
# 等待5秒
sleep(5)
# 退出
driver.quit()
2、name定位: find_element_by_name()
从上面定位到的搜索框属性中,有个name="wd"的属性,我们可以通过这个name定位到这个搜索框
# 通过name定位搜索框,并输入selenium
driver.find_element_by_name('wd').send_keys('selenium')
3、class定位:find_element_by_class_name()
从上面定位到的搜索框属性中,有个class="s_ipt"的属性,我们可以通过这个class定位到这个搜索框
# 通过class定位搜索框,并输入selenium
driver.find_element_by_class_name('s_ipt').send_keys('selenium')
4、tag定位:find_element_by_tag_name()
如果懂HTML知识,我们就知道HTML是通过tag来定义功能的,比如input是输入,table是表格,等等...。每个元素其实就是一个tag,一个tag往往用来定义一类功能,我们查看百度首页的html代码,可以看到有很多div,input,a等tag,所以很难通过tag去区分不同的元素。基本上在我们工作中用不到这种定义方法,仅了解就行。
通过标tag name定位百度的输入框与百度按钮会发现它们完全相同:
# 通过tag定位搜索框,并输入selenium, 此处必报错 driver.find_element_by_tag_name('input').send_keys('selenium')
5、link定位:find_element_by_link_text()
此种方法是专门用来定位文本链接的,比如百度首页右上角有“新闻”,“hao123”,“地图”等链接
我们来定位“新闻”这个链接元素
# 通过link定位"新闻"这个链接并点击
driver.find_element_by_link_text('新闻').click()
6、partial_link定位:find_element_by_partial_link_text()
有时候一个超链接的文本很长很长,我们如果全部输入,既麻烦,又显得代码很不美观,这时候我们就可以只截取一部分字符串,用这种方法模糊匹配了。
我们用这种方法来定位百度首页的“新闻”超链接
# 通过partial_link定位"新闻"这个链接并点击
driver.find_element_by_partial_link_text('闻').click()
7、xpath定位:find_element_by_xpath()
前面介绍的几种定位方法都是在理想状态下,有一定使用范围的,那就是:在当前页面中,每个元素都有一个唯一的id或name或class或超链接文本的属性,那么我们就可以通过这个唯一的属性值来定位他们。
但是在实际工作中并非有这么美好,有时候我们要定位的元素并没有id,name,class属性,或者多个元素的这些属性值都相同,又或者刷新页面,这些属性值都会变化。那么这个时候我们就只能通过xpath或者CSS来定位了。
①绝对路径定位
XPath有多种定位策略,最简单直观的就是写出元素的绝对路径。如果仍把一个元素看作是一个人的话,假设这个人没有任何属性特征(手机号、姓名、身份证号),但这个人一定存在与某个地理位置,如**省**市**区**路**号。对于页面上的元素而言也会有这样一个绝对地址。
参考baidu.html前端工具所展示的代码,我们可以通过下面的方式找到百度输入框和搜索按钮。
driver.find_element_by_xpath('/html/body/div/div/div/div/div/form/span/input').send_keys('selenium')
driver.find_element_by_xpath('/html/body/div/div/div/div/div/form/span[2]/input').click()
注意此处的index下标是从1开始的,不是从0。即div[1]表示当前层级下第1个div标签。
driver.find_element_by_xpath()方法使用XPath语言来定位元素。XPath主要用标签名的层级关系来定位元素的绝对路径,最外层为html语言。在body文本内,一级一级往下查找,如果一个层级下有多个相同的标签名,那么久按上下顺序确定是第几个,例如span[2]表示当前层级下的第二个span标签。
②利用元素属性定位
除了使用绝对路径外,XPath也可以使用元素的属性值来定位。同样以百度输入框和搜索按钮为例:
driver.find_element_by_xpath("//*[@id='kw']").send_keys('selenium')
driver.find_element_by_xpath("//*[@id='su']").click()
//表示当前页面某个目录下,input表示定位元素的标签名,【@id='kw'】表示这个元素的id属性等于kw。下面通过name和class属性值来定位。
driver.find_element_by_xpath("//input[@name='wd']")
driver.find_element_by_xpath("//input[@class='s_ipt']")
driver.find_element_by_xpath("//*[@class='bg s_ipt']")
如果不想指定标签名,则可以用星号(*)代替。当然,使用XPath不局限于id、name和 class这三个属性值,元素的任意属性值都可以使用,只要它能唯一的标识一个元素。
driver.find_element_by_xpath("//input[@maxlength='100']")
driver.find_element_by_xpath("//input[@autocomplete='off']")
driver.find_element_by_xpath("//input[@type='submit']")
③层级与属性结合
如果一个元素本身没有可以唯一标识这个元素的属性值,那么我们可以找其上一级元素,如果它的上一级元素有可以唯一标识属性的值,也可以拿来使用。
假如百度输入框本身没有可利用的属性值,那么我们可以查找它的上一级属性。例如,“小明”刚出生的时候没有名字,没上户口(没有身份证号),那么亲朋好友找“小明”时,可以先找到小明的爸爸,因为他爸爸是有很多属性特征的,找到了小明的爸爸后,就可以找到小明了。通过XPath描述如下:
driver.find_element_by_xpath('//span[@class="bg s_btn_wr"]/input').click()
span[@class="bg s_btn_wr"]通过class属性定位到父元素,后面/input就标识父元素下面的子元素。如果父元素没有可利用的属性值,那么可以继续向上查找“爷爷”元素。
driver.find_element_by_xpath('//form[@id="form"]/span/input').click()
driver.find_element_by_xpath('//form[@id="form"]/span[2]/input').click()
我们可以通过这种方法一级一级地向上查找,直到找到最外层的<html>标签,这就是一个绝对路径的写法了。
④使用逻辑运算符
如果一个属性不能唯一区分一个元素,我们可以使用逻辑运算符连接多个属性来查找元素。
如上面的三行元素,假设我们现在要定位第一个元素,如果使用id将会与第二个元素重名,如果使用class将会与第三行重名。如果同时使用id和class就会唯一地标识这个元素,这个时候就可以通过逻辑运算符“and”来连接两个条件。
driver.find_element_by_xpath('//input[@id="kw" and @class="s_ipt"]').send_keys('selenium')
当然,我们也可以用“and”连接更多的属性来唯一地标识一个元素。
⑤获取网页页面元素xpath值
- 打开任意网页例如百度网页
- 鼠标点击右键,可以看到有个检查按钮,点击检查按钮打开调试工具
- 进入调试工具后,点击左上角的鼠标箭头,选中后将鼠标移至你想要查看的元素的位置
- 鼠标移至选中位置后点击,这时右边调试工具会跳转到指定的位置
- 鼠标右键点击该位置出现弹窗,选择copy,然后选择copy xpath
- 打开记事本,通过快捷键ctrl+v,将刚才copy的xpath粘贴下来,至此我们就获得了想要的元素的xpath,通过该xpath能精准的定位元素完成自动化操作
8、CSS定位:find_element_by_css_selector()
这种方法相对xpath要简洁些,定位速度也要快些,但是学习起来会比较难理解,这里只做下简单的介绍。
CSS定位百度搜索框
# 通过CSS定位搜索框,并输入selenium
driver.find_element_by_css_selector('#kw').send_keys('selenium')
CSS(Cascading Style Sheets)是一种语言,它用于描素HTML和XML文档的表现。CSS使用选择器来为页面元素绑定属性。这些选择器可以被Selenium用作另外的定位策略。CSS可以较为灵活的选择控件的任意属性,一般情况下定位速度要比XPath快,但对于初学者来说学习起来稍微有难度,下面我们就详细地介绍CSS的语法与使用。
CSS选择器常见语法如下表:
选择器 | 例子 | 描述 |
.class | .intro | class选择器,选择class="intro"的所有元素 |
#id | #firstname | id选择器,选择id="firstname"的所有元素 |
* | * | 选择所有元素 |
element | p | 元素所有<p>元素 |
element>element | div>input | 选择父元素为<div>元素之后的所有<input>元素 |
element+element | div+input | 选择同一级中紧接在<div>元素之后的所有<input>元素 |
【attribute-value】 | [target=blank] | 选择target=“_blank”的所有元素。 |
下面同样以百度和搜索按钮为例介绍CSS定位的用法。
1)通过class属性定位:
driver.find_element_by_css_selector(".s_ipt").send_keys("selenium")
driver.find_element_by_css_selector(".s_btn").click()
find_element_by_css_selector()方法用于CSS语言定位元素,点号(.)表示通过class属性来定位元素。
2)通过id属性定位:
driver.find_element_by_css_selector('#kw').send_keys('selenium')
driver.find_element_by_css_selector('#su').
click()
3)井号(#)表示通过id属性来定位元素。
通过标签定位:
driver.find_element_by_css_selector("input").send_keys("selenium")
在CSS语言中,用标签定位元素不需要任何符号标识,直接使用标签名即可。但我们前面已经了解到,标签名重复的概率非常大,所以通过这种方式很难找到想要的元素。
1)通过父子关系定位
driver.find_element_by_css_selector("span>input").send_keys("selenium")
上面的写法表示有父亲元素,它的标签名为span,查找它的所有标签名叫input的子元素。
2)通过属性定位
driver.find_element_by_css_selector("[autocomplete=off]").send_keys("selenium") driver.find_element_by_css_selector("[name='wd']").send_keys("selenium") driver.find_element_by_css_selector("[type='submit']").click()
在CSS当中也可以使用元素的任意属性,只要这些属性可以唯一的标识这个元素,对于属性值来说,可加引号,也可以不加,但注意和整个字符串的引号进行区分。
3)组合定位:
我们当然可以把上面的定位策略组合起来,这就大大加强了定位元素的唯一性。
driver.find_element_by_css_selector("span.s_ipt_wr>input.s_ipt").send_keys("selenium") driver.find_element_by_css_selector("span.s_btn_wr>input#su").click()
有一个父元素,它的标签名叫span:它有一个class属性值叫s_ipt_wr;它有一个子元素,标签名叫input,并且这个子元素的class属性值叫s_ipt。好吧,我们要找的就是具有这么多特性的一个子元素。
我们可以通过使用Firebug工具帮助我们生成CSS语法,生成方法与XPath相同,通过Firebug定位元素,在元素上右击,选择复制CSS路径
需要说明的是,CSS的语法远不止上面所介绍的内容,更多的前端技术读者可以参考W3CShool网站。
XPath与CSS的类似功能的简单对比。
定位方法 | XPath | CSS |
标签 |
//div | div |
By id | //div[@id='eleid'] | div#eleid |
By class | //div[@class='eleclass'] | div.eleid |
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>h1 |