现状
好久好久没有更新博客了,应该有一个月了吧,这段时间内,好忙,公司的业务在上涨期,但是却把下面的一个小朋友砍掉了(换组),所以很多打杂的时候都让jb去做了,基本上每天活着跟咸鱼一样~
虽然是咸鱼,但是还是要学习,最近在返璞归真,做了那么多年的测试狗,还是要学习点理论知识,毕竟得有些料才能吹的更愉快;
这段时间基本上都是在学习测试相关的书籍,测试工作,理论知识等,也看到不同的测试书籍,感觉很多都很差强人意,每本书都总觉得有所欠缺,如果有机会,挺想自己撸一本的,哈哈哈;
本篇作为阅读篇的第一篇,主要来介绍下selenium,介绍的原因是,最近有些项目是web端的,随着项目的稳定,后面会考虑自动化,而PC的自动化,基本上都是用selenium,那就来围观吧~
前言
之前看coder-pig文章时有大致了解,很早之前也听过selenium,但是还是想系统看一遍,听说虫师的这本书还可以,因此就来学习学习下~
虽然这部书叫selenium,但是有大致三分之二的内容是测试跟Python相关的内容,因此会优先介绍selenium相关内容,最后会贴一些自己觉得有点用的信息;
说明,本篇内容是基于coder-pig的原文进行补充及介绍,算是一个整理;
书籍信息
本书全名:Selenium 2 自动化测试实战,基于Python语言 作者:虫师 出版社:电子工业出版社 版次:2016年1月第1版
Selenium
简介
Selenium是一个自动化测试框架,通过他,可以编写代码让浏览器:
- 自动加载网页,获取当前呈现页面的源码;
- 模拟点击和其他交互方式,最常用:模拟表单提交(比如模拟登录);
- 页面截屏;
- 判断网页某些动作是否发生,等等。
Selenium是不支持浏览器功能的,需要和第三方的浏览器一起搭配使用,支持下述浏览器,你需要把对应的浏览器驱动下载到Python的对应路径下:
- Chrome:sites.google.com/a/chromium.…
- FireFox:github.com/mozilla/gec…
- PhantomJS:phantomjs.org/
- IE:selenium-release.storage.googleapis.com/index.html
- Edge:developer.microsoft.com/en-us/micro…
- Opera:github.com/operasoftwa…
安装
直接利用pip命令进行安装,命令如下:
pip install selenium
复制代码
接着下载浏览器驱动,大部分用的Chrome浏览器,就以此为例,其他浏览器可自行搜索相关文档,打开Chrome浏览器键入:
chrome://version
复制代码
即可查看Chrome浏览器版本的相关信息,主要是关注版本号:
Google Chrome 68.0.3440.106 (正式版本) (32 位) (cohort: Stable)
修订版本 1c32c539ce0065a41cb79da7bfcd2c71af1afe62-refs/branch-heads/3440@{#794}
操作系统 Windows
JavaScript V8 6.8.275.26
Flash 30.0.0.154 C:\Users\jb\AppData\Local\Google\Chrome\User Data\
PepperFlash\30.0.0.154\pepflashplayer.dll
用户代理 Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/68.0.3440.106 Safari/537.36
命令行 "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
--flag-switches-begin --flag-switches-end
可执行文件路径 C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
个人资料路径 C:\Users\jb\AppData\Local\Google\Chrome\User Data\Default
复制代码
这里看到,大版本号是68,接下来到下面的这个网站查看对应的驱动版本号:
https://chromedriver.storage.googleapis.com/2.41/notes.txt
复制代码
可以看到如下的版本号信息。
----------ChromeDriver v2.41 (2018-07-27)----------
Supports Chrome v67-69
Resolved issue 2458: Chromedriver fails to start with whitelisted-ips option [[Pri-1]]
Resolved issue 2379: Returned capabilities should include remote debugging port [[Pri-2]]
Resolved issue 1005: driver.manage().window().getSize() is not implemented on Android [[Pri-2]]
Resolved issue 2474: desktop launcher error messages are not readable by users [[Pri-]]
Resolved issue 2496: Fail fast when not able to start binary [[Pri-]]
Resolved issue 1990: Close Window return value does not conform with spec [[Pri-]]
复制代码
ok,那就是下载2.4.1这个版本驱动,链接:
https://chromedriver.storage.googleapis.com/index.html?path=2.41/
复制代码
打开后可以看到所示的页面,选择对应的系统下载即可。
下载完成后,把zip文件解压下,解压后的chromedriver.exe拷贝到Python的Scripts目录下,另外这里不用纠结win32,在64位的浏览器上也是可以正常使用的!Mac的话把解压后的文件拷贝到usr/local/bin目录下 ,Ubuntu的话则拷贝到usr/bin目录下。
demo
接下来,来个小demo吧:
# coding = utf-8
# 为了防止乱码问题,以及方便的在程序中添加中文注释,把编码统一成 UTF-8。
from selenium import webdriver
# 导入 selenium 的 webdriver 包,只有导入 webdriver 包我们才能使用 webdriver API 进行自动化脚本的开发。
browser = webdriver.Chrome()
#把webdriver的Chrome对象赋值给变量driver;
#只有获得了浏览器对象后,才可以启动浏览器,打开网址,操作页面元素,Chrome浏览器驱动默认已经在Selenium WebDriver包里了,可以直接调用;
#要先安装相关的浏览器驱动
browser.get("http://www.baidu.com")
#获得浏览器对象后,通过 get()方法,可以向浏览器发送网址。
html_text = browser.page_source
# 获得页面代码
browser.quit()
#退出并关闭窗口
复制代码
执行这段代码后,会自动调起Chrome浏览器,并访问百度,可以看到浏览器顶部有下面的提示。
并且控制台会输出HTML的代码,和Chrome的Elements页面结构完全一致。 那就可以用selenium这么玩了;
不过,在实践之前,再继续介绍下selenium其他方法吧;
API
定位元素
- find_element_by_id():根据id定位
- find_element_by_name():根据节点名定位
- find_element_by_class_name():根据class定位
- find_element_by_tag_name():通过tag定位
- find_element_by_link_text():根据链接的文本来定位
- find_element_by_partial_link_text():根据元素标签对之间的部分文本信息来定位
- find_element_by_xpath():使用Xpath进行定位
- find_element_by_css_selector():根据css定位
- find_element(By.XX,value):根据By来声明定位的方法,并且传入对应定位方法的定位参数,比如By.ID跟By.CLASS_NAME等
另外,如果把element改为elements会定位所有符合条件的元素,返回一个List,比如:
find_elements_by_class_name
复制代码
Selenium定位到结点位置会返回一个WebElement类型的对象,可以调用下述方法来提取需要的信息。
- 获取属性:
element.get_attribute()
- 获取文本:
element.text
- 获取标签名称:
element.tag_name
- 获取结点id:
element.id
控制窗口大小
# 设置浏览器宽480,高800显示
driver.set_window_size(480,800):
# 全屏显示
driver.maximize_window()
复制代码
页面前进,后退,切换
在页面操作过程中有时候点击某个链接会弹出新的窗口,这时候需要切换到新打开的窗口上进行操作;
# 通过window_handles来遍历
for handle in driver.window_handles:
driver.switch_to_window(handle)
# 切换窗口
driver.switch_to.window("窗口名")
# 或通过window_handles来遍历
for handle in driver.window_handles:
driver.switch_to_window(handle)
# 前进
driver.forward()
# 后退
driver.back()
复制代码
刷新动作
driver.refresh()
复制代码
清除文本,模拟按键输入,点击动作
# clear()用于清除文本输入框中的内容
driver.find_element_by_id("idinput").clear()
# send_keys()用于模拟键盘向输入框里输入内容
driver.find_element_by_id("idinput").send_keys("username")
# click()用于进行点击操作
driver.find_element_by_id("loginbtn").click()
复制代码
提交表单
# 通过定位搜索框并通过submit()提交搜索框的内容,达到点击搜索按钮的效果
driver.find_element_by_id("query").submit()
复制代码
鼠标动作
有时需要在页面上模拟鼠标操作,比如:单击,双击,右键,按住,拖拽等,可以导入ActionChains类:selenium.webdriver.common.action_chains.ActionChains,使用ActionChains(driver).XXX调用对应节点的行为。
- click(element):单击某个节点;
- click_and_hold(element):单击某个节点并按住不放;
- context_click(element):右键单击某个节点;
- double_click(element):双击某个节点;
- drag_and_drop(source,target):按住某个节点拖拽到另一个节点;
- drag_and_drop_by_offset(source, xoffset, yoffset):按住节点按偏移拖拽
- key_down:按下特殊键,只能用(Control, Alt and Shift),比如Ctrl+C
- ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform();
- key_up:释放特殊键;
- move_by_offset(xoffset, yoffset):按偏移移动鼠标;
- move_to_element(element):鼠标移动到某个节点的位置;
- move_to_element_with_offset(element, xoffset, yoffset):鼠标移到某个节点并偏移;
- pause(second):暂停所有的输入多少秒;
- perform():执行操作,可以设置多个操作,调用perform()才会执行;
- release():释放鼠标按钮
- reset_actions:重置操作
- send_keys(keys_to_send):模拟按键,
比如输入框节点.send_keys(Keys.CONTROL,'a') 全选输入框内容,
输入框节点.send_keys(Keys.CONTROL,'x')剪切,
模拟回退: 节点.send_keys(keys.RETURN);
或者直接设置输入框内容:输入框节点.send_keys('xxx'); - send_keys_to_element(element, *keys_to_send):和send_keys类似;
键盘事件
send_key()虽然可以模拟键盘输入,但除此之外,还需要输入其他按键,比如空格,这时候就需要用到Keys(); 对应类:selenium.webdriver.common.keys.Keys,使用send_keys(Keys.XX)输入对应的内容即可;
- BACK_SPACE:删除键(BackSpace)(send_key(Keys.BACK_SPACE))
- SPACE:空格键(Space)
- TAB:制表键(TAB)
- ESCAPE:回退键(Esc)
- ENTER:回车键(Enter)
- CONTROL,'a':全选(Ctrl+A)(send_key(Keys.CONTROL,'a'))
- CONTROL,'c':复制(Ctrl+C)
- CONTROL,'x':剪切(Ctrl+X)
- CONTROL,'v':粘贴(Ctrl+V)
- F1:键盘F1
- ...
- F12:键盘F12
页面标题和链接
# 获取当前网页的标题
driver.title
# 获取当前网页的url
driver.current_url
复制代码
页面等待
现在的网页越来越多采用了 Ajax技术,这样程序便不能确定何时某个元素完全加载出来了。
如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。
为了避免这种元素定位困难而且会提高产生ElementNotVisibleException的概率。
所以Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。
- 显式等待:
指定某个条件,然后设置最长等待时间。
如果在这个时间还没有找到元素,那么便会抛出异常,代码示例如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 库,负责循环等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 类,负责条件出发
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.PhantomJS()
driver.get("http://www.xxxxx.com/loading")
try:
# 每隔10秒查找页面元素 id="myDynamicElement",直到出现则返回
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
复制代码
如果不写参数,程序默认会0.5s调用一次来查看元素是否已经生成,如果本来元素就是存在的,那么会立即返回。
下面是一些内置的等待条件,你可以直接调用这些条件,而不用自己写某些等待条件了。
等待条件 | 描述 |
---|---|
title_is | 标题是内容 |
title_contains | 标题包含某内容 |
presence_of_element_located | 结点加载出来,传入定位元组 |
visibility_of_element_located | 结点课件,传入定位元组 |
visibility_of | 可见,传入结点对象 |
presence_of_all_elements_located | 所有结点加载出来 |
text_to_be_present_in_element | 某个结点文本包含某文字 |
text_to_be_present_in_element_value | 某个结点值包含某文字 |
frame_to_be_available_and_switch_to_it | 加载并切换 |
invisibility_of_element_located | 结点不可见 |
element_to_be_clickable | 节点可点击 |
staleness_of | 判断结点是否仍在DOM,常用于判断页面是否已刷新 |
element_to_be_selected | 结点可选择,传入结点对象 |
element_located_to_be_selected | 结点可选择,传入定位元组 |
element_selection_state_to_be | 传入结点对象和状态,相等返回True,否则返回False |
element_located_selection_state_to_be | 传入定位元组和状态,相等返回True,否则返回False |
alert_is_present | 是否出现警告 |
- 隐式等待:
隐式等待比较简单,就是简单地设置一个等待时间,单位为秒,代码示例如下:
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
如果不设置,就默认等待时间为0
复制代码
休眠sleep
有时候希望脚本执行到某个位置做固定时间的休眠,这时候就需要用到sleep(),这个sleep方法是由Python的time模块提供,因此使用之前需要from time import sleep;
# 休眠X秒
sleep(X)
复制代码
多表单切换
在web应用中经常会遇到frame/iframe表单嵌套页面的应用,webdriver只能在一个页面上对元素识别与定位,对于frame/iframe无法直接定位;
这时候就需要通过switch_to.frame()方法将当前定位的主体切换为frame/iframe内嵌的的页面中;
# 切换到iframe(id = "XX")
driver.switch_to.frame("XX")
复制代码
切换后就能正常操作元素了;
switch_to.frame()默认可以直接获取表单的id或name属性,但如果iframe没有可用的id和name属性呢?
# 先通过xpath定位到iframe
xf = driver.find_element_by_xpath("//*[@class="XX"]")
# 再将定位对象传给switch_to.frame()方法
driver.switch_to.frame(xf)
复制代码
弹窗
对应类:selenium.webdriver.common.alert.Alert,用得不多,如果你触发了某个事件,弹出了对话框,可以调用这个方法获得对话框:alert = driver.switch_to_alert(),然后alert对象可以调用下述方法:
- accept():确定
- dismiss():关闭对话框
- send_keys():传入值
- text():获得对话框文本
上传文件
一般网页上传文件,都是有一个浏览按钮,选择文件点击上传即可,但是对应做自动化测试来说,在选择文件那个过程是非常麻烦的;
其实,做过类似功能的同学会发现,浏览按钮其实就是input标签实现的上传功能,可以看到是一个输入框,居然如此,就可以用send_keys()来模拟;
driver.find_element_by_name("file").send_keys("C:\\jb.txt")
复制代码
下载文件
运行设置文件下载路径;
options = webdriver.ChromeOptions()
prefs = {'profile.default_content_settings.popups': 0, 'download.default_directory': os.getcwd()}
options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(chrome_options=options)
driver.get("http://pypi.Python.org/pypi/selenium")driver.find_element_by_partial_link_text("selenium-3.11.0-py2.py3-none-any").click()
复制代码
页面截图
driver.save_screenshot("截图.png")
# 截取当前窗口,并指定截图图片的保存位置
dirver.get_screenshot_as_file("C:\\jb\\jb.jpg")
复制代码
Cookies
有些站点需要登录后才能访问,用Selenium模拟登录后获取Cookie,
然后供爬虫使用的场景非常常见,Selenium提供了获取,增加,删除Cookies的函数,代码示例如下:
# 获取所有Cookies
browser.get_cookies()
# 获取name对应的cookie信息
browser.get_cookie(name)
# 增加Cookies,是字典对象,必须要有name 和value
browers.add_cookie({xxx})
driver.add_cookie({"name":"jb","value":"jbtest"})
# 如果需要遍历,则如下:
for cookie in driver.get_cookies():
print("%s -> %s " % (cookie["name"],cookie["value"]))
# 删除所有Cookies
browser.delete_cookies()
# 删除Cookie信息,name是要删除的cookie的名称,optionsString是该cookie的选项,目前支持的选项包括“路径”和“域”
browser.delete_cookie(name,optionsString)
复制代码
实践:
from selenium import webdriver
browser = webdriver.Chrome()
url = "https://www.baidu.com/"
browser.get(url)
# 通过js新打开一个窗口
newwindow='window.open("https://www.baidu.com");'
# 删除原来的cookie
browser.delete_all_cookies()
# 携带cookie打开
browser.add_cookie({'name':'ABC','value':'DEF'})
# 通过js新打开一个窗口
browser.execute_script(newwindow)
input("查看效果")
browser.quit()
复制代码
这里还是需要说下,add_cookie方法接受一个字典,字典中包含name,value,path,domain,secure,expiry,
正确的写cookie格式:
cookie = {
# "domain": ".58.com", #Firefox浏览器不能写domain,如果写了会报错,谷歌需要写否则也是报错,这里就是一个坑。其他浏览器没测试不知道情况。
'name': name,
'value': value,
"expires": "",
'path': '/',
'httpOnly': False,
'HostOnly': False,
'Secure': False,
}
name:cookie的名称
value:cookie对应的值,动态生成的
domain:服务器域名
expiry:Cookie有效终止日期
path:Path属性定义了Web服务器上哪些路径下的页面可获取服务器设置的Cookie
httpOnly:防脚本攻击
secure:在Cookie中标记该变量,表明只有当浏览器和Web Server之间的通信协议为加密认证协议时
复制代码
为什么要构造成这样子,其实我们看下浏览器保存的cookie格式就明白了。下图就是谷歌浏览器的cookie 的截图。
代码应该这么写:
这里有个问题,cookie要key:value的格式,是非常麻烦的,尤其是像豆瓣那样非常非常长的cookie,再手动一个一个改格式,这个工作量还不如重新用selenium写一个登陆操作;
fiddler转包的cookie格式是这样的:
一个一个改会崩溃的;所以遇到cookie很长的情况,还不如写一个登陆脚本保存吧~
执行JS语句
虽然webdriver提供浏览器的前进和后退,但是并不提供滚动浏览器的操作,因此来借助JS来控制浏览器的滚动条;
driver.execute_script(js语句)
复制代码
比如滚动到底部的代码示例如下:
js = document.body.scrollTop=10000
driver.execute_script(js)
复制代码
又如设置浏览器窗口的滚动条位置:
js = "window.scrollTo(100,450)"
driver.excute_script(js)
复制代码
向文本框输入文本信息:
text = "jbtest"
js = "var sum=document.getElementById("id"); sum.value='"+text+ " ';"
driver.excute_script(js)
复制代码
处理HTML5 的视频播放
HTML5定义了一个新的元素video,指定了一个标准的方式来嵌入电影片段;
from selenium import webdriver
from time import sleep
driver = webdriver.Firefox()
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)
# 播放视频
driver.execute_script("return arguments[0].play()",video)
# 暂停视频
driver.execute_script("arguments[0].pause()",video)
复制代码
JS函数有个内置的对象叫做arguments; arguments对象包含了函数调用的参数数组,[0]表示取对象的第一个值;
- currentSrc:返回当前音频/视频的URL,如果未设置音频/视频,则返回空字符串;
- load():控制着视频的加载
- play():控制着视频的播放
- pause():控制着视频的暂停
Headless
在介绍Headless之前,必须介绍下PhantomJS,
PhantomJS是没有界面的浏览器,特点:
会把网站加载到内存并执行页面上的JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效
而上面的例子,每次执行后,都会打开浏览器,很麻烦,这么看,PhantomJs是刚需啊;
但这里不打算介绍PhantomJs,因为18年4月份,维护者宣布退出PhantomJs,意味着这个项目不再维护了;而同时,Chrome和FireFox也开始 提供Headless模式(无需调起浏览器),所以,后面的phantomjs小伙伴会迁移到这两个浏览器上;
注意:Windows Chrome需要60以上的版本才支持 Headless模式,linux,unix系统需要 chrome浏览器 >= 59
启用Headless模式也很简单,以上面打开百度的代码举例,代码如下:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_option = Options()
chrome_option.add_argument("--headless")
chrome_option.add_argument("--disable-gpu")
browser = webdriver.Chrome(chrome_options=chrome_option) # 调用本地的Chrome浏览器
browser.get('http://www.baidu.com') # 请求页面,会打开一个浏览器窗口
html_text = browser.page_source # 获得页面代码
browser.quit() # 关闭浏览器
print(html_text)
复制代码
就是多了设置chrome_option这几步,执行后,就不会再弹出浏览器了,是不是很方便??
设置自定义请求头
from selenium import webdriver
# 进入浏览器设置
options = webdriver.ChromeOptions()
# 设置中文
options.add_argument('lang=zh_CN.UTF-8')
# 更换头部
options.add_argument('user-agent="Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20"')
browser = webdriver.Chrome(chrome_options=options)
url = "https://httpbin.org/get?show_env=1"
browser.get(url)
browser.quit()
复制代码
温馨提示:遇到JS加载的问题,建议先尝试破解JS,不行再用selenium,selenium属于无脑类型,而且效率比较差,假如你有1W个网站,都跑一趟,估计要一天了;
大部分selenium相关的操作都介绍完了,先留个印象,那接下来,让我们看看怎么用selenium来获取豆瓣验证码captcha这个属性吧;
"Cookie":"your cookie" #这里需要输入你自己的cookie信息,如果遇到转义字符,转
义字符前面加\即可
复制代码
Selenium详细介绍
什么是Selenium
Selenium主要用于Web应用程序的自动化测试;
特点:
- 开源,免费;
- 多浏览器支持:Firefox、Chrome、IE、Opera、Edge;
- 多平台支持:Linux、Windows、MAC;
- 多语言支持:Java、Python、Ruby、C#、JavaScript、C++;
- 对Web页面有良好的支持;
- API简单、灵活(用开发语言驱动)
- 支持分布式测试用例执行
Selenium有两个版本:Selenium 1.0 和Selenium 2.0; Selenium不是由单独一个工具构成的,而是由一些插件、类库组成,每个部分都有起特点和应用场景;
Selenium 1.0家谱:
Selenium IDE
Selenium IDE是嵌入到Firefox浏览器中的一个插件,实现简单的浏览器操作的录制与回放功能;
官方给出它自身作用的定位:
快速地创建bug重现脚本,在测试人员测试过程中,发现bug之后可以通过IDE将重现的步骤录制下来,以帮助开发人员
更容易的重现bug;
复制代码
那就可以理解,IDE的重点在于录制,避免不会写代码的同学,而且每次写xpath也会很烦;
安装
在线安装 通过 firefox 浏览器访问 selenium;
在 selenium IED 下载介绍部分,点击版本号链接;
firefox 浏览器将自动识别需要下载的 selenium IED 插件,,点击 Install Now 按钮,安装 selenium IED 插件。
安装完成后重启 firefox 浏览器,通过菜单栏“Tools(工具)”---> selneium IDE 可以打开,或通过 Ctrl+Alt+S 快捷键打开。
但是实际,上面的url,试了半天都访问不了,另外还有,如果非Firefox浏览器是不是就用不了IDE?
插件安装 非也,还有个插件安装的方法,此方法来自小敏同学亲测可行,Python2.7版本,Firefox40.0版本;
1)python2.7 mac/Linux自带,不用装; Windows需要手动安装,要装的小伙伴自行百度,so easy ~
2)selenium 由于selenium IDE在新版本firefox上并不支持,没有录制功能写起来还是挺费神的,建议保守的都选择旧版本。
如果已经安装了selenium3,需要先卸载;
查看selenium版本命令:
pip show selenium
卸载selenium命令:
pip uninstall selenium
复制代码
selenium用命令行pip install selenium==2.53.6安装时,由于被墙了,选择下载安装包自行安装,步骤如下:
- 下载安装包selenium-2.53.6.tar.gz
- 将安装包放到python2.7的site-packages目录下,解压,比如目录是/Library/Python/2.7/site-packages/
- cd到上一步解压后的selenium目录下,python setup.py install,安装完成,查看版本号确认安装成功
3)下载安装firefox 40.0版本
4)下载selenium_ide-2.9.1-fx.xpi,拖到firefox里面安装好后,firefox右上角多出selenium IDE插件入口
5)下载firebug-2.0.16-fx.xpi,拖到firefox里面安装好后,firefox右上角多出firebug插件入口
至此,环境安装完成。
6)录制自动化脚本 点击firefox右上角selenium IDE插件图标,进入selenium IDE主界面;
- 在下图序号1红框中,输入你要测试的web url;
- 在下图序号2红框中,调节你要执行用例的速度,一般建议调到中间;
- 在下图序号3红框中,点击录制按钮开始录制;
- 在下图序号4红框中,对录制结果进行调节,可以增删改事件、参数;
- 在下图序号3红框中,点击停止录制按钮停止录制;
- 在下图序号5红框中,点击按钮开始执行用例;
- 可以在菜单中选择文件——export test case as——python 2/unittest/web driver,将脚本导出为python,本地编辑直接脚本调用。
7)优化脚本 上步中最后导出的脚本,只包含了操作,没有包含断言结果判断,也缺少容错,想要持续集成自动生成结果,还需要自己按需补充。
Selenium Grid
是一种自动的测试辅助功能,Grid通过利用现有的计算机基础设施,能加快Web-App的功能测试;
利用Grid可以很方便地实现在多台机器上和异构环境中运行测试用例;
听上去会一脸懵逼,简单说,Selenium Grid可以解决重复执行测试和多浏览器兼容测试的亮点,并且是使用分布式执行测试;
那分布式是什么概念?简单的说就是老大收到任务,分发给手下去干;
通过Selenium Grid的可以控制多台机器多个浏览器执行测试用例,分布式上执行的环境在Selenium Grid中称为node节点。
举例说明一下,比如用例上万,一台机器执行全部测试用例耗时5个小时,而如果需要覆盖主流浏览器比如Chrome、Firefox,加起来就是10个小时;
最笨的办法就是另外拿台机器,然后部署环境,把测试用例分开去执行然后合并结果即可。
而Selenium也想到了这点,所以有了Selenium Grid的出现,它就是解决分布式执行测试的痛点。
工作原理
Selenium Grid实际它是基于Selenium RC的,而所谓的分布式结构就是由一个hub节点和若干个node代理节点组成。
Hub用来管理各个代理节点的注册信息和状态信息,并且接受远程客户端代码的请求调用,然后把请求的命令转发给代理节点来执行。
下面结合环境部署来理解Hub与node节点的关系。
环境部署
1)下载selenium-server-standalone-2.53.1.jar
2)启动hub
使用快捷键WIN+R打开运行对话框,输入cmd确定,进入命令窗口
进入selenium-server-standalone-2.53.1.jar包的位置,如E:\selenium;
启动hub,命令如下:
java -jar selenium-server-standalone-2.53.1.jar -role hub -maxSession 10 -port 4444
复制代码
参数 | 解释 |
---|---|
role hub | 启动运行hub |
port | 设置端口号,hub的默认端口是4444,这里使用的是默认的端口,当然可以自己配置 |
maxSession | 最大会话请求,这个参数主要要用并发执行测试用例,默认是1,建议设置10及以上 |
浏览器打开地址:http://localhost:4444/grid/console,出现如下图表示hub启动成功。
启动hub后,就需要运行节点啦,最少都要有一个node节点,不然hub就成空头司令了;而node节点可以与hub在同一台机器上运行,演示一个node节点与hub同机,另一个node节点启动了一台虚拟机。
名称 | IP |
---|---|
hub机 | 192.168.0.245 |
node1机 | 192.168.0.245 |
node2机 | 192.168.0.183 |
3)启动node节点1
node1节点,配置firefox浏览器,运行下面命令:
java -jar selenium-server-standalone-2.53.1.jar -role node -port 5555 -hub http://192.168.0.245:4444/grid/register -maxSession 5 -browser browserName=firefox,seleniumProtocol=WebDriver,maxInstances=5 ,platform=WINDOWS,version=45.0.2
复制代码
没有报错则再次刷新一下http://localhost:4444/grid/console的访问会发现node节点已经显示,表示启动成功;
参数 | 解释 |
---|---|
role node | 启动运行node节点 |
port 555 | 指定node节点端口 |
hub http://192.168.0.245:4444/grid/register | hub机地址 |
maxSession 5 | node节点最大会话请求 |
browser browserName=firefox,seleniumProtocol=WebDriver, maxInstances=5,platform=WINDOWS,version=45.0.2 | 这个就是设置浏览器的参数啦 |
browserName表示浏览器名字,maxInstances表示最大实例,可以理解为最多可运行的浏览器数,不能大于前面maxSession的值,否则可能会出错;platform表示操作系统;version表示浏览器版本。
复制代码
4)启动node节点2
node2节点,在目录放了chromedriver.exe文件,这里要提示一下,这个chromedriver.exe文件前面说过下载地址了,主要是版本需要与系统中安装的chrome浏览器匹配;
java -jar selenium-server-standalone-2.53.1.jar -role node -port 6666 -hub http://192.168.0.245:4444/grid/register -Dwebdriver.chrome.driver=chromedriver.exe -maxSession 5 -browser browserName=chrome,seleniumProtocol=WebDriver,maxInstances=5,platform=WINDOWS
复制代码
没有报错则再次刷新一下http://localhost:4444/grid/console的访问会发现node节点已经显示,表示启动成功;
如果使用的chromedriver.exe与selenium-server-standalone-2.53.1版本或者浏览器chrome版本不匹配都会报错提示,具体原因需要具体解决。
参数 | 解释 |
---|---|
Dwebdriver.chrome.driver=chromedriver.exe | 浏览器插件,如果是其他浏览器就写对应的名字 |
如firefox: -Dwebdriver.firefox.driver=geckodriver.exe
注意多了这个参数注意是chromedriver.exe需要指定,而对于Webdriver2是支持geckodriver所以不需要指定geckodriver,但前提是firefox浏览器版本不能大于46,所以看到node节点1使用的是45版本的浏览器。
复制代码
使用
当实例化Hub远程时,会根据配置去匹配Hub上注册的node代理节点,匹配成功后转发给代理节点,这时候代理节点会生成sessionid启动浏览器,然后响应给Hub说一切准备就绪,Hub也会把这个sessionid响应给客户端,接下来的客户端的代码发来的请求都会被Hub转发给这个代理节点来执行。这里实际上整个流程与Selenium1.0的原理是一样的,只是多了Hub这一层。
DesiredCapabilities capability = new DesiredCapabilities();
capability.setBrowserName("chrome");
capability.setPlatform(Platform.WINDOWS);
try {
WebDriver driver = new RemoteWebDriver(new URL("http://192.168.0.245:4444/wd/hub"), capability);
driver.get("http://www.baidu.com");
driver.quit();
} catch (MalformedURLException e) {
e.printStackTrace();
}
复制代码
根据上面代码会发现node节点2执行,如果把setBrowserName()方法里面的传参改了firefox就会在node节点1执行。表示Selenium Grid环境搭建完成。
另外客户端还可以直接使用node节点运行代码,这样的方式就与selenium1.0一模一样啦,看下面代码:
DesiredCapabilities capability = new DesiredCapabilities();
capability.setBrowserName("chrome");
capability.setPlatform(Platform.WINDOWS);
try {
WebDriver driver = new RemoteWebDriver(new URL("http://192.168.0.183:6666/wd/hub"), capability);
driver.get("http://www.baidu.com");
driver.quit();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
复制代码
要注意实例化driver对象时填写的服务地址是node节点的地址,这样就会直接去节点运行;还有一个注意的就是DesiredCapabilities配置,一定要设置该节点运行参数正确的浏览器、浏览器版本、系统,如果参数不对都会出现报错。
Selenium RC
Selenium RC(Remote Control)是Selenium家族的核心部分; 支持多种不同语言编写的自动化测试脚本,通过Selenium RC的服务器作为代理服务器去访问应用,从而达到测试目的;
selenium RC 分为 Client Libraries 和 Selenium Server; Client Libraries 库主要主要用于编写测试脚本,用来控制 selenium Server 的库。 Selenium Server 负责控制浏览器行为;
总的来说,Selenium Server 主要包括 3 个部分: Launcher、Http Proxy、Core。
其中 Selenium Core 是被 Selenium Server 嵌入到浏览器页面中的。 其实 Selenium Core 就是一堆 JS 函数的集合,就是通过这些 JS 函数,我们才可以实现用程序对浏览器进行操作。
Launcher 用于启动浏览器,把 selnium Core 加载到浏览器页面当中,并把浏览器的代理设置为 Selenium Server 的Http Proxy。
Selenium 2.0
Selenium 2.0 是把 WebDriver 加入到了这个家族中; 简单用公式表示为:
selenium 2.0 = selenium 1.0 + WebDriver
在 selenium 2.0 中主推的是 WebDriver ,WebDriver 是 selenium RC 的替代品; 那么 selenium RC 与 webdriver 主要有什么区别呢?
Selenium RC 在浏览器中运行 JavaScript 应用,使用浏览器内置的 JavaScript 翻译器来翻译和执行 selenium 命令)。
WebDriver 通过原生浏览器支持或者浏览器扩展直接控制浏览器。
WebDriver 针对各个浏览器而开发,取代了嵌入到被测 Web 应用中的 JavaScript。与浏览器的紧密集成支持创建更高级的测试,避免了JavaScript 安全模型导致的限制。
除了来自浏览器厂商的支持,WebDriver 还利用操作系统级的调用模拟用户输入。
复制代码
WebDriver原理
WebDriver是按照Server-Client的设计模式设计的;
Server端就是Remote Server,可以是任意的浏览器; 当我们的脚本启动浏览器后,该浏览器就是Remote Server,职责就是等待Client发送请求并做出响应;
Client端简单理解就是测试代码; 脚本的行为是以http请求的方式发送给被测试的浏览器,浏览器接受请求,执行相应操作,并在response中返回执行状态,返回等信息;
WebDriver的工作流程:
- WebDriver启动目标浏览器,并绑定到指定端口;启动的浏览器实例将作为WebDriver的Remote Server;
- Client端通过CommandExcuter发送HTTPRequest给Remote Server 的侦听端口;
- Remote Server需要依赖原生的浏览器组件来转化浏览器的native调用;
小结
断断续续的看了这本书很久很久,还是因为自己懒;
看完这本书,对selenium的api至少留个印象,最重要的还是找控件的8种方式,一般如果Jb去面试,也会问这个问题,当然也会有selenium的原理以及2.0跟1.0的区别,不过后面几点只是做简单了解,不做任何评价;
可别忘记了,selenium对于是可以获取JS加载后的页面内容,如果想爬一个网页,而且内容是JS加载的,如果不想研究JS,就用selenium吧,贼好用的玩意;
立个flag,之前太忙了,导致一个月没更新博客,感觉人都废了,因此立一个,一周更新一篇的flag,看能坚持多久吧~
最后,贴这个这本书电子版的链接:
https://pan.baidu.com/s/1b8T6Iq?errno=0&errmsg=Auth%20Login%20Sucess&&bduss=&ssnerror=0&traceid=
复制代码
这里说明下,电子版跟实体书还是有点不一样,如果只是用来查api,看这篇文章或者看电子书就好了,主要的内容没什么变化;
谢谢大家~