4.9 多表单切换
在web应用中经常会遇到frame嵌套页面的应用,webdriver每次只能在一个页面上识别元素,对于frame嵌套的页面上的元素,直接定位是定位不到的,这时候就需要switch_to_frame()方法将当前定位的主体切换到frame里。Frame.htm:frame.htm, 直接定位百度的输入框一定会报找不到元素的错误。那么可以使用switch_to_frame()先找到frame.html
中的<iframe>标签,然后再定位百度输入框。switch_to_frame() 默认可以直接取表单的id 或name 属性进行切换. 如果完成了在当前表单上的操作可以通过switch_to_default_content()方法返回到上一层表单, 不用指定某个表单的返回,默认对应与它最近的switch_to_frame()方法。
Frame.py
#coding=utf-8
from selenium importwebdriver
import time,os
driver=webdriver.Chrome()
file_path="file:///"+os.path.abspath("frame.htm")
driver.get(file_path)
driver.switch_to_frame("if")
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(3)
driver.switch_to_default_content()
time.sleep(3)
driver.close()
4.10 多窗口切换
有时候需要在不同的窗口切换,从而操作不同的窗口上的元素。WebDriver 提供了switch_to_window()方法可以切换到任意的窗口。Window.py
#conding=utf-8
from selenium import webdriver
driver=webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
search_windows=driver.current_window_handle
driver.find_element_by_link_text(u‘登录‘).click()
driver.find_element_by_link_text(u‘立即注册‘).click()
all_handles=driver.window_handles
#进入注册窗口
for handle in all_handles:
if handle !=sreach_windows:
driver.switch_to_window(handle)
print ‘now registerwindow!‘
driver.find_element_by_name("account").send_keys(‘username‘)
driver.find_element_by_name(‘password‘).send_keys(‘password‘)
#进入搜索窗口
for handle in all_handles:
if handle ==sreach_windows:
driver.switch_to_window(handle)
print ‘now sreachwindow!‘
driver.find_element_by_id(‘TANGRAM__PSP_2__closeBtn‘).click()
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(5)
driver.close()
整个脚本的处理过程:首先打开百度首页,通过current_window_handle 获得当前窗口的句柄,并给变量sreach_handle。接着打开登录弹窗,在登录窗口上点击“立即注册”从而打开新的注册窗口。通过window_handles 获得当前打开的所窗口的句柄,赋值给变量all_handles。
第一个循环遍历all_handles,如果handle 不等于sreach_handle,那么一定是注册窗口,因为脚本执行只打开的两个窗口。所以,通过switch_to_window()切换到注册页进行注册操作。第二个循环类似,不过这一次判断如果handle 等于sreach_handle,那么切换到百度搜索页,关闭之前打开的登录弹窗,然后时行搜索操作。
在本例中所有用到的新方法:
current_window_handle 获得当前窗口句柄
window_handles 返回的所有窗口的句柄到当前会话
switch_to_window()
用于切换到相应的窗口,与上一节的switch_to_frame() 是类似,前者用于不同窗口的切换,后者用于不同表单之间的切换。
4.11 警告框处理
在WebDriver 中处理JavaScript 所生成的alert、confirm 以及prompt是很简单的。具体做法是使用switch_to_alert()方法定位到alert/confirm/prompt。然后使用text/accept/dismiss/send_keys按需进行操做。
l text 返回alert/confirm/prompt中的文字信息。
l accept 点击确认按钮。
l dismiss 点击取消按钮,如果有的话。
l send_keys 输入值,这个alert\confirm没有对话框就不能用了,不然会报错。
弹出框不能通过前端工具对其进行定位,可以通过switch_to_alert()方法接收这个弹窗。
Alert.py
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time
driver=webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
#mouse stop set link
link=driver.find_element_by_name("tj_settingicon")
ActionChains(driver).move_to_element(link).perform()
#open search setting
driver.find_element_by_link_text(u‘搜索设置‘).click()
#save set
driver.find_element_by_link_text(u‘保存设置‘).click()
#recieve pop_window
driver.switch_to_alert().accept()
time.sleep(5)
driver.close()
ActionChains 类所提供的move_to_element()鼠标悬停的使用,将鼠标悬停在“搜索”链接上然后弹出下拉菜单。在菜单中点击“搜索设置”按钮。设置完成点击“保存设置”弹出警告框。通过switch_to_alert()方法获取当前页上的警告框,accept()接受警告框。
4.12 上传文件
对于web页面的上传功能,点击上传按钮需要打开本地的window窗口,从窗口选择本地文件进行上传,那么webdriver对于windows的控件是无能为力的。
对于web页面的上传功能一般会有以下几种方式。
普通上传:普通上传都是将本地文件的路径作为一个值放在input标签中,通过form表单提交的时候将这个值提交给服务器。
插件上传:一般是指基于flash与JavaScript或ajax等技术所实现的上传功能或插件。
4.12.1 Send_keys()实现上传
通过input标签实现上传,通过send_keys()传入本地文件路径从而模拟上传功能。Upfile.htm:upfile.htm
Upfile.py
#coding=utf-8
from seleniumimport webdriver
import os,time
driver=webdriver.Chrome()
#open upfilefuntion page
file_path="file:///"+os.path.abspath("upfile.htm")
driver.get(file_path)
#locate theupload button and add file
driver.find_element_by_name("file").send_keys("D:\\session_help.txt")
time.sleep(10)
driver.close()
通过这种方法上传,就绕开了操作Windows控件的步骤。如果能找上传的input 标签,那么基本都可以通过send_keys()方法向其输入一个文件地址来实现上传。
4.12.2 AutoIt 实现上传
Autolt 是一个使用类似basic脚本语言的免费软件,它设计用于windows GUI中进行自动化操作。它利用模拟键盘按键,鼠标移动和窗口/控件的组合来实现自动化任务。
官方网站:https://www.autoitscript.com/site/
AutoIt Windows Info 用于帮助我们识Windows 控件信息。
Compile Script to.exe 用于将AutoIt 生成exe 执行文件。
Run Script 用于执行AutoIt 脚本。
SciTE Script Editor 用于编写AutoIt 脚本。
下面以操作upload.html 上传弹出的窗口为例讲解AutoIt 实现上传过程。
1、 首先打开AutoIt Windows Info 工具,鼠标点击Finder Tool,鼠标将变成一个小风扇形状的图标,按住鼠标左键拖动到需要识别的控件上。
如图4.14、4.15,通过AutoIt WindowsInfo 获得以下信息。
窗口的title 为“选择要加载的文件”,标题的Class 为“#32770”。
文件名输入框的class 为“Edit”,Instance 为“1”,所以ClassnameNN 为“Edit1”。
打开按钮的class 为“Button”,Instance 为“1”,所以ClassnameNN 为“Button1”。
2、根据AutoItWindows Info 所识别到的控件信息打开SciTEScript Editor 编辑器,编写脚本。
ControlFocus()方法用于识别Window 窗口。WinWait()设置10 秒钟用于等待窗口的显示,其用法与WebDriver所提供的implicitly_wait()类似。ControlSetText()用于向“文件名”输入框内输入本地文件的路径。这里的Sleep()方法与Python 中time 模块提供的Sleep()方法用法一样,不过它是以毫秒为单位,Sleep(2000)表示固定休眠2000 毫秒。ControlClick()用于点击上传窗口中的“打开”按钮。
AutoIt 的脚本已经写好了,可以通过菜单栏“Tools”-->“Go” (或按键盘F5)来运行一个脚本吧!注意在运行时上传窗口当前处于打开状态。
3、 脚本运行正常,将其保存为upfile.au3,这里保存的脚本可以通过Run Script 工具将其打开运行,但我们的目的是希望这个脚本被Python 程序调用,那么就需要将其生成exe 程序。打开Compile Script to.exe工具,将其生成为exe 可执行文件。如图4.16,
点击“Browse”选择upfile.au3 文件,点击“Convert”按钮将其生成为upfile.exe 程序。
4、下面就是通过自动化测试脚本调用upfile.exe 程序实现上传了。Upfile_by_autoit.py:
#coding=utf-8
from seleniumimport webdriver
import os,time
driver=webdriver.Chrome()
#open theupload funtion page
file_path="file:///"+os.path.abspath("upfile.htm")
driver.get(file_path)
time.sleep(10)
#click theopen upload window
driver.find_element_by_name("file").click()
#callupfile.exe programe
os.system("C:\\Users\\ewang\\Desktop\\Python_Selenium2\\upflie.exe")
driver.close()
4.13 操作Cookie
有时候我们需要验证浏览器中是否存在某个cookie,因为基于真实的cookie 的测试是无法通过白盒和集成测试完成的。WebDriver 提供了操作Cookie 的相关方法可以读取、添加和删除cookie 信息。
webdriver 操作cookie 的方法有:
get_cookies() 获得所有cookie 信息
get_cookie(name) 返回有特定name 值有cookie 信息
add_cookie(cookie_dict) 添加cookie,必须有name 和value 值
delete_cookie(name) 删除特定(部分)的cookie 信息
delete_all_cookies() 删除所有cookie 信息
下面通过get_cookies()来获取当前浏览器的cookie 信息。Cookie.py
#coding=utf-8
from seleniumimport webdriver
import time
driver=webdriver.Chrome()
driver.get("http://www.youdao.com")
cookie=driver.get_cookies()
ck_nu=0
for ck incookie:
ck_nu=ck_nu+1
print "the %d cookie: \t %r \n" %(ck_nu,ck)
driver.close()
通过打印结果可以看出,cookie是以字典的形式进行存放的,知道了cookie 的存放形式,那么我们就可以按照这种形式向浏览器中写入cookie 信息。Add_cookie.py
#coding=utf-8
from selenium import webdriver
import time
driver=webdriver.Chrome()
driver.get("http://www.youdao.com")
driver.add_cookie({‘name‘:‘key-enlong‘,‘value‘:‘value-loveyou‘})
for ck in driver.get_cookies():
print "%s -> %s" %(ck[‘name‘], ck[‘value‘])
driver.close()
那么在什么情况下会用到cookie 的操作呢?例如开发人员开发一个功能,当用户登录后,会将用户的用户名写入浏览器cookie,指定的key 为“username”,那么我们就可以通过get_cookies() 找到useranme,打印vlaue,如果找不到username 或对应的value 为空,那么说明保存浏览器的cookie 是有问题的。
delete_cookie() 和delete_all_cookies()的使用也很简单,前者通过name 值到一个特定的cookie 将其删除,后者直接删除浏览器中的所有cookies()信息。
4.14 调用JavaScript
WebDriver不能操作本地windows控件,但对于浏览器的控件也不是都可以操作的。比如浏览器上的滚动条,虽然webdriver提供操作浏览器的前进和后退按钮,但对与滚动条并没有提供相应用的方法。Webdriver提供了execute_script()方法来执行JavaScript。
一般操作滚动条的会有两个场景:
l 注册时的法律条文的阅读,判断用户是否阅读完成的标准是:滚动条是否拉倒最下方。
l 操作的页面不在视觉范围,无法执行操作,需要拖动滚动条。
用于标识滚动条位置的代码:
<bodyonload= "document.body.scrollTop=0 ">
<bodyonload= "document.body.scrollTop=100000 ">
document.body.scrollTop:scrollTop 设置或获取滚动条与最顶端之间的距离。如果想让滚动条处于顶部,那么可以设置scrollTop 的值为0,如果想让滚动条处于最底端,可以将这个值设置的足够大,大个窗口的高度即可。HTML.PY:
#coding=utf-8
from seleniumimport webdriver
import time
driver=webdriver.Chrome()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(3)
js="varq=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(3)
js_="varq=document.documentElement.scrollTop=0"
driver.execute_script(js_)
time.sleep(3)
driver.close()
通过JavaScript 代码控制滚动条在任意位置,需要改变的就是scrollTop 的值。通过execute_script()方法来执行这段JavaScript 代码。当然,JavaScript 的作用不仅于此,它同样可操作页面上的元素或让,或让这个元素隐藏。
4.15 窗口截图
自动化脚本是交给工具去执行,有时候打印的错误信息并十分不明确,如果在执行脚本出错的时候将对当前窗口截图保存,通过图片信息的找到脚本出错的原因。Webdriver提供了截图函数get_screenshot_as_file()来截取当前窗口。Screenshot.py
#coding=utf-8
from selenium import webdriver
driver=webdriver.Chrome()
driver.get("http://www.baidu.com")
try:
driver.find_element_by_id("kw_22").send_keys("selenium")
driver.find_element_by_id("su").click()
except :
driver.get_screenshot_as_file("D:\\BAIDU.JPG")
driver.quit()
本例中百度输入框的id=kw_error 会定位不到元素,那么try就会捕捉到这个异常,从而执行except,在except 中执行get_screenshot_as_file()对当前窗口进行截图,这里需要指定图片的保存路径及文件名,并且关闭当前驱动。脚本运行完成打开D 盘就可以找到baidu_error.jpg 图片文件了。
4.16 关闭窗口
Quit()方法:退出相关的驱动程序和关闭所有窗口
Close()方法:用于关闭当前窗口
当脚本在执行时打开了多个窗口,这个时候只能关闭其中的某一个窗口,这个时候就需要使用close()来关闭。
4.17 验证码的处理
1. 去掉验证码
这是最简单的方法,对于开发人员来说,只是把验证码的相关代码注释掉即可,如果是在测试环境,这样做可省去了测试人员不少麻烦,如果自动化脚本是要在正式环境跑,这样就给系统带来了一定的风险。
2. 设置万能码
去掉验证码的主要是安全问题,为了应对在线系统的安全性威胁,可以在修改程序时不取消验证码,而是程序中留一个“后门”---设置一个“万能验证码”,只要用户输入这个“万能验证码”,程序就认为验证通过,否则按照原先的验证方式进行验证。
1. 验证码识别技术
例如可以通过Python-tesseract 来识别图片验证码,Python-tesseract 是光学字符识别Tesseract OCR 引擎的Python 封装类。能够读取任何常规的图片文件(JPG, GIF ,PNG , TIFF 等)。不过,目前市面上的验证码形式繁多,目前任何一种验证码识别技术,识别率都不是100%
2. 记录cookie
通过向浏览器中添加cookie 可以绕过登录的验证码,这是比较有意思的一种解决方案。比如我们在第一次登录某网站可以勾选“记住密码”的选项,当下次再访问该网站时自动就处于登录状态了。这样其实也绕过验证码问题。那么这个“记住密码”的功能其实就记在了浏览器的cookie 中。WebDriver 来操作浏览器的Cookie,可以通过add_cookie()方法将用户名密码写入浏览器cookie ,再次访问网站时服务器直接读取浏览器Cookie 登录。
这种方式最大的问题是如何从浏览器的Cookie 中找到用户名和密码对应的key 值,并传传输入对应的登录信息。可以get_cookies()方法来获取登录的所有的cookie 信息,从中找到用户名和密码的key。当然,如果网站登录时根本不将用户名和密码写Cookie,这会存在一定的安全风险。那么这种方式就不起作用了。
4.18 WebDriver 原理
WebDriver是按照server-client的经典设计经典模式设计。
webdriver 的工作流程:
1. WebDriver 启动目标浏览器,并绑定到指定端口。该启动的浏览器实例,做为WebDriver 的remote server。
2. Client 端通过CommandExcuter 发送HTTPRequest 给remote server 的侦听端口(通信协议:the webriver wire protocol)
3. Remote server 需要依赖原生的浏览器组件(如:IEDriverServer.exe、chromedriver.exe),来转化转化浏览器的native 调用。
在Python 提供了logging 模块,logging 模块给运行中的应用提供了一个标准的信息输出接口。它提供了basicConfig()方法用于基本信息的定义。将debug 模块开启。就可以捕捉到客户端与服务器的交互信息。basicConfig()开启的debug 模式只能捕捉到客户端向服务器所发送的POST 请求,而无法获取服务器所返回应答信息。Test.py
#coding=utf-8
from selenium import webdriver
import logging
logging.basicConfig(level=logging.DEBUG)
diver = webdriver.Chrome()
diver.get("http://www.baidu.com")
diver.find_element_by_id("kw").send_keys("selenium")
diver.find_element_by_id("su").click()
diver.quit()