WebDriver API

WebDriver提供了八种元素定位方法,在Python语言中,所对应的方法如下:

  • id               →   name
  • class name           →   tag name
  • link text            →   partial link text
  • xpath              →   css selector
  • 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()

定位元素

1.id定位

find_element_by_id(“kw”)

2.name定位

find_element_by_name(“wd”)

3.class定位

find_element_by_class_name(“s_ipt”)#通过class属性来定位元素。

4.tag定位:(标签名)

find_element_by_tag_name(“input”)#通过元素的tag name来定位元素。

5.link定位

link定位与前面介绍的几种定位方法有所不同,它专门用来定位文本链接。

 <a class="mnav" name="tj_trnews" href="http://news.baidu.com">新闻</a>
 
 find_element_by_link_text("新闻")
 
find_element_by_link_text()方法通过元素标签对之间的文本信息来定位元素。
6.partial link定位(模糊定位)
<a class="mnav"name="tj_lang"href="#">一个很长很长的文本链接</a>

通过partial link定位如下:

    find_element_by_partial_link_text("一个很长的")
    
    find_element_by_partial_link_text("文本链接")
find_element_by_partial_link_text()方法通过元素标签对之间的部分文本信息来定位元素。
7.XPath定位

find_element_by_xpath()方法使用XPath语言来定位元素。

绝对路径定位

    find_element_by_xpath("/html/body/div/div[2]/div/div/div/from/span/input")

利用元素属性定位

find_element_by_xpath("//input[@id='kw']")

层级与属性结合

  find_element_by_xpath("//span[@class='bg s_ipt_wr']/input")

使用逻辑运算符

<input id="kw" class="su" name="ie">
find_element_by_xpath("//input[@id='kw' and@class='su']/span/input")
8.CSS定位

find_element_by_css_selector()方法用于CSS语言定位元素

选择器 例子 描述
.class .intro class选择器,选择class="intro"的所有元素
#id #firstname id选择器,选择id="firstname"的所有元素
* * 选择所有元素
element p 元素所有元素
element>element div>input 选择父元素为
的所有元素
element+element div+input 选择同一级中紧接在
元素之后的所有元素
[attribute=value] [target=_blank] 选择target="_blank"的所有元素。
     <span class="bg s_ipt_wr">
        <input id="kw" class="s_ipt" autocomplete="off"
                         maxlength="100" value="" name="wd">
     </span>
     <span class="bg s_btn_wr">
        <input id="su" class="bg s_btn" type="submit"
                          value="百度一下">
     </span>

(1)通过class属性定位,点号(.)表示通过class属性来定位元素。

  find_element_by_css_selector(".s_ipt")
  find_element_by_css_selector(".bg s_btn")

(2)通过id属性定位,井号(#)表示通过id属性来定位元素。

find_element_by_css_selector("#kw")

(3)通过标签名定位,在CSS语言中,用标签名定位元素不需要任何符号标识,直接使用标签名即可。

find_element_by_css_selector("input")

1)通过父子关系定位:

   find_element_by_css_selector("span>input")

2)通过属性定位:

    find_element_by_css_selector("[autocomplete=off]")
    
    find_element_by_css_selector("[name='kw']")
    
    find_element_by_css_selector('[type="submit"]')

在CSS当中也可以使用元素的任意属性,只要这些属性可以唯一标识这个元素。

对于属性值来说,可加引号,也可以不加,但注意和整个字符串的引号进行区分。

3)组合定位:

我们当然可以把上面的定位策略组合起来使用,这就大大加强了定位元素的唯一性。

    find_element_by_css_selector("span.bg s_ipt_wr>input.s_ipt")

有一个父元素,它的标签名叫span;它有一个class属性值叫bg s_ipt_wr;它有一个子元素,标签名叫input,并且这个子元素的class属性值叫s_ipt。好吧,我们要找的就是具有这么多特征的一个子元素。

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
9.用By定位元素

针对前面介绍的8种定位方法,WebDriver还提供了另外一套写法,即统一调用find_element()方法,通过By来声明定位的方法,并且传入对应定位方法的定位参数。

    find_element(By.ID,"kw")
    
    find_element(By.NAME,"wd")
    
    find_element(By.CLASS_NAME,"s_ipt")
    
    find_element(By.TAG_NAME,"input")
    
    find_element(By.LINK_TEXT,"新闻")
    
    find_element(By.PARTIAL_LINK_TEXT,"新")
    
    find_element(By.XPATH,"//*[@class='bg s_btn']")
    
    find_element(By.CSS_SELECTOR,"span.bg s_btn_wr>input#su")

find_element()方法只用于定位元素。

它需要两个参数,第一个参数是定位的类型,由By提供;

第二个参数是定位的具体方式。在使用By之前需要将By类导入。

    from selenium.webdriver.common.by import By

控制浏览器

控制浏览器窗口大小

set_window_size()方法来设置浏览器的大小

maximize_window()方法使打开的浏览器全屏显示,其用法与set_window_size()相同,但它不需要参数。

from selenium import webdriver
driver=webdriver.Firefox()
driver.get("http://m.mail.10086.cn")
    
#参数数字为像素点
print("设置浏览器宽480、高800显示")
driver.set_window_size(480, 800)
driver.quit()

控制浏览器后退、前进

back()和forward()方法来模拟后退和前进按钮

from selenium import webdriver
    
driver=webdriver.Firefox()
    
#访问百度首页
first_url='http://www.baidu.com'
print("now access%s"%(first_url))
driver.get(first_url)
    
#访问新闻页面
second_url='http://news.baidu.com'
print("now access%s"%(second_url))
driver.get(second_url)
    
#返回(后退)到百度首页
print("back to%s"%(first_url))
driver.back()
    
#前进到新闻页
print("forward to%s"%(second_url))
driver.forward()
driver.quit()

模拟浏览器刷新

driver.refresh() #刷新当前页面

简单元素操作

  • clear():      清除文本。
  • send_keys(*value): 模拟按键输入。
  • click():      单击元素。

126邮箱登录

下面通过126邮箱登录来演示这些方法的使用。

login126.py

from selenium import webdriver
    
driver=webdriver.Firefox()
driver.get("http://www.126.com")
    
driver.find_element_by_id("idInput").clear()
driver.find_element_by_id("idInput").send_keys("username")
driver.find_element_by_id("pwdInput").clear()
driver.find_element_by_id("pwdInput").send_keys("password")
driver.find_element_by_id("loginBtn").click()
    
driver.quit()

WebElement接口常用方法

 submit()

submit()方法用于提交表单。例如,在搜索框输入关键字之后的“回车”操作,就可以通过submit()方法模拟。

  • size:        返回元素的尺寸。
  • text:        获取元素的文本。
  • get_attribute(name): 获得属性值。
  • is_displayed():   设置该元素是否用户可见。

baidu.py

from selenium import webdriver
    
driver=webdriver.Firefox()
driver.get("http://www.baidu.com")
    
#获得输入框的尺寸
size=driver.find_element_by_id('kw').size
print(size)#{'width':500, 'height':22}
    
#返回百度页面底部备案信息
text=driver.find_element_by_id("cp").text
print(text)#©2015 Baidu使用百度前必读 意见反馈 京ICP证030173号
    
#返回元素的属性值,可以是id、name、type或其他任意属性
attribute=driver.find_element_by_id("kw").get_attribute('type')
print(attribute)#text
    
#返回元素的结果是否可见,返回结果为True或False
result=driver.find_element_by_id("kw").is_displayed()
print(result)#True
    
driver.quit()

鼠标事件

在WebDriver中,将这些关于鼠标操作的方法封装在ActionChains类提供。

ActionChains类提供了鼠标操作的常用方法:

  • perform():    执行所有ActionChains中存储的行为;
  • context_click(): 右击;
  • double_click():  双击;
  • drag_and_drop(): 拖动;
  • move_to_element():鼠标悬停。

1.鼠标右击操作

yunpan.py

from selenium import webdriver
#引入ActionChains类
from selenium.webdriver.common.action_chains import ActionChains
    
driver=webdriver.Firefox()
driver.get("http://yunpan.360.cn")
#……
    
#定位到要右击的元素
right_click=driver.find_element_by_id("xx")
#对定位到的元素执行鼠标右键操作
ActionChains(driver).context_click(right_click).perform()
#……
  • from selenium.webdriver import ActionChains
    导入提供鼠标操作的ActionChains类。
  • ActionChains(driver)
    调用ActionChains()类,将浏览器驱动driver作为参数传入。
  • context_click(right_click)
    context_click()方法用于模拟鼠标右键操作,在调用时需要指定元素定位。
  • perform()
    执行所有ActionChains中存储的行为,可以理解成是对整个操作的提交动作。

鼠标悬停

move_to_element()方法可以模拟鼠标悬停的动作,其用法与context_click()相同。

#……
    
#定位到要悬停的元素
above=driver.find_element_by_id("id")
#对定位到的元素执行悬停操作
ActionChains(driver).move_to_element(above).perform()
#……

鼠标双击操作

double_click方法用于模拟鼠标双击操作。

mouse.py

#……
    
#定位到要悬停的元素
double_click=driver.find_element_by_id("xx")
#对定位到的元素执行双击操作
ActionChains(driver).double_click(double_click).perform()
#……

鼠标拖放操作

drag_and_drop(source, target)在源元素上按住鼠标左键,然后移动到目标元素上释放。

  • source:鼠标拖动的源元素。
  • target:鼠标释放的目标元素。
#定位元素的原位置
element=driver.find_element_by_id("xx")

#定位元素要移动到的目标位置
target=driver.find_element_by_id("xx")

#执行元素的拖放操作
ActionChains(driver).drag_and_drop(element, target).perform()

键盘事件

Keys()类提供了键盘上几乎所有按键的方法。

前面了解到,send_keys()方法可以用来模拟键盘输入,

除此之外,我们还可以用它来输入键盘上的按键,甚至是组合键,如Ctrl+A、Ctrl+C等。

baidu.py

from selenium import webdriver
#引入Keys模块
from selenium.webdriver.common.keys import Keys
    
driver=webdriver.Firefox()
driver.get("http://www.baidu.com")
    
#输入框输入内容
driver.find_element_by_id("kw").send_keys("seleniumm")
    
#删除多输入的一个m
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)
    
#输入空格键+“教程”
driver.find_element_by_id("kw").send_keys(Keys.SPACE)
driver.find_element_by_id("kw").send_keys("教程")
    
# ctrl+a全选输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, 'a')
    
# ctrl+x剪切输入框内容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, 'x')
    
# ctrl+v粘贴内容到输入框
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, 'v')
    
#通过回车键来代替单击操作
driver.find_element_by_id("su").send_keys(Keys.ENTER)
    
driver.quit()

需要说明的是,上面的脚本没有什么实际意义,仅向我们展示模拟键盘各种按键与组合键的用法。

from selenium.webdriver.common.keys import Keys

在使用键盘按键方法前需要先导入keys类。

以下为常用的键盘操作:

send_keys(Keys.BACK_SPACE)      删除键(BackSpace)
send_keys(Keys.SPACE)        空格键(Space)
send_keys(Keys.TAB)         制表键(Tab)
send_keys(Keys.ESCAPE)        回退键(Esc)
send_keys(Keys.ENTER)        回车键(Enter)
send_keys(Keys.CONTROL,'a')     全选(Ctrl+A)
send_keys(Keys.CONTROL,'c')     复制(Ctrl+C)
send_keys(Keys.CONTROL,'x')     剪切(Ctrl+X)
send_keys(Keys.CONTROL,'v')     粘贴(Ctrl+V)
send_keys(Keys.F1)          键盘F1
send_keys(Keys.F12)         键盘F12

获得验证信息

#再次打印当前页面title
title=driver.title
print(title)
    
#打印当前页面URL
now_url=driver.current_url
print(now_url)

title:用于获得当前页面的标题。

current_url:用户获得当前页面的URL。

设置元素等待

显式等待

显式等待使WebdDriver等待某个条件成立时继续执行,否则在达到最大时长时抛弃超时异常(TimeoutException)。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
element = WebDriverWait(driver, 5, 0.5).until(
                      EC.presence_of_element_located((By.ID, "kw"))
                      )
element.send_keys('selenium')
driver.quit()

WebDriverWait类是由WebDirver提供的等待方法。在设置时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置时间检测不到则抛出异常。具体格式如下:

    WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)

driver :浏览器驱动。

timeout :最长超时时间,默认以秒为单位。

poll_frequency :检测的间隔(步长)时间,默认为0.5S。

ignored_exceptions :超时后的异常信息,默认情况下抛NoSuchElementException异常。

WebDriverWait()一般由until()或until_not()方法配合使用,下面是until()和until_not()方法的说明。

    · until(method, message=‘ ’)

调用该方法提供的驱动程序作为一个参数,直到返回值为True。

    · until_not(method, message=’ ’)

调用该方法提供的驱动程序作为一个参数,直到返回值为False。

在本例中,通过as关键字将expected_conditions重命名为EC,并调用presence_of_element_located()方法判断元素是否存在。

隐式等待

WebDriver提供了implicitly_wait()方法来实现隐式等待,默认设置为0。它的用法相对来说要简单得多。

# 设置隐式等待为10秒
driver.implicitly_wait(10)

sleep休眠方法

使用sleep()方法,由Python的time模块提供。

sleep(2)

定位一组元素

    find_elements_by_id()
    
    find_elements_by_name()
    
    find_elements_by_class_name()
    
    find_elements_by_tag_name()
    
    find_elements_by_link_text()
    
    find_elements_by_partial_link_text()
    
    find_elements_by_xpath()
    
    find_elements_by_css_selector()

element后面多了一个s表示复数

# 选择页面上所有的tag name为input的元素
inputs = driver.find_elements_by_tag_name('input')
# 然后从中过滤出tpye为checkbox的元素,单击勾选
for i in inputs:
    if i.get_attribute('type') == 'checkbox':
        i.click()
        time.sleep(1)

通过浏览器打开的是一个本地的html文件,所以需要用到Python的os模块,path.abspath()方法用于获取当前路径下的文件。

# 通过XPath找到type=checkbox的元素
# checkboxes = driver.find_elements_by_xpath("//input[@type='checkbox']")
# 通过CSS找到type=checkbox的元素
checkboxes = driver.find_elements_by_css_selector('input[type=checkbox]')
for checkbox in checkboxes:
    checkbox.click()
    time.sleep(1)
# 打印当前页面上type为checkbox的个数
print(len(checkboxes))
# 把页面上最后1个checkbox的钩给去掉
driver.find_elements_by_css_selector('input[type=checkbox]').pop().click()

len()方法可以用来计算元素的个数

pop()方法用于获取列表中的一个元素(默认为最后一个元素),并且返回该元素的值。

pop()或pop(-1): 默认获取一组元素中的最后一个。
pop(0): 默认获取一组元素中的第一个。
pop(1): 默认获取一组元素中的第二个。

多表单切换

WebDriver只能在一个页面上对元素识别与定位,对于frame/iframe表单内嵌页面上的元素无法直接定位。

这时就需要通过switch_to.frame()方法将当前定位的主体切换为frame/iframe表单的内嵌页面中。

通过iframe表单嵌入一个百度页面,

<iframe id="if" name="nf" src="http://www.baidu.com" width="800"
                 height="300">
       </iframe>
# 切换到iframe(id = "if")
driver.switch_to.frame("if")

# 下面就可以正常的操作元素了
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()

switch_to.parent_content()方法跳出当前一级表单。该方法默认对应于离它最近的switch_to.frame()方法。

在进入多级表单的情况下,还可以通过switch_to.default_content()跳回最外层的页面。

多窗口切换

switch_to.window()方法,可以实现在不同的窗口之间切换。

current_window_handle:获得当前窗口句柄。

window_handles:返回所有窗口的句柄到当前会话。

switch_to.window():用于切换到相应的窗口,与上一节的switch_to.frame()类似,前者用于不同窗口的切换,后者用于不同表单之间的切换。

# 获得当前所有打开的窗口的句柄
all_handles = driver.window_handles
# 获得百度搜索窗口句柄
sreach_windows = driver.current_window_handle

警告框处理

switch_to_alert()方法定位到alert/confirm/prompt,

然后使用text/accept/dismiss/ send_keys等方法进行操作。

  • text:返回alert/confirm/prompt中的文字信息。
  • accept():接受现有警告框。
  • dismiss():解散现有警告框。
  • send_keys(keysToSend):发送文本至警告框。keysToSend:将文本发送至警告框。
  • switch_to_alert()方法接受这个弹窗

上传文件

对于Web页面的上传功能实现一般有以下两种方式。

  • 普通上传:普通的附件上传是将本地文件的路径作为一个值放在input标签中,通过form表单将这个值提交给服务器。
  • 插件上传:一般是指基于Flash、JavaScript或Ajax等技术所实现的上传功能。

send_keys实现上传

对于通过input标签实现的上传功能,可以将其看作是一个输入框,即通过send_keys()指定本地文件路径的方式实现文件上传。

 <input type="file" name="file" />

# 定位上传按钮,添加本地文件
driver.find_element_by_name("file").send_keys('D:\\upload_file.txt')

AutoIt实现上传

下载文件

from selenium import webdriver
import os
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.download.folderList",2)
fp.set_preference("browser.download.manager.showWhenStarting",False)
fp.set_preference("browser.download.dir", os.getcwd())
fp.set_preference("browser.helperApps.neverAsk.saveToDisk",
"application/octet-stream") #下载文件的类型
driver = webdriver.Firefox(firefox_profile=fp)
driver.get("http://pypi.Python.org/pypi/selenium")
driver.find_element_by_partial_link_text("selenium-2").click()

为了让Firefox浏览器能实现文件下载,我们需要通过FirefoxProfile()对其做一些设置。

    browser.download.folderList

设置成0代表下载到浏览器默认下载路径,设置成2则可以保存到指定目录。

    browser.download.manager.showWhenStarting

是否显示开始;True为显示,Flase为不显示。

    browser.download.dir

用于指定所下载文件的目录。os.getcwd()函数不需要传递参数,用于返回当前的目录。

    browser.helperApps.neverAsk.saveToDisk

指定要下载页面的Content-type值,“application/octet-stream”为文件的类型。

HTTP Content-type常用对照表:http://tool.oschina.net/commons

上面例子中的设置只针对Firefox浏览器,不同的浏览器设置方法会有所不同。通用的方法还是借助AutoIt来操作Windows控件进行下载,

操作Cookie

WebDriver操作cookie的方法:

  • get_cookies(): 获得所有cookie信息。

  • get_cookie(name): 返回字典的key为“name”的cookie信息。

  • add_cookie(cookie_dict): 添加cookie。“cookie_dict”指字典对象,必须有name和value值。

  • delete_cookie(name,optionsString):删除cookie信息。“name”是要删除的cookie的名称,“optionsString”是该cookie的选项,目前支持的选项包括“路径”,“域”。

  • delete_all_cookies(): 删除所有cookie信息。

调用JavaScript

WebDriver提供了execute_script()方法来执行JavaScript代码。

window.scrollTop()方法用于设置浏览器窗口滚动条的水平和垂直位置。

方法的第一个参数表示水平的左间距,第二个参数表示垂直的上边距。

# 通过javascript设置浏览器窗口的滚动条位置
js="window.scrollTo(100,450);"
driver.execute_script(js)

……
<textarea id="id" style="width: 98%" cols="50" rows="5" class="txtarea">
</textarea>
text = "input text"
js = "var sum=document.getElementById('id'); sum.value='" + text + "';"
driver.execute_script(js)
……

处理HTML5的视频播放

load()、play()、pause()等控制着视频的加载、播放和暂停。

driver.get("http://videojs.com/")
video = driver.find_element_by_xpath("body/Setion[1]/div/video")
# 返回播放文件地址
url = driver.execute_script("return arguments[0].currentSrc;", video)
print(url)
# 播放视频
print("start")
driver.execute_script("return arguments[0].play()", video)
# 播放15秒钟
sleep(15)
# 暂停视频
print("stop")
driver.execute_script("arguments[0].pause()", video)

窗口截图

WebDriver提供了截图函数get_screenshot_as_file()来截取当前窗口。

# 截取当前窗口,并指定截图图片的保存位置
driver.get_screenshot_as_file("D:\\pyse\\baidu_img.jpg")
# 脚本运行完成后打开D盘,就可以找到baidu_error.jpg图片文件了。

关闭窗口

quit()方法,其含义为退出相关的驱动程序和关闭所有窗口。

close()方法,用来关闭当前窗口。

在用例执行的过程中打开了多个窗口,我们想要关闭其中的某个窗口,这时就要用到close()方法进行关闭了。

验证码的处理

1.去掉验证码

把验证码的相关代码注释掉->不安全

2.设置万能验证码

在修改程序时不取消验证码,而是设置一个“万能验证码”。只要用户输入这个“万能验证码”,程序就认为验证通过,否则就判断用户输入的验证码是否正确。(及下面例子中的elif 132741)

对用户的输入信息多加一个逻辑判断

if number == verify:
    print("登录成功!!")
elif number == 132741:
    print("登录成功!!")
3.验证码识别技术

通过Python-tesseract来识别图片验证码。

Python-tesseract是光学字符识别Tesseract OCR引擎的Python封装类,能够读取任何常规的图片文件(JPG、GIF、PNG、TIFF等)。

4.记录cookie

通过向浏览器中添加cookie可以绕过登录的验证码,这是比较有意思的一种解决方案。

例如我们在第一次登录某网站时勾选“记住密码”的选项,当下次再访问该网站时自动就处于登录状态了。这样自然就绕过了验证码问题。这个“记住密码”的功能其实就记录在了浏览器的cookie中。

通过WebDriver来操作浏览器的cookie,可以通过add_cookie()方法将用户名密码写入浏览器cookie,当再次访问网站时,服务器将直接读取浏览器的cookie进行登录。

# cookie_login.py
# 访问xx网站
driver.get("http://www.xx.cn")
# 将用户名密码写入浏览器cookie
driver.add_cookie({'name':'Login_UserNumber', 'value':'username'})
driver.add_cookie({'name':'Login_Passwd', 'value':'password'})
# 再次访问xx网站,将会自动登录
driver.get("http://www.xx.cn/")
# ……
driver.quit()

这种方式最大的问题是如何从浏览器的cookie中找到用户名和密码对应的key值,并传输入对应的登录信息。可以用get_cookies()方法来获取登录的所有的cookie信息,从中找到用户名和密码的key。当然,更直接的方式是询问开发人员。

WebDriver原理

结尾

对于自动化测试人员来说,如果精通前端技术将会非常有助于自动化用例的编写,熟练使用XPath和CSS技术会使你的定位变得容易很多,精通JavaScript、jQuery可以让我们有更多的方式去操作Web页面。

假如,你已经动手开始进行自动化了,那么笔者再提几点建议:

1.熟练掌握XPath\CSS定位的使用,这样在遇到各种难以定位的问题时才不会变得束手无策。

2.准备一份WebDriver API文档,以便随时查阅WebDriver所提供的方法。

3.学习掌握JavaScript、jQuery技术,它可以让我们使用该技术去操作Web页面。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐