Selenium

Selenium

自动化工具介绍

  1. UFT 非开源
  2. RobotFramework
    1. 高度扩展
    2. 拥有大量的库
    3. 支持关键字驱动
  3. Selenium
    1. 业内普及
    2. 灵活
    3. 使用场景广泛

为什么要进行自动化测试?

  1. 目的
    1. 解决回归测试、压力测试、兼容性测试
    2. 提高测试效率保证产品质量
  2. 相关解释
    1. 回归测试:项目在发布新版本之前进行的功能验证
    2. 压力测试:可以理解多用户去操作软件,统计服务器处理用户请求的能力
    3. 兼容性测试:表示在不同浏览器下软件运行状态
  3. 如下三种情况一般需要使用自动化?
    1. 需求变动不频繁
    2. 项目周期长
    3. 项目需要回归测试

配置编程环境

  1. window下安装python3.7(傻瓜式安装)
  2. Linux下安装python3.7
  3. 安装selenium包 pip3 install selenium
  4. 下载谷歌、火狐、IE驱动
  5. 安装pycharm

selenium的使用

selenium安装、卸载以及查看命令

  1. 安装 pip install selenium
  2. 卸载 pip uninstall selenium
  3. 查看 pip show selenium

元素的定位

  1. id定位 find_element_by_id("kw") 注:有些id值动态变化
  2. class_name定位 find_element_by_class_name("s_ipt") 注:classname有可能重复
  3. tag_name定位 find_element_by_tag_name("input") 注:tagname最容易重复
  4. name定位 find_element_by_name("wd") 注:name有可能重复
  5. link文字精确定位 find_element_by_link_text("登录")
  6. link文字模糊定位 find_element_by_partial_link_text("登")
  7. CSS定位(常用定位策略) 在selenium中推荐使用css定位,因为它比xpath定位速度快
    1. id选择器 #id值
    2. class选择器 .class值
    3. 元素选择器 标签名 >表示直接子级 空格表示子级
      1. p[id="user"]>input 表示p元素(id为user)的直接子级 或者使用p#user>input
      2. p[id="user"] input 表示p元素(id为user)的子级 或者使用p#user input
    4. css延伸
      1. input[type^="p"] type属性以p字母开头的元素
      2. input[type$="d"] type属性以d结尾的元素
      3. input[type*="w"] type属性包含w字母的元素
  8. XPath定位的常规策略
    1. 路径
      1. 绝对路径 绝对路径对页面结构要求非常高,不建议使用
      2. 相对路径 匹配任意层级的元素,不限制元素的位置
        1. 相对路径以//开始
        2. 格式 //input或者//*
    2. 路径结合属性 //input[@placeholder="密码A"]
    3. 路径结合逻辑(多个属性)
      1. //input[@placeholder="密码A" and @name="password"]
      2. //p[@id="parent"]/input[@placeholder="密码A" and @name="password"
    4. 路径结合层级
    5. xpath的延伸
      1. //*[text()="xxx"] 文本内容是xxx的元素
      2. //*[contains(@attribute,"xxx")] 属性中含有xxx的元素
      3. //*[starts-weith(@attribute,"xxx")] 属性以xxx开头的元素
  9. 定位一组元素
    1. 通过下标操作定位元素 driver.find_elements_by_tag_name("input")[0].send_keys("吴鹏") 向一组input元素的第一个input输入内容
    2. 通过遍历操作定位元素 for el in elements:→el.send_keys("吴鹏")

SeleniumBuilder辅助定位元素

在火狐浏览器的附加组件中搜索添加SeleniumBuilder即可完全安装(老版本的还存在,新版本的已经被弃用)

元素操作方法

  1. 为什么要学习操作元素的方法?
    1. 需要让脚本模拟用户给指定元素输入值
    2. 需要让脚本模拟人为删除元素的内容
    3. 需要让脚本模拟点击操作
  2. 相关元素的操作方法
    1. send_keys() 扩展可以实现上传的操作(send_keys("文件路径"))
    2. click()
    3. clear() 清空
    4. maximize_window() 窗口最大化
    5. set_window_size(width,height) 设置浏览器窗口大小
    6. set_window_position(x,y) 设置浏览器窗口位置
    7. back() 后退,模拟浏览器后天按钮
    8. forward() 前进,模拟浏览器前进按钮
    9. refresh() 刷新,模拟浏览器F5刷新
    10. close() 关闭当前窗口,模拟电机架浏览器关闭按钮
    11. quit() 关闭浏览器驱动对象,关闭所有程序启动的窗口
    12. title 获取页面title
    13. current_url 获取当前页面URL
    14. get_screenshot_as_file("D://test/b1.img") 截屏

获取元素信息(及属性)的常用方法

  1. size 返回元素大小
  2. text 返回元素的文本(文本内容)
  3. get_attribute("xxx") 获取属性值,传递的参数为元素的属性名
  4. is_displayed() 判断元素是否可见
  5. is_enabled() 判断元素是否可用
  6. is_selected() 判断元素是否选中,用来检查复选框或单选按钮是否被选中
  7. title() 获取百度的title可以使用该方法
  8. tag_name 获取元素的标签名
  9. get_attribute("属性") 这里的参数类似于class、name等,也就是标签内部的属性,能够获取标签内部属性的属性值
  10. get_attribute("value") 获取输入框的默认文本值,在输入框输入的值也能获取
  11. dirver.name 获取浏览器名字

鼠标操作

  1. 对于鼠标操作需要导入ActionChains包 from selenium.webdriver.common.action_chains import ActionChains
  2. 鼠标事件常用的操作方法 初始化 action=ActionChains(driver)
    1. context_click() 右击 action.context_click(driver.find_element_by_css_selector("#user")).perform()
      1. selenium框架中虽然提供了右击鼠标方法,但是没有提供选择右击菜单方法,可以通过发送快捷键的方式解决(经过测试,谷歌浏览器不支持)
    2. double_click() 双击 action.double_click(driver.find_element_by_css_selector("#user").send_keys("admin")).perform()
    3. drag_and_drop() 拖拽 action.drag_and_drop(第一个元素,第二个元素).perform()
      1. action.drag_and_drop_by_offset(source,xoffset=360,yoffset=180).perform()
    4. move_to_element() 悬停 action.move_to_element(driver.find_element_by_css_selector("button")).perform()
    5. perform() 执行以上事件方法

键盘操作

selenium中把键盘的案件都封装在keys类中,导包 from selenium.webdriver.common.keys import keys

  1. 删除 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.BACK_SPACE) 单键就一个参数
  2. 全选 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"a") 组合键两个参数
  3. 复制 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"c")
  4. 粘贴 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"v")
  5. 剪切 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.CONTROL,"v")
  6. F1-F12 driver.find_element_by_css_selector("#userA").send_keys("admin1").send_keys(Keys.F1)

元素等待

元素等待类型

  1. 隐式等待
    1. 什么是隐式等待? 定位元素时,如果能定位到元素则直接返回该元素,不触发等待,如果不能定位到该元素,则间隔一段时间再去定位如果超出,则抛出such**异常
      2.方法 driver.implicitly_wait(timeout)
  2. 显式等待
    1. 什么是显式等待? 定位指定元素时,如果能定位到元素则直接返回该元素,不触发等待,如果不能定位到元素,则隔一段时间再去定位,如果超出,跑出time**异常
    2. 实现方式
      1. 导包 from selenium.webdriver.support.wait import WebDriverWait
      2. 调用方法 until(method):直到...时 一般使用匿名函数来实现
      3. element=WebDriverWait(driver,10,1).until(lambda x:x.find_element_by_id("useA"))

操作API

select下拉框

  1. 使用css去定位下拉框 如果option选项没有value值得话,css定位或者其他定位就不太方便
  2. 使用Select from selenium.webdriver.support.select import Select
    1. 通过下标 Select(driver.find_element_by_css_selector("#userA")).select_by_index(1)
    2. 通过value值 select_by_value(" ")
    3. 通过显示文本 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处理办法

  1. 网页中常用的弹出框
    1. alert 警告框
    2. confirm 确认框
    3. prompt 提示框
  2. 弹出框的处理方法
    1. 获取弹出框对象 alert=driver.switch_to.alert
    2. 调用
      1. alert.text 返回弹出的文字信息
      2. alert.accept() 接受对话框选项(同意)
      3. 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)

滚动条操作

  1. 设置JavaScript脚本控制滚动条 js="window.scrollTo(0,1000)" 0表示左边距,1000表示上边距
  2. selenium调用执行JavaScript脚本的方法 driver.excute_script(js)

frame切换

  1. 什么是frame切换? 就是作用在当前页面中指定区域显示另一页面元素
  2. 具体的使用步骤
    1. driver.switch_to.frame(frame_reference) 切换到指定frame的方法 frame_reference:可以为frame框架的name、id或者定位到的frame元素
    2. 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()

多窗口切换

  1. 出现过程 在HTML中,当点击链接或者按钮时,有的会在新的窗口打开页面
  2. 为什么需要切换? 页面存在多个窗口式,selenium默认焦点只会在主窗口上,不切换窗口,无法操作除主窗口以外的窗口内的元素
  3. 如何实现 在selenium中封装了获取当前窗口句柄,获取所有窗口句柄和切换到指定句柄窗口的方法
    1. driver.current_windwo_handle 获取当前窗口句柄
    2. driver.window_handles 获取所有窗口句柄
    3. 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)

验证码的处理方式

  1. 去掉验证码 测试环境下采用
  2. 设置万能验证码 生产环境和测试环境下采用
  3. 验证码识别技术 通过python-tesseract来识别图片类型验证码:识别率很难达到100%
  4. 记录cookie 通过记录cookie进行跳过登录
    1. Cookie是由web服务器生成的,并且保存在用户浏览器上的小文本文件,它可以包含用户相关的信息.
    2. Cookie数据格式:键值对组成(python中的字典)
    3. Cookie产生:客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个Cookie数据
    4. Cookie使用:当浏览器再次请求该网站时,浏览器把请求的数据和Cookie数据一同提交给服务器,服务器检查该Cookie来辨认用户状态
  5. cookie的使用 selenium中对cookie操作提供相应的方法
    1. get_cookie(name) 获取指定cookie name为cookie的名称
    2. get_cookies() 获取本网站所有本地cookies
    3. add_cookie(cookie_dict) 添加cookie cookie_dict:一个字典对象,必选的键包括:"name"and"value"
    4. 步骤
      1. 打开百度url driver.get("https://www.baidu.com")
      2. 设置cookie信息 dirver.add_cookie({"name":"BDUSS","value":"根据实际情况编写值"})

富文本编辑器的处理

拿博客园举例
第一种常规解决方案

  1. 打开博客园,点击心随笔
  2. 输入标题(这边可以直接使用id就可以定位到)
  3. 富文本的编辑,可以精细的发现编辑框有个iframe,所以需要先切换到iframe
  4. 正文部分也就是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,然后直接输入日期文本内容
实现步骤:

  1. 先定位到元素,然后通removeAttribute("readonly")方法删除属性
  2. 输入日期
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定位

  1. div的属性
  2. 通过id定位,通过控制scrollTop的值来控制滚动条高度(控制scrollLeft控制滚动条的宽度)
  3. 运行下面代码,观察页面是不是先滚动到底部,过五秒在回到顶部
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事件失效了

  1. 第一种解决办法 先点击它的父元素一次,然后在点击这个元素
  2. 第二种解决办法 使用js执行点击事件

解决自动上传

关于非input文件上传,这种弹出的windows的空间,所以这里借助三方工具AutoIT
功能菜单介绍:

  1. sciTE Script Editor编辑器,在这里编写AutoIt脚本
  2. AutoIt Windows Info 元素定位器,用于识Windows控件信息
  3. Run Script 执行AutoIt脚本
  4. Compile Script to.exe 将AutoIt生成 .exe 可执行文件
    操作步骤:
  5. 以博客园为例,准备好web页面的环境,上传本地图片→弹出选择图片界面
  6. 使用AutoIt window Info去识别字段
  7. 打开SciTE Script Editor编辑器编写脚本
  8. 编辑完成之后执行,tools>go,或者按F5执行,执行完之后就能看到图片上传成功了
  9. 执行成功后,把脚本保存到本地,save as
  10. 在应用程序里面找到compile script to.exe,将刚才导出的.au3文件转化为.exe文件
  11. 执行 os.system("C:\Users\Gloria\Desktop\sendjpg.exe")
    autoit脚本的具体含义
  12. WinActivate("title") 聚焦到指定活动窗口
  13. ControlFocus ( "title", "窗口文本", controlID) 设置输入焦点到指定窗口的某个控件上;
  14. WinWait ( "title" , "窗口文本" , 超时时间 ) 暂停脚本的执行直至指定窗口存在(出现)为止;
  15. ControlSetText ( "title", "窗口文本", controlID, "新文本" ) 修改指定控件的文本;
  16. Sleep ( 延迟 ) 使脚本暂停指定时间,单位是毫秒;
  17. ControlClick ( "title", "窗口文本", 控件ID , 按钮 , 点击次数 ) 向指定控件发送鼠标点击命令;
WinWait("[CLASS:#32770]","",5)
ControlFocus("文件上传", "","Edit1")
ControlSetText("文件上传", "", "Edit1",'C:\其他\file\name.txt')
Sleep(5000)
ControlClick("文件上传", "","Button1");

解决文件下载

文件下载时候会弹出一个下载选项框,这个弹框是定位不到的,有些元素指定定位不到,就当没有鼠标,可以通过键盘的快捷键完成操作
解决思路

  1. 点击按钮时,会弹出下载的保存与取消按钮
  2. 先按TAB键,移动光标聚集到保存按钮上
  3. 在按下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的常见异常

  1. NoSuchElementException:没有找到元素
  2. .NoSuchFrameException:没有找到iframe
  3. NoSuchWindowException:没找到窗口句柄handle
  4. NoSuchAttributeException:属性错误
  5. NoAlertPresentException:没找到alert弹出框
  6. lementNotVisibleException:元素不可见
  7. ElementNotSelectableException:元素没有被选中
  8. TimeoutException:查找元素超时
posted @ 2020-11-17 22:00  SunFree  阅读(279)  评论(0编辑  收藏  举报