WEB UI自动化测试之Selenium框架学习
文章目录
- 前言
- 自动化测试介绍
- Selenium简介
- Selenium安装
- 浏览器驱动安装与下载
- 浏览器驱动初始化
- 浏览器驱动管理
- 自动管理驱动
- 传统方法(指定驱动绝对/相对路径) 可选
- 配置浏览器选项
- Selenium 进行WEB自动化测试
- 基本代码
- 元素定位
- 元素标签获取
- 元素定位方法
- id定位方法
- name定位方法
- class_name 方法
- tag_name 方法
- link_text
- partial_link_text
- xpath定位方法
- CSS定位
- 定位一组元素的方法
- 元素定位方法的另一种写法
- 元素定位实践经验
- 元素等待与异常处理
- 隐式等待
- 显式等待
- 强制等待
- 异常处理 (根据实际情况,仅作介绍)
- 模拟鼠标操作
- 单击左键
- 单击右键
- 拖动
- 鼠标悬停
- 模拟键盘操作
- 其他控制操作
- 元素操作
- 浏览器操作
- 下拉框操作
- 弹出框操作
- 滚动条
- frame/iframe表单
- 连续切换frame/iframe
- 多窗口切换
- 截图操作
- 验证码处理
- 上传与下载文件
- 上传文件
- 下载文件
- 参考目录
前言
阅读本文前请注意最后编辑时间,文章内容可能与目前最新的技术发展情况相去甚远。欢迎各位评论与私信,指出错误或是进行交流等。
自动化测试介绍
Selenium简介
Selenium是广泛使用的模拟浏览器运行的库,它是一个用于Web应用程序测试的工具。 Selenium测试直接运行在浏览器中,就像真正的用户在操作一样,并且支持大多数现代 Web 浏览器。Selenium 支持多种语言。目前,Selenium Web 驱动程序最受 Python 和 C#欢迎,本文以Python 为例。
官方地址:https://www.selenium.dev/
Selenium安装
# 使用pip安装最新版本
pip install selenium# 安装特定版本
pip install selenium==4.10.0# 在虚拟环境中安装(推荐)
python -m venv selenium_env
source selenium_env/bin/activate # Linux/Mac
selenium_env\Scripts\activate.bat # Windows
pip install selenium# 卸载:
pip uninstall selenium
浏览器驱动安装与下载
针对不同的浏览器,需要安装不同的驱动。安装驱动后,Selenium才能进行自动化操作。
注:从Selenium 4.0开始,提供了自动管理驱动的功能 但手动安装方法仍需了解:
以谷歌浏览器驱动为例:
1)、确定浏览器版本
在新标签页输入 chrome://settings/ 进入设置界面,然后选择 【关于 Chrome】。
或者点击chrome浏览器最右侧的“三个点”图标,然后点击弹出的“帮助”中的“关于Google Chrome”,查看自己的版本信息。
确定浏览器版本后,下载对应版本的 Chrome 驱动即可。
获取谷歌浏览器的驱动地址:http://chromedriver.storage.googleapis.com/index.html
2)、获取浏览器的版本一定要选本地电脑谷歌浏览器版本号一样。注意:可能有些版本驱动没有一模一样的,可以选择用 . 号隔开的前三位必须相同,第四位可以选最接近你浏览器版本的那个数. 后面一步的是有,这里只有win32位,但是不影响,64位也能用这个驱动,但是显示的是64位,那么32位就不能用了,这里选择对应操作系统就可以了。
3)、下载完成后,压缩包内只有一个 exe 文件。
将 chromedriver.exe 保存到任意位置,并把当前路径保存到环境变量。
(建议将其保存到anaconda的安装目录下 或者 放到Python解释器根目录下,这样不需要再添加环境变量了)
添加成功后使用下面代码进行测试。
from selenium import webdriver
# Chrome浏览器
driver = webdriver.Chrome()
如果能弹出Chrome浏览器,则说明安装成功。
浏览器驱动初始化
浏览器驱动管理
通过驱动管理, 我们来用打开对应的浏览器。以谷歌浏览器驱动为例
自动管理驱动
from selenium import webdriver# 自动管理驱动
driver = webdriver.Chrome()
传统方法(指定驱动绝对/相对路径) 可选
from selenium import webdriver# 指定驱动路径
service = r'C:\Users\Gdc\.wdm\drivers\chromedriver\win32\96.0.4664.45\chromedriver.exe'
driver = webdriver.Chrome(service)
配置浏览器选项
from selenium import webdriver
from selenium.webdriver.chrome.options import Options# 创建Chrome选项对象
# 对所需进行的设置下进行add_argument 添加参数并设置值即可
chrome_options = Options()
chrome_options.add_argument("--headless") # 无头模式
chrome_options.add_argument("--window-size=1920,1080") # 设置窗口大小
chrome_options.add_argument("--disable-gpu") # 禁用GPU加速
chrome_options.add_argument("--disable-extensions") # 禁用扩展
chrome_options.add_argument("--proxy-server='direct://'") # 代理设置
chrome_options.add_argument("--proxy-bypass-list=*") # 绕过代理
chrome_options.add_argument("--start-maximized") # 启动时最大化窗口
chrome_options.add_experimental_option("prefs", {"download.default_directory": "/path/to/download/directory", # 设置下载目录"download.prompt_for_download": False, # 禁用下载提示"download.directory_upgrade": True,"safebrowsing.enabled": True
})# 初始化WebDriver
driver = webdriver.Chrome(options=chrome_options)
Selenium 进行WEB自动化测试
基本代码
步骤:
1、导包
2、实例化浏览器对象
3、打开网页
4、测试代码
5、关闭网页
"""
web 自动化基本代码
"""
# 1、导包
from selenium import webdriver# 2、实例化浏览器对象:类名()
driver = webdriver.Chrome()# 3、打开网页
driver.get('https://www.baidu.com/')# 4、测试代码# 5、关闭网页
driver.quit() # 退出浏览器驱动
元素定位
为什么要使用元素定位?
计算机无法向人一样,所见即所得,因此需要先让计算机定位到要进行操作的元素,才能进行后续操作。
使用 selenium 定位页面元素的前提是你已经了解基本的页面布局及各种标签含义(HTML、CSS)
元素标签获取
方法1)、谷歌使用 F12 进入开发者工具
以我们熟知的 百度为例,我们进入首页,按 【F12】 进入开发者工具。红框中显示的就是页面的代码,我们要做的就是从代码中定位获取我们需要的元素。
我们可以通过开发者工具所提供的功能, 如下图所示。点击该按钮,随后再点击想要定位的元素。
如下图所示。点击了该按钮后,鼠标悬停在该元素上方,最后我们点击鼠标左键。
所定位的元素的标签,会在代码区被高亮显示。
方法 2)、鼠标悬停元素上-点击右键-检查进入开发者工具
获取到所对应元素的标签
元素定位方法
定位元素方法通过什么找到元素?
通过标签名、属性、层级、路径
Selenium框架提供了八种元素定位方法,每种都有其适用场景:
定位方式:
1、id
2、name
3、class_name(使用的是class属性进行定位)
4、tag_name (标签名称)
5、link_text(定位超链接 a 标签)
6、partial_link_text(定位超链接 a 标签)
7、xpath (路径)
8、css (元素选择器)
id定位方法
说明:通过元素的id属性定位,id一般情况下在当前页面中是唯一。
提示:元素必须要有id属性。
# 方法:
find_element_by_id(元素value)# 演示
from selenium import webdriver
# 实例化浏览器对象
driver = webdriver.Chrome()
# 打开网址url
driver.get('https://www.baidu.com/')
# 通过元素 id 定位到它
driver.find_element_by_id('kw')
由于各种方法函数用法几乎相同,后续不再写演示
name定位方法
说明:通过元素的name属性来定位
提示:1、 元素必须要有name属性。
2、不同元素的 name 属性值可能相同, 最好确保其能够唯一指向目标元素之后使用
3、当页面内有多个元素的name 属性值相同的时候,执行该方法会默认获取第⼀个符合要求的元素。
driver.find_element_by_name('name的值')
class_name 方法
说明:通过元素的class属性来定位,一个元素的class属性可以有多个值。
提示:元素必须要有class属性。
注意:
1、方法名是class_name ,但实际是根据元素标签中的class属性
2、如果元素的 class 属性值存在多个值, 使用class_name 方法定位时, 只能使用其中的任意一个
3、不同元素的 class 属性值可能相同, 最好确保其能够唯一指向目标元素之后使用
4、当页面内有多个元素的 class 属性值相同的时候,执行该方法会默认获取第⼀个符合要求的元素。
driver.find_element_by_class_name
tag_name 方法
说明:通过元素的标签名称来定位,标签名(查看元素时尖括号(<)紧挨着的单词或字母就是标签名)
注意:1、由于一个页面中存在大量标签,并且重复性高,最好确保其能够唯一指向目标元素之后使用
2、如果页面中存在多个相同标签,默认返回第一个标签元素。
driver.find_element_by_tag_name("标签名")
link_text
说明:定位超链接标签
注意:1、只能使用精准匹配(a标签的全部文本内容)
2、该方法只针对超链接元素(a 标签),并且需要输入超链接的全部文本信息
driver.find_element_by_link_text('文本内容')
partial_link_text
说明:同样用于i定位超链接标签,但不强制要求a标签的全部文本内容,可以只传入a标签的局部文本,当然也可以传入全部文本。
注意:
- 可以使用精准或模糊匹配,如果使用模糊匹配最好使用能代表唯一的关键词
- 如果有多个值,默认返回第一个值
driver.find_element_by_partial_link_text('部分文本或全部文本')
xpath定位方法
# Xpath 定位方法:
driver.find_element_by_xpath('Xpath的策略')
说明:Xpath定位方法只有一种,但是策略有多种,不同策略参数的写法不同。
<html><head>...<head/><body><div id="csdn-toolbar"><div class="toolbar-inside"><div class="toolbar-container"><div class="toolbar-container-left">...</div><div class="toolbar-container-middle"><div class="toolbar-search onlySearch"><div class="toolbar-search-container"><input id="toolbar-search-input" autocomplete="off" type="text" value="" placeholder="C++难在哪里?">
以上方的XML文档为例,介绍Xpath常用的定位策略:
**绝对路径:**从最外层元素到指定元素之间所有经过元素层级的路径 ,绝对路径是以/html根节点开始,使用 / 来分割元素层级
根据上面的标签,定位最后一行 input 标签。
语法:driver.find_element_by_xpath(“/html/body/div/div/div/div[2]/div[2]/input”) (例子中div标签下有多个div标签,用div[2]索引的方式定位)
注意:绝对路径对页⾯结构要求比较严格
**相对路径:**匹配任意层级的元素,不限制元素的位置 ,相对路径是以 // 开始, // 跟元素名称,元素标签可以使用*代替(通配符)。
语法://input 或者 //*
driver.find_element_by_xpath(“//div[@id=‘csdn-toolbar’]/div/div/div[2]/div[2]/input”)
(没有从根节点开始,而是从id为’csdn-toolbar’的div标签开始向下找,采用了相对路径)
元素xpath路径获取
元素属性:
1、单独利用属性定位: 该方法可以使用目标元素的任意一个属性和属性值(需要保证唯⼀性)
# 语法1://标签名[@属性名='属性值']
# 语法2://*[@属性名='属性值']# 利用最后一个input标签的id属性来定位该元素
driver.find_element_by_xpath("//input[@id='toolbar-search-input']"))
driver.find_element_by_xpath("//*[@id='toolbar-search-input']"))
2、**层级与属性结合:**假如目标元素无法直接定位, 可以考虑先定位其父层级或祖辈层级, 再获取目标元素
# 语法举例://*[@id='父级id属性值']/input (⽗层级定位策略/目标元素定位策略)
driver.find_element_by_xpath("//div[@id='toolbar-search-container']/input")
# 此处使用了最后一个input标签的父级属性查找策略,利用其id值进行定位,随后采用层级策略定位到input标签
3、**多个属性定位:**解决的是单个属性和属性值无法定位元素唯一性的问题。
# 语法: //*[@属性1="属性值1" and @属性2="属性值2"]
注:多个属性定位也可以和层级策略再进行结合使用
# xpath 扩展(还有其他很多策略, 根据需要进行使用)
1. //*[text()='文本信息'] # 定位文本值等于XXX的元素
另外一种写法 //a[contains(text(), '文本信息')] 提示:一般适合 p标签,a标签
2. //*[contains(@属性,'属性值的部分内容')] # 定位属性包含xxx的元素提示:contains为关键字,不可更改。
3. //*[starts-with(@属性,'属性值的开头部分')] # 定位属性以xxx开头的元素提示:starts-with为关键字不可更改
4. //button[@type='submit' or @type='button']提示:属性定位可以使用 or 关键字 (也称为逻辑定位)
5. 轴定位是根据父节点,兄弟节点等节点来定位本节点,使用语法: 轴名称 :: 节点名称具体方法此处不再给出,可参考其他资料或官方文档
CSS定位
通过 css 的选择器语法定位元素
1、Selenium框架官方推荐使用 css ,因为定位效率高于xpath
2、 CSS是一种标记语言,焦点:数据的样式。控制元素的显示样式,就必须先找到元素,在css标记语言中找元素使用css选择器;
3、css的选择策略也有很多,但是无论选择哪一种选择策略都是用的同一种定位方法
# 方法:
driver.find_element_by_css_selector('css策略')
方法 | css策略举例 | 描述 |
---|---|---|
id 选择器 | #toolbar-search-input | 选择 id = ‘toolbar-search-input’ 的元素 |
class 选择器 | .toolbar-search-container | 选择 class = ‘toolbar-search-container’ 的元素,如果元素具有多个class属性值,需要全部输入 |
* | * | 选择所有元素 |
标签选择器 | input | 选择所有 <input> 元素 |
属性选择器 | type=‘text’ | 选择 type = ‘text’ 的所有元素,input[name^=‘user’] # 属性值以user开头;input[name$=‘name’] # 属性值以name结尾;input[name*=‘erna’] # 属性值包含erna |
组合选择器 | form input[type=‘text’] | form标签后 属性type为text的input标签(采用了标签选择器、属性选择器两种策略结合) |
element>element | div>input | 选择父元素为 <div> 的所有 <input> 元素 |
element+element | div+input | 选择同一级中在 <div> 之后的所有 <input> 元素 |
css的路径获取
定位一组元素的方法
前文我们定位元素方法的是 driver.find_element_by_xxx
Selenium 同样提供了 driver.find_elements_by_xxx这种element后面带s的方法。执行结果返回的是列表类型,里面的数据是多个元素对象,用于定位多个满足查找条件的元素。
Selenium 中提供的定位一组元素的方法有以下:
find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_xpath()
find_elements_by_css_selector()
find_elements_by_link_text()
find_elements_by_partial_link_text()
元素定位方法的另一种写法
上文介绍了八类元素定位的方法,但Selenium提供了另外一种写法。统一使用一种方法,元素定位方法作为参数输入。
语法:driver.find_element(方法, 方法所需参数)
方法 | 例子 |
---|---|
ID | find_element(by=By.ID, “具体参数”) |
NAME | driver.find_element(By.NAME, “具体参数”) |
CLASS_NAME | find_element(By.CLASS_NAME, “具体参数”) |
TAG_NAME | find_element(By.TAG_NAME, “具体参数”) |
LINK_TEXT | find_element(By.LINK_TEXT, “具体参数”) |
Partial Link Text定位(部分匹配) | find_element(By.PARTIAL_LINK_TEXT, “具体参数”) |
CSS选择器 | find_element(By.CSS_SELECTOR, “css选择器策略”) |
XPath | find_element(By.XPATH, “xpath策略”) |
元素定位实践经验
1、性能优化顺序:ID > Name > CSS > XPath
2、避免使用:绝对XPath路径(容易失效)
3、推荐使用:
- 有意义的ID和名称属性
- 短而明确的CSS选择器
元素等待与异常处理
1、为什么要设置元素等待?
很多页面都使用 ajax 技术,页面的元素不是同时被加载出来的,定位这些尚在加载的元素,会导致报错。
页面加载和元素渲染需要时间。
由于电脑配置或网络原因,在查找元素时,元素代码未在第一时间内被加载出来,而抛出未找到元素异常。
所以,这种情况下需要设置延时,进行元素等待。
2、什么是元素等待?
元素在第一次未找到时,元素等待设置的时长被激活,如果在设置的有效时长内找到元素,继续执行代码,如果超出设置的时长未找打元素,抛出未找到元素异常。
webdriver 中的等待分为 显式等待 和 隐式等待。
隐式等待
隐式等待是指定一个超时时间,如果超出这个时间指定元素还没有被加载出来,就会抛出 NoSuchElementException 异常。
隐式等待是全局性的,即运行过程中,如果元素可以定位到,它不会影响代码运行,但如果定位不到,则它会以轮询的方式不断地访问元素直到元素被找到,若超过指定时间,则抛出异常。
使用 implicitly_wait() 来实现隐式等待,使用难度相对于显式等待要简单很多。
示例:打开个人主页,设置一个隐式等待时间 5s,通过 id 定位一个不存在的元素,最后打印 抛出的异常 与 运行时间。
from selenium import webdriver
from time import timedriver = webdriver.Chrome()
driver.get('https://blog.csdn.net/qq_43965708')start = time()
driver.implicitly_wait(5)
try:driver.find_element_by_id('kw')
except Exception as e:print(e)print(f'耗时:{time()-start}')
代码运行到 driver.find_element_by_id(‘kw’) 这句之后触发隐式等待,在轮询检查 5s 后(超过最大等待时间)仍然没有定位到元素,抛出异常。
显式等待
显式等待:设置一个超时时间,每隔一段时间就去检测一次该元素是否存在(相比于隐式等待,显示等待是针对于某一个元素的),如果存在则执行后续内容,如果超过最大时间(超时时间)则抛出超时异常(TimeoutException)。显示等待需要使用 WebDriverWait,同时配合 until 或 not until 。
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
- driver:浏览器驱动
- timeout:超时时间,单位秒
- poll_frequency:每次检测的间隔时间,默认为0.5秒
- ignored_exceptions:指定忽略的异常,如果在调用 until 或 until_not 的过程中抛出指定忽略的异常,则不中断代码,默认忽略的只有 NoSuchElementException 。
until(method, message=’ ‘)
until_not(method, message=’ ')
显示等待WebDriverWait,需要搭配until、until_not使用
- method:指定预期条件的判断方法,在等待期间,每隔一段时间调用该方法,判断元素是否存在,直到元素出现。until_not 正好相反,当元素消失或指定条件不成立,则继续执行后续代码
- message: 如果超时,抛出 TimeoutException ,并显示 message 中的内容
下面写一个简单的例子,帮助我们理解。这里定位一个页面不存在的元素,抛出的异常信息正是我们指定的内容。
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import Bydriver = webdriver.Chrome()
element = WebDriverWait(driver, 5, 0.5).until(EC.presence_of_element_located((By.ID, 'kw')),message='超时啦!')
由上可看到,声明了一个浏览器驱动driver。并且为此设置了显示等待,最大等待时间5秒,每间隔0.5秒去检查一次。直到(until)元素出现(presence_of_element),该元素通过ID进行定位,其ID的值为kw(By.ID, ‘kw’)。最后超出了最大等待时间5秒,报了超时异常(TimeoutException),且显示的文本信息是自行设置的message的值。
关于until中的methon,即等待期间的预期条件的判断方法是由 expected_conditions 提供,下面列举常用方法。
并介绍这些方法中要用到的定位器和元素
from selenium.webdriver.common.by import By
from selenium import webdriverdriver = webdriver.Chrome()
locator = (By.ID, 'kw') # 定位器
element = driver.find_element_by_id('kw') # 元素
方法 | 描述 |
---|---|
title_is(‘百度一下’) | 判断当前页面的 title 是否等于预期 |
title_contains(‘百度’) | 判断当前页面的 title 是否包含预期字符串 |
presence_of_element_located(locator) | 判断元素是否被加到了 dom 树里,并不代表该元素一定可见 |
visibility_of_element_located(locator) | 判断元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0 |
visibility_of(element) | 跟上一个方法作用相同,但传入参数为 element |
text_to_be_present_in_element(locator , ‘百度’) | 判断元素中的 text 是否包含了预期的字符串 |
text_to_be_present_in_element_value(locator , ‘某值’) | 判断元素中的 value 属性是否包含了预期的字符串 |
frame_to_be_available_and_switch_to_it(locator) | 判断该 frame 是否可以 switch 进去,True 则 switch 进去,反之 False |
invisibility_of_element_located(locator) | 判断元素中是否不存在于 dom 树或不可见 |
element_to_be_clickable(locator) | 判断元素中是否可见并且是可点击的 |
staleness_of(element) | 等待元素从 dom 树中移除 |
element_to_be_selected(element) | 判断元素是否被选中,一般用在下拉列表 |
element_selection_state_to_be(element, True) | 判断元素的选中状态是否符合预期,参数 element,第二个参数为 True/False |
element_located_selection_state_to_be(locator, True) | 跟上一个方法作用相同,但传入参数为 locator |
alert_is_present() | 判断页面上是否存在 alert |
强制等待
使用 time.sleep() 强制等待,设置固定的休眠时间,对于代码的运行效率会有影响。
实践经验建议:
- 添加页面加载和元素等待机制
- 查找元素的超时和重试机制
- 详细的错误处理机制
- 避免使用time.sleep():不灵活且低效
- 结合使用隐式等待和显式等待:隐式等待作为全局保护,显式等待针对特定场景
- 设置合理的超时时间:不要过长或过短
- 捕获并处理超时异常:提供适当的恢复机制或用户友好的错误信息
- 为不同网络环境调整等待策略:可配置的超时参数
异常处理 (根据实际情况,仅作介绍)
Selenium操作可能会触发各种异常,合理的异常处理可以提高脚本的健壮性。
常见异常类型
from selenium.common.exceptions import (NoSuchElementException, # 元素未找到TimeoutException, # 等待超时ElementNotVisibleException, # 元素不可见ElementNotInteractableException, # 元素不可交互StaleElementReferenceException, # 元素已过时(DOM已更新)WebDriverException, # WebDriver通用异常InvalidSelectorException, # 无效的选择器UnexpectedAlertPresentException, # 意外的警告框NoAlertPresentException, # 没有警告框SessionNotCreatedException, # 会话创建失败ElementClickInterceptedException # 元素点击被拦截
)
基本异常处理
try:element = driver.find_element(By.ID, "non_existent_element")element.click()
except NoSuchElementException:print("元素未找到")
except ElementNotInteractableException:print("元素不可交互")
except Exception as e:print(f"发生其他异常: {e}")
重试机制
def retry_click(driver, by, value, max_attempts=3, wait_time=1):"""尝试多次点击元素"""from time import sleepfor attempt in range(max_attempts):try:element = driver.find_element(by, value)element.click()return Trueexcept (NoSuchElementException, ElementNotInteractableException, ElementClickInterceptedException, StaleElementReferenceException) as e:if attempt == max_attempts - 1:print(f"无法点击元素,错误: {e}")return Falsesleep(wait_time)return False
处理StaleElementReferenceException
def get_fresh_element(driver, by, value):"""获取一个新鲜的元素引用,避免StaleElementReferenceException"""try:return driver.find_element(by, value)except StaleElementReferenceException:# 重新查找元素return driver.find_element(by, value)
模拟鼠标操作
在浏览器中定位元素后,也就需要能够模拟鼠标的一些操作了,在webdriver 中,鼠标操作绝大多数封装在ActionChains类中。
from selenium.webdriver.common.action_chains import ActionChains
常见方法如下:
方法 | 描述 |
---|---|
click() | 单击左键(不需要导入 ActionChains 即可实现) |
context_click() | 单击右键 |
double_click() | 双击 |
drag_and_drop() | 拖动 |
move_to_element() | 鼠标悬停 |
perform() | 执行所有ActionChains中存储的动作 |
单击左键
# 定位搜索按钮
button = driver.find_element_by_xpath('//*[@id="toolbar-search-button"]/span')
# 执行单击操作
button.click()
单击右键
from selenium.webdriver.common.action_chains import ActionChains# 定位搜索按钮
button = driver.find_element_by_xpath('//*[@id="toolbar-search-button"]/span')
# 右键搜索按钮
ActionChains(driver).context_click(button).perform()
注意: 调用perform()才会执行
注意: selenium 框架虽然提供了 鼠标右键方法,但是没有提供选择右键菜单方法,可以通过键盘快捷键操作实现
拖动
模拟鼠标拖动操作,该操作有两个必要参数,
- source:鼠标拖动的元素
- target:鼠标拖至并释放的目标元素
from selenium import webdriver
from selenium.webdriver import ActionChainsdriver = webdriver.Chrome()
driver.get('file:///D:/%E6%A1%8C%E9%9D%A2/page/drag.html')red = driver.find_element_by_xpath('//*[@id="div1"]')
blue = driver.find_element_by_xpath('//*[@id="div2"]')# 实例化鼠标
action = ActionChains(driver)
# 鼠标拖拽
action.drag_and_drop(red, blue)
# 鼠标执行
action.perform()driver.quit()
鼠标悬停
模拟悬停的作用一般是为了显示隐藏的下拉框。
模拟键盘操作
在浏览器中定位元素后,也就需要能够模拟键盘的一些操作了,在webdriver 中,键盘操作绝大多数封装在Keys类中。
from selenium.webdriver.common.keys import Keys
使用方法
# 输入文本
element.send_keys('文本')
# 键盘单键
element.send_keys(Keys.XXX)
# 组合键
element.send_keys(Keys.XXX, 'a') # 注意这里的组合键都是小写
举例
from selenium.webdriver.common.keys import Keys# 定位输入框并输入文本
driver.find_element_by_id('xxx').send_keys('hello world')# 模拟回车键进行跳转(输入内容后)
driver.find_element_by_id('xxx').send_keys(Keys.ENTER)# 使用 Backspace 来删除一个字符
driver.find_element_by_id('xxx').send_keys(Keys.BACK_SPACE)# Ctrl + A 全选输入框中内容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'a')# Ctrl + C 复制输入框中内容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'c')# Ctrl + V 粘贴输入框中内容
driver.find_element_by_id('xxx').send_keys(Keys.CONTROL, 'v')
其他常见键盘操作:
描述 | 按键 |
---|---|
空格 | Keys.SPACE |
Tab键 | Keys.TAB |
Alt键 | Keys.ALT |
Shift键 | Keys.SHIFT |
向下箭头 | Keys.ARROW_DOWN |
向左箭头 | Keys.ARROW_DOWN |
向右箭头 | Keys.ARROW_RIGHT |
向上箭头 | Keys.ARROW_UP |
F1键 | Keys.F1 |
其他控制操作
元素操作
.clear() # 清空内容 一般用于清空输入框内容
.is_displayed() # 判断该元素是否可见
.get_attribute() # 获取标签属性值
.size # 返回元素的尺寸
.text # 返回元素文本
.is_enabled() # 判断元素是否可用 如:element.is_enabled()
.is_selected() # 判断元素是否被选中 如:element.is_selected()
浏览器操作
# 方法
"""
1、driver.maximize_window() # 最大化浏览器
2、driver.set_window_size(w,h) # 设置浏览器大小 单位像素
3、driver.set_window_position(x,y) # 设置浏览器位置
4、driver.back() # 后退操作
5、driver.forward() # 前进操作
6、driver.refrensh() # 刷新操作
7、driver.close() # 关闭当前主窗口(主窗口:默认启动那个界面,就是主窗口)
8、driver.quit() # 关闭driver对象启动的全部页面
9、driver.title # 获取当前页面title信息
10、driver.current_url # 获取当前页面url信息
"""
注意:driver.close() ,关闭当前主窗口,只有完成页面切换(下文提及)才可以关闭新的页面。
在我们打开浏览器时,打开的主页面称为主窗口。随后我们在该浏览器内可以打开多个页面,并且这些多个页面可以并列显示,但主窗口还是最初的那一个页面。
下拉框操作
下拉框是HTML中的元素,对下拉框的操作的方法封装在Select类中。
# 导包
from selenium.webdriver.support.select improt Select# 下拉框标签
<select>
<option></option>
<option></option>
</select>element = driver.find_element_by_id("select") # 通过元素定位方式找到<select>标签,也就是下拉框
# 实例化
select = Select(element)# 操作方法
1)、select_by_index() # 根据option索引 选中下拉框选项
2)、select_by_value() # 根据option属性 value值 选中下拉框选项
3)、select_by_visible_text() # 根据option显示文本 选中下拉框选项
弹出框操作
一旦出现弹出框,如果不进行处理,则后续操作不可实现
JavaScript 有三种弹窗 alert(确认)、confirm(确认、取消)、prompt(文本框、确认、取消)。
处理方式:先定位(switch_to.alert自动获取当前弹窗),再使用 text、accept、dismiss、send_keys 等方法进行操作
方法 | 描述 |
---|---|
text | 获取弹窗中的文字 |
accept | 接受(确认)弹窗内容 |
dismiss | 解除(取消)弹窗 |
send_keys | 发送文本至警告框 |
一个简单的测试页面,其中包含三个按钮,分别对应三个弹窗。
<!DOCTYPE html>
<html lang="en"><head>
</head><body><button id="alert">alert</button><button id="confirm">confirm</button><button id="prompt">prompt</button><script type="text/javascript">const dom1 = document.getElementById("alert")dom1.addEventListener('click', function(){alert("alert hello")})const dom2 = document.getElementById("confirm")dom2.addEventListener('click', function(){confirm("confirm hello")})const dom3 = document.getElementById("prompt")dom3.addEventListener('click', function(){prompt("prompt hello")})</script>
</body>
</html>
下面使用上面的方法进行测试。为了防止弹窗操作过快,每次操作弹窗,都使用 sleep 强制等待一段时间。
from selenium import webdriver
from pathlib import Path
from time import sleepdriver = webdriver.Firefox()
driver.get('file:///' + str(Path(Path.cwd(), '弹窗.html')))
sleep(2)# 点击alert按钮 弹出alert弹窗
driver.find_element_by_xpath('//*[@id="alert"]').click()
sleep(1)
alert = driver.switch_to.alert # 定位到弹窗
# 打印alert弹窗的文本
print(alert.text)
# 确认
alert.accept()# 点击confirm按钮 弹出confirm弹窗
driver.find_element_by_xpath('//*[@id="confirm"]').click()
sleep(1)
confirm = driver.switch_to.alert # 定位到弹窗
print(confirm.text)
# 取消
confirm.dismiss()# 点击prompt按钮 弹出prompt弹窗
driver.find_element_by_xpath('//*[@id="prompt"]').click()
sleep(1)
prompt = driver.switch_to.alert # 定位到弹窗
print(prompt.text)
# 向prompt的输入框中传入文本
prompt.send_keys("hello world")
sleep(2)
prompt.accept()
滚动条
在现在浏览器页面中,元素可能是动态显示,需要根据滚动条的下拉而被加载。
或者有些特殊场景中,需要将页面滑动后才能进行操作。例如,页面注册同意条款,需要拉到最底端点击确认按钮。
Selenium框架中没有专门处理滚动条的方法,需要通过调用 Js 代码实现操作;webdriver 中使用execute_script方法实现 JavaScript 的执行。
通过 x ,y 坐标滑动滚动条,我们需要知道坐标的起始位置在页面左上角(0,0)
from selenium import webdriver
from time import sleepdriver = webdriver.Chrome()
driver.get("https://blog.csdn.net/")
sleep(1)
# 设置操作滚动条操作JavaScript语句
# 0:为左边距 对应 水平滚动条
# 1000: 对应 垂直滚动条
js = "window.scrollTo(0,500);"
# 调用执行js方法,将设置js语句传入方法中
driver.execute_script(js)
frame/iframe表单
很多页面也会用 frame/iframe 表单嵌套,对于这种内嵌的页面 selenium 是无法直接定位其中的元素,需要使用 switch_to.frame() 方法将当前操作的对象切换成 frame/iframe 内嵌的页面,再进行元素定位操作。
使用方法:driver.switch_to.frame(“id/name/element”) 进行切换表单操作,传入的是代表表单唯一的特征值。如果 frame 没有 id 或 name ,这时就需要使用 xpath 进行定位。
<!DOCTYPE html>
<html lang="en"># HTML 其他部分略
<body><iframe id="CSDN_info" name="Dream丶Killer" src="https://blog.csdn.net/qq_43965708" width="400" height="200"></iframe>
</body>
</html>
from selenium import webdriver
from pathlib import Pathdriver = webdriver.Chrome()
# 读取本地html文件
driver.get('file:///' + str(Path(Path.cwd(), 'iframe测试.html')))# 1.通过id定位
driver.switch_to.frame('CSDN_info')
# 2.通过name定位
# driver.switch_to.frame('Dream丶Killer')
# 通过xpath定位
# 3.iframe_label = driver.find_element_by_xpath('/html/body/iframe')
# driver.switch_to.frame(iframe_label)
通过 driver.switch_to.frame()切换到表单当中后,我们再随后使用之前的元素定位方法就可以定位到表单中的元素,并进行后续的操作。
连续切换frame/iframe
说明:如果要实现多个frame之间的切换,假如现在页面中一共有两个iframe。从主页面已经切换到第一个iframe中,想要从第一个iframe切换到第二个iframe,需要先切换回到主页面,然后才能切换到第二个iframe。
回到主页面的方法:driver.switch_to.default_content()
from selenium import webdriverdriver = webdriver.Chrome()
driver.get('file:///D:/%E6%A1%8C%E9%9D%A2/page/%E6%B3%A8%E5%86%8C%E5%AE%9E%E4%BE%8B.html')driver.switch_to.frame('idframe1')
driver.find_element_by_id('userA').send_keys('admin')
# 切换回到主页面
driver.switch_to.default_content()
driver.switch_to.frame('myframe2')
driver.find_element_by_id('userB').send_keys('admin4')driver.quit()
多窗口切换
在点击超链接或某些按钮后,可能会在新窗口中打开新的页面。这时候 selenium 还是只能定位主窗口,需要进行切换才能够定位最新页面上的元素。
每个窗口都有唯一的一个句柄值,那么我们就可以通过句柄值来完成窗口的切换操作
切换方法:
1)、driver.current_window_handle (获取当前窗口的句柄值)
2)、driver.window_handles ( 获取当前由driver启动的所有窗口句柄)
3)、driver.switch_to.window(handle) —> 切换窗口
from selenium import webdriverdriver = webdriver.Chrome()
driver.get('file:///D:/%E6%A1%8C%E9%9D%A2/page/%E6%B3%A8%E5%86%8C%E5%AE%9E%E4%BE%8B.html')# 1、获取当前窗口的句柄值
# print("当前的句柄值是:", driver.current_window_handle)# 2、获取driver启动的所有窗口句柄
handles = driver.window_handles# 3、切换窗口
driver.switch_to.window(handles[-1])driver.quit()
注意:窗口切换后,现在使用close()就是关闭切换后的页面,如果还想重新操作原始页面,需要重新进行窗口切换。
截图操作
driver.get_screenshot_as_file(imgpath) # imgpath 图片保存路径
注意:需要先创建文件夹,该方法不会主动创建不存在的文件夹路径。
验证码处理
验证码是一种随机生成的信息(数字,字母、汉字、图片、算术题等)为了防止恶意的请求行为,增加应用的安全性。
在WEB应用中,大部分系统在用户注册和登录时,都需要输入验证码。在自动化测试的时候,就要处理验证码的问题。
处理方式大致有:
1、去除验证码(测试环境中 可以这样处理)
2、设置万能验证码(测试环境中 可以这样处理)
3、采用第三方的验证码识别库
4、记录cookie (使用cookie跳过登录)
主要介绍使用cookie跳过登录:
客户端在登录账号后,将登录状态相关的cookie 信息发给服务器,再发送去请求,携带cookie信息如果跟服务器保留的一致,则服务器认为客户端是登录状态。(关于cookie的详细解释,可以查看我的另外一篇博客,或者自行查阅资料。)
webdriver 提供 cookies 的几种操作:读取、添加删除。
get_cookies:以字典的形式返回当前会话中可见的 cookie 信息。
get_cookie(name):返回cookie字典中 某个cookie 的Value。
add_cookie(cookie_dict):将 cookie 添加到当前会话中,以字典的方式添加
delete_cookie(name):删除指定名称的单个 cookie。
delete_all_cookies():删除会话范围内的所有 cookie。
1、获取与登录有关的cookie信息
2、整理cookie信息为字典数据
3、调用方法添加cookie
driver.add_cookie(cookie变量)
4、刷新页面 -->发送cookie给服务器验证
driver.refresh()
实例
准备工作,在百度WEB应用登录的状态下,获取cookie字段(BDUSS这个cookie,及其对应的Value与登录有关)
from selenium import webdriver
driver = webdriver.Chrome()driver.get('https://www.baidu.com/')
driver.maximize_window()# 1、整理cookie信息为字典数据,对应的是name和value,保存在一个变量中
# 此处的name和value是从浏览器上手动获取的
cookie_value = {'name':'BDUSS',
'value':'........................'}
# 2、调用方法添加cookie
driver.add_cookie(cookie_value)
# 3、刷新页面 -->发送cookie给服务器验证
driver.refresh()
# 登录成功
driver.quit()
# 另外一种思路
from selenium import webdriver
driver = webdriver.Chrome()driver.get('https://www.baidu.com/')
driver.maximize_window()# 查看所有cookie信息
print(driver.get_cookies())# 1、整理cookie信息为字典数据,对应的是name和value,保存在一个变量中
cookie_value = {'name':'BDUSS',
'value':driver.get_cookie('BDUSS')}
# 2、调用方法添加cookie
driver.add_cookie(cookie_value)
# 3、刷新页面 -->发送cookie给服务器验证
driver.refresh()
# 登录成功
driver.quit()# 删除 name = 'BDUSS' 的cookie信息
# driver.delete_cookie('BDUSS')
# 删除当前会话中的所有cookie
# driver.delete_all_cookies()
注意:
1、不同项目的cookie字段信息不同
2、利用cookie绕过了登录,但也别忘记对登录功能进行测试。
3、部分项目用cookie绕过登录,可能需要添加多个cookie
4、cookie信息可能会过期,需要重新登录获取。
上传与下载文件
上传文件
常见的 web 页面的上传,一般使用 input 标签或是插件(JavaScript、Ajax),对于 input 标签的上传,可以直接使用 send_keys(路径) 来进行上传。
一个测试用的页面。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><input type="file" name="">
</body>
</html>
通过 xpath 定位 input 标签,然后使用 send_keys(str(file_path) 上传文件。
from selenium import webdriver
from pathlib import Path
from time import sleepdriver = webdriver.Chrome()
file_path = Path(Path.cwd(), '上传下载.html')
driver.get('file:///' + str(file_path))driver.find_element_by_xpath('//*[@name="upload"]').send_keys(str(file_path))
下载文件
Chrome 浏览器要想实现文件下载,需要通过 add_experimental_option 添加 prefs 参数。
download.default_directory:设置下载路径。
profile.default_content_settings.popups:0 禁止弹出窗口。
下面测试下载搜狗图片。指定保存路径为代码所在路径。
from selenium import webdriver prefs = {'profile.default_content_settings.popups': 0,'download.default_directory': str(Path.cwd())}
option = webdriver.ChromeOptions()
option.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(options=option)
driver.get("https://pic.sogou.com/d?query=%E7%83%9F%E8%8A%B1&did=4&category_from=copyright")
driver.find_element_by_xpath('/html/body/div/div/div/div[2]/div[1]/div[2]/div[1]/div[2]/a').click()driver.switch_to.window(driver.window_handles[-1])
driver.find_element_by_xpath('./html').send_keys('thisisunsafe')
代码最后两句实际作用是当你弹出像下面的页面 “您的连接不是私密连接” 时,可以直接键盘输入 “thisisunsafe” 直接访问链接。由于该标签页是新打开的,所以要通过 switch_to.window() 将窗口切换到最新的标签页。
Firefox 浏览器要想实现文件下载,需要通过 set_preference 设置 FirefoxProfile() 的一些属性。
- browser.download.foladerList:0 代表按浏览器默认下载路径;2 保存到指定的目录。
- browser.download.dir:指定下载目录。
- browser.download.manager.showWhenStarting:是否显示开始,boolean 类型。
- browser.helperApps.neverAsk.saveToDisk:对指定文件类型不再弹出框进行询问。
- HTTP Content-type对照表:https://www.runoob.com/http/http-content-type.html
from selenium import webdriver
import os
fp = webdriver.FirefoxProfile()
fp.set_preference("browser.download.dir",os.getcwd())
fp.set_preference("browser.download.folderList",2)
fp.set_preference("browser.download.manager.showhenStarting",True)
fp.set_preference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream")driver = webdriver.Firefox(firefox_profile = fp)
driver.get("https://pic.sogou.com/d?query=%E7%83%9F%E8%8A%B1&did=4&category_from=copyright")
driver.find_element_by_xpath('/html/body/div/div/div/div[2]/div[1]/div[2]/div[1]/div[2]/a').click()
参考目录
https://www.bilibili.com/video/BV1eZ4y1s7BY
https://www.bilibili.com/video/BV18Q4y1y7v3
https://blog.csdn.net/yuanbang_bc/article/details/147515853
https://blog.csdn.net/qq_54219272/article/details/123310772
https://blog.csdn.net/kobepaul123/article/details/128796839
https://blog.csdn.net/qq_43965708/article/details/120658713
https://blog.csdn.net/qq_54219272/article/details/123338773