Selenium
自动化工具介绍
- UFT 非开源
- RobotFramework
- 高度扩展
- 拥有大量的库
- 支持关键字驱动
- Selenium
- 业内普及
- 灵活
- 使用场景广泛
为什么要进行自动化测试?
- 目的
- 解决回归测试、压力测试、兼容性测试
- 提高测试效率保证产品质量
- 相关解释
- 回归测试:项目在发布新版本之前进行的功能验证
- 压力测试:可以理解多用户去操作软件,统计服务器处理用户请求的能力
- 兼容性测试:表示在不同浏览器下软件运行状态
- 如下三种情况一般需要使用自动化?
- 需求变动不频繁
- 项目周期长
- 项目需要回归测试
配置编程环境
- window下安装python3.7(傻瓜式安装)
- Linux下安装python3.7
- 安装selenium包 pip3 install selenium
- 下载谷歌、火狐、IE驱动
- 安装pycharm
selenium的使用
selenium安装、卸载以及查看命令
- 安装 pip install selenium
- 卸载 pip uninstall selenium
- 查看 pip show selenium
元素的定位
- id定位 find_element_by_id("kw") 注:有些id值动态变化
- class_name定位 find_element_by_class_name("s_ipt") 注:classname有可能重复
- tag_name定位 find_element_by_tag_name("input") 注:tagname最容易重复
- name定位 find_element_by_name("wd") 注:name有可能重复
- link文字精确定位 find_element_by_link_text("登录")
- link文字模糊定位 find_element_by_partial_link_text("登")
- CSS定位(常用定位策略) 在selenium中推荐使用css定位,因为它比xpath定位速度快
- id选择器 #id值
- class选择器 .class值
- 元素选择器 标签名 >表示直接子级 空格表示子级
- p[id="user"]>input 表示p元素(id为user)的直接子级 或者使用p#user>input
- p[id="user"] input 表示p元素(id为user)的子级 或者使用p#user input
- css延伸
- input[type^="p"] type属性以p字母开头的元素
- input[type$="d"] type属性以d结尾的元素
- input[type*="w"] type属性包含w字母的元素
- XPath定位的常规策略
- 路径
- 绝对路径 绝对路径对页面结构要求非常高,不建议使用
- 相对路径 匹配任意层级的元素,不限制元素的位置
- 相对路径以//开始
- 格式 //input或者//*
- 路径结合属性 //input[@placeholder="密码A"]
- 路径结合逻辑(多个属性)
- //input[@placeholder="密码A" and @name="password"]
- //p[@id="parent"]/input[@placeholder="密码A" and @name="password"
- 路径结合层级
- xpath的延伸
- //*[text()="xxx"] 文本内容是xxx的元素
- //*[contains(@attribute,"xxx")] 属性中含有xxx的元素
- //*[starts-weith(@attribute,"xxx")] 属性以xxx开头的元素
- 定位一组元素
- 通过下标操作定位元素 driver.find_elements_by_tag_name("input")[0].send_keys("吴鹏") 向一组input元素的第一个input输入内容
- 通过遍历操作定位元素 for el in elements:→el.send_keys("吴鹏")
SeleniumBuilder辅助定位元素
在火狐浏览器的附加组件中搜索添加SeleniumBuilder即可完全安装(老版本的还存在,新版本的已经被弃用)
元素操作方法
- 为什么要学习操作元素的方法?
- 需要让脚本模拟用户给指定元素输入值
- 需要让脚本模拟人为删除元素的内容
- 需要让脚本模拟点击操作
- 相关元素的操作方法
- send_keys() 扩展可以实现上传的操作(send_keys("文件路径"))
- click()
- clear() 清空
- maximize_window() 窗口最大化
- set_window_size(width,height) 设置浏览器窗口大小
- set_window_position(x,y) 设置浏览器窗口位置
- back() 后退,模拟浏览器后天按钮
- forward() 前进,模拟浏览器前进按钮
- refresh() 刷新,模拟浏览器F5刷新
- close() 关闭当前窗口,模拟电机架浏览器关闭按钮
- quit() 关闭浏览器驱动对象,关闭所有程序启动的窗口
- title 获取页面title
- current_url 获取当前页面URL
- get_screenshot_as_file("D://test/b1.img") 截屏
获取元素信息(及属性)的常用方法
- size 返回元素大小
- text 返回元素的文本(文本内容)
- get_attribute("xxx") 获取属性值,传递的参数为元素的属性名
- is_displayed() 判断元素是否可见
- is_enabled() 判断元素是否可用
- is_selected() 判断元素是否选中,用来检查复选框或单选按钮是否被选中
- title() 获取百度的title可以使用该方法
- tag_name 获取元素的标签名
- get_attribute("属性") 这里的参数类似于class、name等,也就是标签内部的属性,能够获取标签内部属性的属性值
- get_attribute("value") 获取输入框的默认文本值,在输入框输入的值也能获取
- dirver.name 获取浏览器名字
鼠标操作
- 对于鼠标操作需要导入ActionChains包 from selenium.webdriver.common.action_chains import ActionChains
- 鼠标事件常用的操作方法 初始化 action=ActionChains(driver)
- context_click() 右击 action.context_click(driver.find_element_by_css_selector("#user")).perform()
- selenium框架中虽然提供了右击鼠标方法,但是没有提供选择右击菜单方法,可以通过发送快捷键的方式解决(经过测试,谷歌浏览器不支持)
- double_click() 双击 action.double_click(driver.find_element_by_css_selector("#user").send_keys("admin")).perform()
- drag_and_drop() 拖拽 action.drag_and_drop(第一个元素,第二个元素).perform()
- action.drag_and_drop_by_offset(source,xoffset=360,yoffset=180).perform()
- move_to_element() 悬停 action.move_to_element(driver.find_element_by_css_selector("button")).perform()
- perform() 执行以上事件方法
键盘操作
selenium中把键盘的案件都封装在keys类中,导包 from selenium.webdriver.common.keys import keys
- 删除 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.BACK_SPACE) 单键就一个参数
- 全选 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"a") 组合键两个参数
- 复制 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"c")
- 粘贴 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"v")
- 剪切 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"v")
- F1-F12 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.F1)
元素等待
元素等待类型
- 隐式等待
- 什么是隐式等待? 定位元素时,如果能定位到元素则直接返回该元素,不触发等待,如果不能定位到该元素,则间隔一段时间再去定位如果超出,则抛出such**异常
2.方法 driver.implicitly_wait(timeout)
- 显式等待
- 什么是显式等待? 定位指定元素时,如果能定位到元素则直接返回该元素,不触发等待,如果不能定位到元素,则隔一段时间再去定位,如果超出,跑出time**异常
- 实现方式
- 导包 from selenium.webdriver.support.wait import WebDriverWait
- 调用方法 until(method):直到...时 一般使用匿名函数来实现
- element=WebDriverWait(driver,10,1).until(lambda x:x.find_element_by_id("useA"))
操作API
select下拉框
- 使用css去定位下拉框 如果option选项没有value值得话,css定位或者其他定位就不太方便
- 使用Select from selenium.webdriver.support.select import Select
- 通过下标 Select(driver.find_element_by_css_selector("#userA")).select_by_index(1)
- 通过value值 select_by_value(" ")
- 通过显示文本 select_by_visible_text(" ")
from selenium import webdriver
from selenium.webdriver.support.ui import Select
driver = webdriver.Firefox()
Select(driver.find_element_by_id("grid")).select_by_index(1)
Select(driver.find_element_by_id("grid")).select_by_value("二年级")
弹出框处理
常规alert、confirm、prompt处理办法
- 网页中常用的弹出框
- alert 警告框
- confirm 确认框
- prompt 提示框
- 弹出框的处理方法
- 获取弹出框对象 alert=driver.switch_to.alert
- 调用
- alert.text 返回弹出的文字信息
- alert.accept() 接受对话框选项(同意)
- alert.dismiss() 取消对话框选项(取消)
无用弹窗(类似于广告之类的弹窗)
现在大多数网站都会使用自定义弹窗,使用selenium自带的常规方法就驾驭不了了,于是下面采用js方式
# encoding:utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://sh.xsjedu.org/")
time.sleep(1)
js = ‘document.getElementById("doyoo_monitor").style.display="none";‘
driver.execute_script(js)
滚动条操作
- 设置JavaScript脚本控制滚动条 js="window.scrollTo(0,1000)" 0表示左边距,1000表示上边距
- selenium调用执行JavaScript脚本的方法 driver.excute_script(js)
frame切换
- 什么是frame切换? 就是作用在当前页面中指定区域显示另一页面元素
- 具体的使用步骤
- driver.switch_to.frame(frame_reference) 切换到指定frame的方法 frame_reference:可以为frame框架的name、id或者定位到的frame元素
- driver.switch_to.default_content() 恢复默认页面方法
from selenium import webdriver
driver = webdriver.Firefox()
# 如果登录按钮在iframe上,并且需要操作登录的话,首先定位到iframe,传入id值
driver.switch_to.frame("login")
# 如果没有id值,需要先对iframe进行定位
# iframe=driver.find_element_by_tag_name("iframe")
# driver.switch_to.frame("iframe")
# 进行输入用户名
# 进行输入密码
# 如果需要回到iframe外主页面的话,在释放iframe
driver.switch_to.default_content()
多窗口切换
- 出现过程 在HTML中,当点击链接或者按钮时,有的会在新的窗口打开页面
- 为什么需要切换? 页面存在多个窗口式,selenium默认焦点只会在主窗口上,不切换窗口,无法操作除主窗口以外的窗口内的元素
- 如何实现 在selenium中封装了获取当前窗口句柄,获取所有窗口句柄和切换到指定句柄窗口的方法
- driver.current_windwo_handle 获取当前窗口句柄
- driver.window_handles 获取所有窗口句柄
- driver.switch_to.window(handle) 切换到指定句柄窗口
第一种处理方案
from selenium import webdriver
driver = webdriver.Chrome()
# 获取当前句柄
current_handle = driver.current_window_handle
# 点击跳转之另一个页面
driver.find_elements_by_id("link").click()
# 获取所有句柄
handles = driver.window_handles
for handle in handles:
if handle != current_handle:
driver.switch_to.window(handle)
driver.find_elements_by_xpath("//span[contains(text(),‘输入‘)]")
第二种处理方案
点击链接,会重开一个页面,那么他们都有一个共性,就是拥有target="_blank"属性,只需要去掉该属性即可
js = ‘document.getElementById("rili").removeAttribute("target")‘
# 或者改target的属性为空 js=‘document.getElementById("rili").target=""‘
driver.execute_script(js)
验证码的处理方式
- 去掉验证码 测试环境下采用
- 设置万能验证码 生产环境和测试环境下采用
- 验证码识别技术 通过python-tesseract来识别图片类型验证码:识别率很难达到100%
- 记录cookie 通过记录cookie进行跳过登录
- Cookie是由web服务器生成的,并且保存在用户浏览器上的小文本文件,它可以包含用户相关的信息.
- Cookie数据格式:键值对组成(python中的字典)
- Cookie产生:客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个Cookie数据
- Cookie使用:当浏览器再次请求该网站时,浏览器把请求的数据和Cookie数据一同提交给服务器,服务器检查该Cookie来辨认用户状态
- cookie的使用 selenium中对cookie操作提供相应的方法
- get_cookie(name) 获取指定cookie name为cookie的名称
- get_cookies() 获取本网站所有本地cookies
- add_cookie(cookie_dict) 添加cookie cookie_dict:一个字典对象,必选的键包括:"name"and"value"
- 步骤
- 打开百度url driver.get("https://www.baidu.com")
- 设置cookie信息 dirver.add_cookie({"name":"BDUSS","value":"根据实际情况编写值"})
富文本编辑器的处理
拿博客园举例
第一种常规解决方案
- 打开博客园,点击心随笔
- 输入标题(这边可以直接使用id就可以定位到)
- 富文本的编辑,可以精细的发现编辑框有个iframe,所以需要先切换到iframe
- 正文部分也就是body位置,通过定位body标签的位置,使用send.keys()就可以输入内容了(有可能输入不成功,那么可以在输入之前先按个table键盘,所以还需要用到键盘事件)
第二种js处理方案
from selenium import webdriver
import time
driver = webdriver.Firefox()
# 1 点击新随笔
# 2 输入标题
# 3 利用js对富文本进行输入
body="111"
js = ‘document.getElementById("Editor_Edit_EditorBody_ifr").contentWindow.document.body.innerHTML="%s"‘ % body
driver.execute_script(js)
js处理日历控件
日历控件是web网站上经常会遇到的一个场景,有些输入框是可以直接输入日期的,有些不能,详细讲解如何解决日历控件为readonly属性的问题
如果readonly属性没有readonly值,那么是可以输入的,如果有的话,需要先使用js去掉readonly,然后直接输入日期文本内容
实现步骤:
- 先定位到元素,然后通removeAttribute("readonly")方法删除属性
- 输入日期
js = ‘document.getElementById("rili").removeAttribute("readonly")‘
driver.execute_script(js)
# 第一种输入,清空文本后输入
driver.find_element_by_id("rili").clear()
driver.find_element_by_id("rili").send_keys("2020-08-20")
# 第二种输入,用js修改value
js_value = ‘document.getElementById("rili").value="2020-08-20"‘
driver.execute_script(js_value)
js处理内嵌div
纵向与横向滚动,使用id定位
- div的属性
- 通过id定位,通过控制scrollTop的值来控制滚动条高度(控制scrollLeft控制滚动条的宽度)
- 运行下面代码,观察页面是不是先滚动到底部,过五秒在回到顶部
js = ‘document.getElementById("neiqiandiv").scrollTop=10000‘
driver.execute_script(js)
time.sleep(5)
js_value = ‘document.getElementById("neiqiandiv").scrollTop=0‘
driver.execute_script(js_value)
判断元素是否存在
# 判断元素是否存在,存在返回True,不存在返回False
def base_element_is_exist(self, loc):
try:
self.base_find_element(loc, timeout=2)
return True
except:
return False
解决click失效问题
有些情况下元素明明已经找到,运行也不会报错,但是点击页面后没有任何反应,这种情况我自己遇到过很多次,问题是click事件失效了
- 第一种解决办法 先点击它的父元素一次,然后在点击这个元素
- 第二种解决办法 使用js执行点击事件
解决自动上传
关于非input文件上传,这种弹出的windows的空间,所以这里借助三方工具AutoIT
功能菜单介绍:
- sciTE Script Editor编辑器,在这里编写AutoIt脚本
- AutoIt Windows Info 元素定位器,用于识Windows控件信息
- Run Script 执行AutoIt脚本
- Compile Script to.exe 将AutoIt生成 .exe 可执行文件
操作步骤:
- 以博客园为例,准备好web页面的环境,上传本地图片→弹出选择图片界面
- 使用AutoIt window Info去识别字段
- 打开SciTE Script Editor编辑器编写脚本
- 编辑完成之后执行,tools>go,或者按F5执行,执行完之后就能看到图片上传成功了
- 执行成功后,把脚本保存到本地,save as
- 在应用程序里面找到compile script to.exe,将刚才导出的.au3文件转化为.exe文件
- 执行 os.system("C:\Users\Gloria\Desktop\sendjpg.exe")
autoit脚本的具体含义
- WinActivate("title") 聚焦到指定活动窗口
- ControlFocus ( "title", "窗口文本", controlID) 设置输入焦点到指定窗口的某个控件上;
- WinWait ( "title" , "窗口文本" , 超时时间 ) 暂停脚本的执行直至指定窗口存在(出现)为止;
- ControlSetText ( "title", "窗口文本", controlID, "新文本" ) 修改指定控件的文本;
- Sleep ( 延迟 ) 使脚本暂停指定时间,单位是毫秒;
- ControlClick ( "title", "窗口文本", 控件ID , 按钮 , 点击次数 ) 向指定控件发送鼠标点击命令;
WinWait("[CLASS:#32770]","",5)
ControlFocus("文件上传", "","Edit1")
ControlSetText("文件上传", "", "Edit1",‘C:\其他\file\name.txt‘)
Sleep(5000)
ControlClick("文件上传", "","Button1");
解决文件下载
文件下载时候会弹出一个下载选项框,这个弹框是定位不到的,有些元素指定定位不到,就当没有鼠标,可以通过键盘的快捷键完成操作
解决思路
- 点击按钮时,会弹出下载的保存与取消按钮
- 先按TAB键,移动光标聚集到保存按钮上
- 在按下ENTER键保存
webdriver操作鼠标
from selenium.webdriver.common.action_chains import ActionChains
# 使用键盘操作需要导入
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
import time
driver=webdriver.Chrome()
driver.get("https://www.baidu.com/")
# 指定元素鼠标右键
ActionChains(driver).context_click(driver.find_element_by_id("su")).perform()
# 指定元素鼠标双击
ActionChains(driver).double_click(driver.find_element_by_id("su")).perform()
# 拖动
box1=driver.find_element_by_id("box1")
box2=driver.find_element_by_id("box2")
# 将box1拖动到box2的位置
ActionChains(driver).drag_and_drop(box1,box2).perform()
# 将box1拖动到坐标500,0的位置
ActionChains(driver).drag_and_drop_by_offset(box1,500,0).perform()
# 鼠标悬停(比较经典的就是悬浮框)
ActionChains(driver).move_to_element(driver.find_element_by_id("su")).perform()
# 删除键
driver.find_element_by_id("su").send_keys(Keys.BACK_SPACE)
# 空格键
driver.find_element_by_id("su").send_keys(Keys.SPACE)
# tab键
driver.find_element_by_id("su").send_keys(Keys.TAB)
# 回退键
driver.find_element_by_id("su").send_keys(Keys.ESCAPE)
# 回车键
driver.find_element_by_id("su").send_keys(Keys.ENTER)
# 全选
driver.find_element_by_id("su").send_keys(Keys.CONTROL,"c")
# 复制
driver.find_element_by_id("su").send_keys(Keys.CONTROL,"v")
判断元素的相关问题
如何判断动态的元素,在selenium的expected_conditions模块收集了一系列的场景判断方法
需要先引入 from selenium.webdriver.support import expected_conditions as EC
EC.title_is()
1. title_is: 判断当前页面的title是否完全等于(==)预期字符串,返回布尔值
2. title_contains : 判断当前页面的title是否包含预期字符串,返回布尔值
3. presence_of_element_located : 判断某个元素是否被加到了dom树里,并不代表该元素一定可见
4. visibility_of_element_located : 判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0
5. visibility_of : 跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了
6. presence_of_all_elements_located : 判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是‘column-md-3‘,那么只要有1个元素存在,这个方法就返回True
7. text_to_be_present_in_element : 判断某个元素中的text是否 包含 了预期的字符串
8. text_to_be_present_in_element_value : 判断某个元素中的value属性是否 包含 了预期的字符串
9. frame_to_be_available_and_switch_to_it : 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False
10. invisibility_of_element_located : 判断某个元素中是否不存在于dom树或不可见
11. element_to_be_clickable : 判断某个元素中是否可见并且是enable的,这样的话才叫clickable
12. staleness_of : 等某个元素从dom树中移除,注意,这个方法也是返回True或False
13. element_to_be_selected : 判断某个元素是否被选中了,一般用在下拉列表
14. element_selection_state_to_be : 判断某个元素的选中状态是否符合预期
15. element_located_selection_state_to_be : 跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator
16. alert_is_present : 判断页面上是否存在alert
判断Selenium的常见异常
- NoSuchElementException:没有找到元素
- .NoSuchFrameException:没有找到iframe
- NoSuchWindowException:没找到窗口句柄handle
- NoSuchAttributeException:属性错误
- NoAlertPresentException:没找到alert弹出框
- lementNotVisibleException:元素不可见
- ElementNotSelectableException:元素没有被选中
- TimeoutException:查找元素超时
读取txt文件
def read_txt(fileName):
filepath = "C:/Users/17327/PycharmProjects/yunhe/data/" + fileName
arr = []
with open(filepath, "r", encoding="utf-8") as file:
datas = file.readlines()
for data in datas:
arr.append(tuple(data.strip().split(",")))
return arr
读取json文件
import json
def read_json(fileName):
filepath = "C:/Users/17327/PycharmProjects/yunhe/data/" + fileName
arr = []
with open(filepath, "r", encoding="utf-8") as file:
datas = json.load(file)
for data in datas.values():
arr.append(
(data["title"], data["content"], data["success"])
)
return arr
Selenium
原文:https://www.cnblogs.com/wp950416/p/13996831.html