赞
踩
Selenium 是一个基于浏览器的自动化工具,可以跨平台、跨浏览器使用。
Selenium 主要包括三部分:
1、Selenium IDE: Firefox 浏览器的一个插件(扩展),它可以进行录制回放,并且可以把录制的操作以多 种语言(如 JAVA、Python、C#等)的形式导出成测试用例。
2、Selenium WebDriver: 提供 Web 自动化所需的 API,主要用作浏览器控制、页面元素选择和调试。不同 的浏览器需要不同的 WebDriver。
3、Selenium Grid: 提供了在不同机器的不同浏览器上运行 selenium 测试的能力。
Selenium的工作原理涉及几个关键组件:WebDriver、浏览器驱动(Browser Driver)、以及Selenium Server或Remote Server:
1、WebDriver: 是一个API接口,用于操作浏览器。
2、浏览器驱动: 是一个与浏览器相对应的程序,它可以接收来自WebDriver的指令,并执行这些指令。
3、Selenium Server/Remote Server:
- Selenium Server是一个可以运行于浏览器的服务器,可以接收从WebDriver发出的命令。
- Remote Server是一个独立的服务器,可以运行在不同的机器上,用于接收和处理WebDriver发出的命令。
参考博客:Selenium环境搭建(浏览器驱动下载)-CSDN博客
# 创建驱动对象
#通过驱动发送请求,打开测试页面
浏览器设置
- from selenium import webdriver
- from selenium.webdriver.edge.options import Options
-
- # 实例化Options
- option = Options()
- # 不自动关闭浏览器的配置
- option.add_experimental_option("detach", True)
-
- # 在打开浏览器之前,去掉自动化标识
- option.add_experimental_option('excludeSwitches', ['enable-automation'])
- option.add_argument('--disable-blink-features=AutomationControlled')
-
- # 关掉密码弹窗
- prefs = {}
- prefs['credentials_enable_service'] = False
- prefs['profile.password_manager_enabled'] = False
- option.add_experimental_option('prefs', prefs)
-
- # 实例化driver对象,将option传入
- driver = webdriver.Edge(options=option)
id -----------------------------> find_element(By.ID,'xxx')
class ------------------------> find_element(By.CLASS_NAME,'xxx')
name ------------------------> find_element(By.NAME,'xxx')
link_text --------------------> find_element(By.LINK_TEXT,'xxx')
partial_link_text ----------> find_element(By. PARTIAL_LINK_TEXT,'xxx')
tag_name------------------> find_element(By.TAG_NAME,'xxx')
xpath -----------------------> find_element(By.XPATH,'xxx')
css --------------------------> find_element(By.CSS_SELECTOR,'xxx')
- # 通过ID定位
- driver.find_element(By.ID, 'kw').send_keys("奥运会")
-
- 通过NAME定位
- driver.find_element(By.NAME, 'wd').clear()
-
- # 通过CLASS_NAME定位
- driver.find_element(By.CLASS_NAME, 'bg s_btn').click()
-
- # 文本属性精准定位
- driver.find_element(By.LINK_TEXT, '新闻').click()
-
- # 文本属性的模糊定位(包含即可)
- driver.find_element(By.PARTIAL_LINK_TEXT, '新').click()
xpath可以通过"id、name、……"等标签,定位
# 通过id属性
//标签[@id="xxx"]
绝对xpath:它其实是标签的层级路径
/html/body/div[3]/div/div[2]/div[1]/div/ul[4]/li[2]/a
很不稳定,只要元素前面多出元素就有可能影响xpath的准确性
相对xpath:它其实是通过属性定位元素
//*[@id="q"]
推荐使用相对xpath,或者手写这样的相对xpath
当有多个元素时,得到是一个列表,可以通过索引取值
- # 方式1:
- eles = driver.find_elements(By.XPATH,'//a[text()="个人信息"]')
- eles[1].click()
-
- # 方式2:通过xpath直接获取第几个(这里下标从1开始)
- driver.find_element(By.XPATH,'(//a[text()="个人信息"])[2]').click()
使用场景:
当新建的信息需要删除,就可以这种方式找到创建信息,对应的删除按钮,进行删除
使用轴定位编写xpath
- $x('//span[text()="老Will"]/../../li//a[text()="删除"]')
-
- # 祖先元素
- //span[text()="老Will"]/ancestor::div[1] 最近一个
- //span[text()="老Will"]/ancestor::div 最古老一个
- $x('//span[text()="老will"]/ancestor::ul//a[text()="删除"]')
-
- # 兄弟元素
- $x('//a[text()="地址管理"]/../preceding-sibling::li[3]')
- $x('//a[text()="地址管理"]/../following-sibling::li[1]')
使用text()属性定位,也属于xpath的一种,但是次方法很方便
//标签[text()="xxx"]
driver.maximize_window()--------最大化浏览器
drvier.refresh()----------------刷新浏览器
driver.back()-------------------后退
driver.forward()----------------前进
driver.close()------------------关闭浏览器当前页面
driver.quit()-------------------关闭浏览器
- # 以x,y坐标点,设置浏览器的位置,以左上角为启点
- driver.set_window_position(100, 600)
-
- # 设置浏览器的分辨率宽高
- driver.set_window_size(宽, 高)
-
- # 获取当前页title名称
- tile_name = driver.title #百度一下,你就知道
-
- # 获取当前页面url
- url_name = driver.current_url #https://www.baidu.com/
xxx
click()--------------------->点击(左击)
send_keys(‘xxx’)------->在输入框内输入 xxx
clear()--------------------->清空目标对象上的内容
submit()------------------->提交---强调对表单内容的提交
text------------------------->获取元素的文本内容
get_attribute('class')---------->获取页面元素的某个属性
size-------------------------------->获取元素的大小(宽高) 字典格式{'height': 55, 'width': 350}
查看元素是否可见:is_display() 返回值是布尔值
查看元素是否可用:is_enable() 返回值是布尔值
selenium是支持模拟鼠标操作,是通过一系列的事件链来完成鼠标需要进行的动作,然后提交。
使用步骤:
首先必选创建一个事件链对象(ActionChains)
使用事件链对象来调用方法进行鼠标操作
右击:context_click()
双击:double_click()
拖拽:drag_and_drop(元素1, 元素2) 或 move_by_offset(x, y)
悬停:move_to_element()
其他...
最后鼠标事件链方法调用完之后一定要进行事务的提交
perform()
注意:如果鼠标事件不进行提交,那么所有的方法都无法生效
- # 创建事件链对象
- chains = ActionChains(driver)
- # 右击:context_click()
- el1 = driver.find_element(By.XPATH,'//*[@id="passwordA"]')
- chains.context_click(el1)
- # 提交事件
- chains.perform()
- # 双击:double_click()
- chains.double_click(el1)
- chains.perform()
步骤:
- # - 悬停:move_to_element()
- from selenium.webdriver import ActionChains
-
- # 元素定位
- ele = driver.find_element(By.XPATH, "//span[text()='账户设置'] ")
- # 悬停操作ActionChains()是一个鼠标操作的类
- action = ActionChains(driver)
- # .perform():提交
- action.move_to_element(ele).perform()
从元素1位置 拖拽到 元素2位置
- # - 拖拽:drag_and_drop()
- el2 = driver.find_element(By.XPATH, '//*[@id="div1"]')
- el3 = driver.find_element(By.XPATH, '//*[@id="div2"]')
-
- chains.drag_and_drop(el2, el3)
- chains.perform()
按像素拖动,可横向拖动(x=n, y=0),可纵向拖动(x=0, y=n)
- block = driver.find_element(By.XPATH,'//*[@id="nc_1_n1z"]')
- action = ActionChains(driver)
-
- # 按住滑块
- action.click_and_hold(block)
-
- # 移动到最右边
- action.move_by_offset(400,0)
-
- # 松开鼠标
- action.release().perform()
Selenium之常见键盘的操作:
https://mp.csdn.net/mp_blog/creation/editor/138118005
特殊标签:select选择框元素
需要对选择框进行定位操作必须创建一个选择框对象进行使用
使用步骤:
首先需要通过Select类创建select对象
通过select对象去选中下拉框元素的具体内容
通过索引(下标)选择,下标从0开始
通过文本内容选择
通过value属性选择
- select = Select(driver.find_element(By.XPATH, '//*[@id="selectA"]'))
- time.sleep(2)
-
- # - 通过索引(下标)选择
- select.select_by_index(1)
-
- # - 通过文本内容选择
- time.sleep(2)
- select.select_by_visible_text("A重庆")
-
- # - 通过value属性选择
- time.sleep(2)
- select.select_by_value('gz')
selenium当中默认没有提供具体方法进行页面滚动操作
可以通过JavaScript脚本去执行滚动操作
使用步骤:
- # 滚动
- # - 首先定义一个滚动的js脚本
- # "window.scrollTo(x,y)"
- time.sleep(2)
-
- js_str = "window.scrollTo(0,100000)"
- # - 然后调用js执行脚本方法:execute_script()
- driver.execute_script(js_str)
selenium提供了截图的方法,但是目前只支持png格式
screenshot()方法
- # 截图 png格式图片
- ele = driver.find_element('xpath', '//*[@id="verify_code_img"]')
- ele.screenshot('./verify.png')
get_screenshot_as_file() -------获取当前浏览器的页面截屏,保存 file 文件
get_screenshot_as_png() -------获取当前浏览器的页面截屏,保存 png 文件
更多截图:https://mp.csdn.net/mp_blog/creation/editor/138125293
警告框出现的机制属于JavaScript脚本执行的结果
一般警告框的类型分为:
不管是那种类型的警告框,都会对页面的继续操作进行阻碍
解决警告框的方法:
获取警告框(悬浮页面只上所以需要进行切换到警告框)
关闭警告
- 确认关闭
- 取消关闭
获取警告框的提示信息
针对一些警告框可以输入内容的可以进行输入(send_keys("密码"))
- # 警告框
- driver.find_element(By.XPATH, '//*[@id="alerta"]').click()
-
- # 切换到警告框里面
- alert1 = driver.switch_to.alert
-
- # 获取警告框的提示信息
- print(alert1.text)
- time.sleep(1)
-
- # # - 确认关闭
- # alert1.dismiss()
-
- # # - 取消关闭
- alert1.accept()
-
- # 针对一些警告框可以输入内容的可以进行输入(send_keys("密码"))
- # alert1.send_keys("123456")
一个浏览器可以开启多个页面,每个页面都有不同的标识(句柄)
操作步骤:
- 1.获取窗口句柄
- 2.进入指定窗口
1.获取窗口句柄(所有句柄、单个)
- # 获取所有的窗口句柄
- hand_list = driver.window_handles
- print(hand_list) # ['008F7760981BF', '008F7760379BF']
-
- # 获取所有的窗口句柄
- hand_now = driver.current_window_handle
- print(hand_now) # 008F7760379BF
2.窗口切换 switch_to.window
- # 切换窗口 switch_to.window(句柄id)
- driver.switch_to.window(driver.window_handles[1])
代码示例:
- # - 获取浏览器中所有的页面句柄:window_handles
- print(driver.window_handles) # 返回值是一个列表
-
- # - 获取单个页面的句柄:current_window_handle
- print(driver.current_window_handle)
-
- # 点击页面的超链接获取多个页面
- driver.find_element(By.XPATH, '//*[@id="navitems-group1"]/li[4]/a').click()
- print(driver.window_handles)
-
- # 页面没有进行切换,那么无法对其他页面进行操作
- # 需要通过获取所有页面句柄的列表下标切换页面
- driver.switch_to.window(driver.window_handles[1])
- driver.find_element(By.XPATH, '//*[@id="extra-zhenpin"]/a').click()
- print(driver.window_handles)
-
- # 页面切换
- driver.switch_to.window(driver.window_handles[2])
- driver.find_element(By.XPATH, '//*[@id="nav-duobaodao"]/a').click()
- print(driver.window_handles)
- time.sleep(2)
-
- # - 支持自由切换不同页面句柄
- driver.switch_to.window(driver.window_handles[0])
- driver.find_element(By.XPATH, '//*[@id="key"]').send_keys("电脑")
- print(driver.current_window_handle)
-
- # - 创建新的页面句柄
- driver.switch_to.new_window()
- print(driver.current_window_handle)
总结:
如果需要操作具体某个页面的元素,必须先切换到页面句柄中,才能执行操作
定位frame框架内的元素需要进行跳入跳出
跳入框架:driver.switch_to.frame(ele1) # ele1='frame框架元素'
跳出框架:driver.switch_to.default_content()
注意:跳出框架会直接跳出到初始框架中,当存在多个frame框架时,需要注意
- # 1.定位frame框架
- frame = driver.find_element(By.XPATH,'/html/frameset/frame[1]')
- # 跳入frame框架
- driver.switch_to.frame(frame)
- # 操作frame内的元素
- driver.find_element(By.XPATH,'//*[@id="navs"]/ul/li[2]/a').click()
- # 退出frame框架
- driver.switch_to.default_content()
-
- # 2.点击全部贷款
- frame = driver.find_element(By.XPATH,'//*[@id="menu-frame"]')
- # 切换
- driver.switch_to.frame(frame)
- driver.find_element(By.XPATH,'/html/body/dl[1]/dd[1]/a').click()
- # 退出子页面(默认回到主页面)
- driver.switch_to.default_content()
一般需要进行iframe框架的跳入操作,等同于frame框架
如图:
xxx
检查上传按钮,在按钮附近找到一个<input type="file"这样的标签
<input type="file" 可以直接使用send_keys('文件的绝对路径')
# 元素标签
<input type="file" class="ke-upload-file" name="imgFile" tabindex="-1">
代码示例:
- # 定位元素后,使用send_keys输入文件路径
- driver.find_element(By.XPATH, '//input[@type="file"]').send_keys(r"D:\verify.png")
-
- # 单文件上传
- driver.find_element(By.XPATH, '//*[@id="filePicker"]/div[2]/input').send_keys(r'C:\Users\Amy\Desktop\will.png')
-
- # 多文件上传
- driver.find_element(By.XPATH, '//*[@id="filePicker"]/div[2]/input').send_keys('\n'.join([r'C:\Users\Amy\Desktop\will.png',r'C:\Users\Amy\Desktop\will.png']))
js详细语法参考博客:
https://www.cnblogs.com/PengHwei/p/18138390
- # 开始时间:
- # 强制输入:通过JavaScript脚本进行参数接受
- el5 = driver.find_element(By.XPATH, '//*[@id="start_time"]')
- # 执行JS脚本需要调用execute_script()
- driver.execute_script("arguments[0].value='2023-07-15 21:10:10'", el5)
在执行前需要再浏览器控制台执行js函数
- function add_time(params) {
- console.log(arguments[0])
- }
提高代码的稳定性,保证页面元素因其它情况的影响下,没有被加载出来,导致程序报错情况的出现
最常见的有三种等待方式:隐式等待、显式等待、强制等待
强制等待又称固定等待,就是无论元素是否被加载出来,都会等待设定时间
需要现导入Python内置的time模块 import time
调用sleep()方法,指定等待2s后继续 time.sleep(2)
特点
作用域是整个webdriver对象
如果需元素在第一次定位的时候就已经出现,则不会触发隐式等待
元素没有定位到会报错(NoSuchElementException)
弊端:
它将会在寻找每个element的时候都进行等待,这样会增加整个测试执行的时间
语法
driver.implicitly_wait(10)
- from selenium import webdriver
-
- driver = webdriver.Chrome()
- driver.maximize_window()
- driver.get('https://www.baidu.com/')
-
- # 设置全局等待10s
- driver.implicitly_wait(10)
-
- # 查找baidu首页中的kw元素,查找到了则继续下一步
- driver.find_element(By.ID,'kw')
浏览器查看cookies
路径:Application(应用程序)-->Storage(存储)-->Cookies
添加cookies
通过百度cookie信息设置保持登录状态
- # # 给页面添加cookie信息
- driver.add_cookie({"name": "BAIDUID", "value": "DDC8E5F343BF028B014:FG=1"})
- driver.add_cookie({"name": "BDUSS",
- "value":"VmRERYbWM5bkN5Umd4MzkdhcU1AAAAAAAAHaKnWR2ip1kem"})
- # 设置完cookie信息之后,需要进行清楚缓存才能保持登录
- time.sleep(2)
- driver.refresh()
获取登录后所有cookies,并进行制定提取
一般需要获取name和value
- # 获取所有cookies信息,返回列表[{},{},……]
- cookies_list = driver.get_cookies()
- # print(cookies_list)
- # 遍历所有cookies
- for cookie in cookies_list:
- # print(cookie)
- # 提取特定cookie; 例如提取name为'BAIDUID', 以及对应的value值
- if cookie["name"] == 'BAIDUID':
- print(cookie["name"], cookie["value"])
cookie信息是保存在客户端的浏览器上面的
服务器管理,当前用户id是处于登录还是未登录的状态
通过浏览器的application里面查看不用页面的cookie信息
关闭整个浏览器(服务器会识别已退出)
手动删除页面的cookie识别登录id
修改也可以实现退出登录状态
从已经登录之后的状态的cookie信息中提取id进行使用
在未登录的页面中使用cookie信息
# 获取页面中的cookie信息
cookies1 = driver.get_cookies() # 返回值是列表中嵌套字典,字典的所有键值对指定的就是页面的cookie信息
print(cookies1)
# 使用cookie信息
for cookie in cookies1:
print(cookie)
driver.add_cookie(cookie)
else:
driver.refresh()
封装函数获取和使用cookies
- def save_cookies(driver):
- # 将页面中的cookies信息保存在本地文件中
- cookies1 = driver.get_cookies()
- with open("cookies.json", "w") as f:
- f.write(json.dumps(cookies1))
-
- def load_cookies(driver):
- driver.get("http://47.107.116.139/fangwei/m.php?m=Public&a=login&")
- try:
- with open("cookies.json") as f:
- cookies = json.loads(f.read())
- # 使用cookies
- for cookie in cookies:
- # print(cookie)
- driver.add_cookie(cookie)
- else:
- driver.refresh()
- except:
- print("目前没有cookie信息,不能进行绕过登录")
为了提高代码容错率,判断是否是登录的状态,防止元素定位出现问题
- def is_login(driver):
- # 通过登录状态判断是否已登录
- if "管理员登录" in driver.title:
- print("需要正常登录")
- return False
- else:
- print("已登录")
- return True
'运行
思想:先去使用cookies,如果没有直接进行正常登录
- # 创建一个驱动对象
- driver = webdriver.Edge()
- # 准备一个被测试的页面url地址
- url = "http://47.107.116.139/fangwei/m.php?m=Public&a=login&"
- # 通过驱动发送请求
- driver.get(url)
- # 页面最大化
- driver.maximize_window()
-
- # 在页面正常登录之前使用cookies
- load_cookies(driver)
-
- # 判断是否已登录
- if not is_login(driver): # 没有登录
- # 截图验证码图片
- driver.find_element(By.XPATH, '//*[@id="verify"]').screenshot("verify.jpg")
- # 调用第三方接口通过函数识别:
- code = get_verify_code("verify.jpg", 'xap001', '123456@xzp', "1902", "959380")
- # 账号
- driver.find_element(By.XPATH, '//input[@name="adm_name"]').send_keys('admin')
- # 密码
- driver.find_element(By.XPATH, '//input[@name="adm_password"]').send_keys("msjy123")
- # 验证码
- driver.find_element(By.XPATH, '//input[@name="adm_verify"]').send_keys(code)
- # 登录按钮
- driver.find_element(By.XPATH, '//*[@id="login_btn"]').click()
- # 提取登录cookies,保存到json文件中
- save_cookies(driver)
- time.sleep(1)
- # 关闭驱动
- # driver.quit()
详见验证码问题博文:
https://mp.csdn.net/mp_blog/creation/editor/138138791
一般web自动化的设计模式有两种类型
P:page代表页面
O:object代表对象
M:module代表模型
以页面对象为模型进行封装和使用
核心思想:对页面元素进行封装成类的属性(类属性),用例执行流程设计成页面类的方法(实例方法)
作用:可以减少代码的冗余,而且方便后期维护,若页面元素发生变化,只需要调整页面封装的属性即可,从而提高用例脚本的可维护性以及可读性
流程:
页面需要被操作的元素定义成类的类属性
页面需要执行的用例脚本定义成类的实例方法
用例执行通过页面类创建一个页面对象,进行调用实例方法完成用例执行
pom模式封装页面:类属性和实例方法
- class BackLogin:
- def __init__(self, driver):
- self.driver = driver
-
- # 封装页面属性
- #账号
- username = (By.XPATH, '//input[@name="adm_name"]')
- #密码
- password = (By.XPATH, '//input[@name="adm_password"]')
- #验证码-
- code = (By.XPATH, '//input[@name="adm_verify"]')
- #登录按钮
- btn_ok = (By.XPATH, '//*[@id="login_btn"]')
- # 获取实际结果
- res_txt = (By.XPATH, '//*[@id="login_msg"]')
-
- # 登录功能
- def login(self, username, password, code=None):
- self.find_element(*self.username, self.driver).send_keys(username)
- self.find_element(*self.password, self.driver).send_keys(password)
- self.find_element(*self.code, self.driver).send_keys(code)
- self.find_element(*self.btn_ok, self.driver).click()
- # 获取实际文本属性 -->这里采用自定义显示等待方法定位
- msg = self.find_element(*self.res_txt, self.driver, need_wait=True).text
- return msg
在case脚本文件调用
- back_login = BackLogin(driver)
- msg = back_login.login("admin", "123456", "")
- print(msg)
-
- assert msg == "验证码不能为空"
K:key代表关键字
D:driver代表驱动
T:test代表用例
核心思想:关键字驱动测试,可以实现极限封装0代码模式条件下,结合Excel表格数据进行去读,构造每个用例的步骤,完成用例的执行,得到最终的结果。
可以实现自动化框架搭建以及功能测试人员的分工
自动化测试框架搭建者负责关键字驱动测试的用例脚本设计
功能测试负责编写Excel规范的用例步骤
BasePage一般在pom设计模式中当做所有页面的父类(页面元类)
BasePage属于抽象类的范畴
不建议把BasePage类去实例化对象
不能代表任何的实例对象
把子类页面需要共同使用的资源(属性及方法)统一封装到BasePage元类中
简单理解:子类中使用率非常高的属性和方法统一抽取封装到BasePage元类中
- class BasePage:
- def __init__(self, driver):
- self.driver = driver
-
- def wait(self, func):
- return WebDriverWait(self.driver, 5).until(func)
-
- def find_element(self, by, value, need_wait=False):
- def f(driver):
-
- # 判断当前元素是否有文本属性
- if driver.find_element(by, value).text:
- msg = driver.find_element(by, value).text
- if need_wait: # 是否触发隐式等待,返回实际提示信息结果
- return msg
- else:
- return True
- else:
- return True
-
- self.wait(f)
- return self.driver.find_element(by, value)
'运行
其它页面类继承BasePage
- class DealPage(BasePage):
- pass
动态元素定位:
1、正向和反向用例,元素可能不一致,不能将元素定位写死,考虑模糊定位
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。