05. Selenium-其它重要Api
2024年10月28日大约 12 分钟
05. Selenium-其它重要Api
1. 元素等待方法
1. 认识元素等待
- 界面渲染和脚本运行速度哪个快
- NOSuchElementException
- 网络速度慢
- 电脑配置低
- 服务器处理请求慢
- Time.sleep() 影响运行效率
- 元素等待
- 在定位页面元素时如果未定位到,会在指定时间内一直等待的过程
- 分类
- 隐式等待
- 显示等待(流畅等待)
- 警告: 不要混合使用隐式和显式等待。这样做会导致不可预测的等待时间。
2. 隐式等待
定位元素时,如果能定位到元素则直接返回该元素,不触发等待;
如果不能定位到该元素,则间隔一段时间后再去定位元素;
如果在达到最大时长时还没有找到指定元素,则抛出元素不存在的异常NoSuchElementException。
driver.implicitly_wait(timeout)
全局生效,所有元素第一次未找到触发等待10秒
- driver.implicitly_wait(10)
演练
完成下面对浏览器的操作 需求:打开注册A.html页面,完成以下操作 最大化窗口 使用隐式等待定位延时加载输入框,输入admin
from time import sleep from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait """ 1. 强制等待 使用方法:time.sleep(delay) 说明:delay的单位为秒,delay设置多少秒页面就会等待多少秒(死等),这个方法很容易让线程挂掉,使程序抛异常,所以要慎用此方法。 2.显式等待(有条件等待) 当等待的条件满足后(一般用来判断需要等待的元素是否加载出来),就继续下一步操作。等不到就一直等,如果在规定的时间之内都没找到,那么就抛出Exception。 使用显示等待前需先导入显示等待所需模块和等待条件 #显式等待模块 from selenium.webdriver.support.ui import WebDriverWait #显式等待条件 from selenium.webdriver.support import expected_conditions as EC 3.隐式等待(无条件等待,在一个时间段内等待) 一次设置,全局生效。 不要当作固定等待使用,不要每次需要等待时都写一次隐式等待。 隐式等待设置了一个最长等待时间,在规定时间内网页加载完成(也就是一般情况下你看到浏览器标签栏那个小圈不再转就代表加载完成),则执行下一步,否则一直等到时间结束,然后执行下一步。 如果是只需等待页面中的一个元素加载就用显示等待,等待整个网页加载就用隐式等待。 使用方法:implicitly_wait(delay),delay的单位为秒 """ # 1、获取浏览器 from selenium.webdriver.common.by import By import config driver = webdriver.Chrome() # 2、打开url driver.get(config.html_a_register_a_path) # 全局生效,所有元素第一次未找到触发 等待10秒 driver.implicitly_wait(10) # 验证隐式等待 driver.find_element(By.CSS_SELECTOR, "#userA").send_keys('admin') # 2、显示等待 -> 返回查找到的元素 el = WebDriverWait(driver, 10, 0.5).until(lambda x: x.find_element(By.CSS_SELECTOR, "#userA")) el.send_keys("admin") # 4、关闭浏览器 sleep(3) driver.quit()
3. 显示等待
定位元素时,如果能定位到元素则直接返回该元素,不触发等待;
如果不能定位到该元素,则间隔一段时间后再去定位元素;
如果在达到最大时长时还没有找到指定元素,则抛出超时异常 TimeoutException
针对单个元素生效
实现方法
# 1. 导包 from selenium.webdriver.support.wait import WebDriverWait # 2. 创建显示等待类对象 WebDriverWait(driver, timeout, poll_frequency=0.5) # 3. 调用until方法 until(method):# 直到...时 el = WebDriverWait(driver, 10, 0.5).until(lambda x: x.find_element(By.CSS_SELECTOR, "#userA")) el.send_keys("admin")
演练
完成下面对浏览器的操作 需求:打开注册A.html页面,完成以下操作 最大化窗口 使用显示等待定位延时加载输入框,输入admin
from time import sleep from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait """ 1. 强制等待 使用方法:time.sleep(delay) 说明:delay的单位为秒,delay设置多少秒页面就会等待多少秒(死等),这个方法很容易让线程挂掉,使程序抛异常,所以要慎用此方法。 2.显式等待(有条件等待) 当等待的条件满足后(一般用来判断需要等待的元素是否加载出来),就继续下一步操作。等不到就一直等,如果在规定的时间之内都没找到,那么就抛出Exception。 使用显示等待前需先导入显示等待所需模块和等待条件 #显式等待模块 from selenium.webdriver.support.ui import WebDriverWait #显式等待条件 from selenium.webdriver.support import expected_conditions as EC 3.隐式等待(无条件等待,在一个时间段内等待) 一次设置,全局生效。 不要当作固定等待使用,不要每次需要等待时都写一次隐式等待。 隐式等待设置了一个最长等待时间,在规定时间内网页加载完成(也就是一般情况下你看到浏览器标签栏那个小圈不再转就代表加载完成),则执行下一步,否则一直等到时间结束,然后执行下一步。 如果是只需等待页面中的一个元素加载就用显示等待,等待整个网页加载就用隐式等待。 使用方法:implicitly_wait(delay),delay的单位为秒 """ # 1、获取浏览器 from selenium.webdriver.common.by import By import config driver = webdriver.Chrome() # 2、打开url driver.get(config.html_a_register_a_path) # 全局生效,所有元素第一次未找到触发 等待10秒 driver.implicitly_wait(10) # 验证隐式等待 driver.find_element(By.CSS_SELECTOR, "#userA").send_keys('admin') # 2、显示等待 -> 返回查找到的元素 el = WebDriverWait(driver, 10, 0.5).until(lambda x: x.find_element(By.CSS_SELECTOR, "#userA")) el.send_keys("admin") # 4、关闭浏览器 sleep(3) driver.quit()
4. 等待对比
隐式等待 | 显示等待 | |
---|---|---|
作用域 | 只用设置一次,对全局生效 | 只对指定元素生效 |
抛出异常 | NoSuchElementException | TimeOutException |
使用方法 | driver.implicitly_wait(timeout) | 通过WebDriverWait对象 |
其它 | 必须等待整个页面加载完成 | 只关注指定元素是否加载 |
2. 多窗口切换、Frame方法
1. Frame
认识frame
- HTML页面中的一种框架,主要作用是在当前页面中指定区域显示另一页面元素
- frameset形式
- iframe标签形式
- HTML页面中的一种框架,主要作用是在当前页面中指定区域显示另一页面元素
Frame切换方法
- 切换指定iframe
- driver.switch_to.frame(frame_reference)
- frame_reference:iframe标签元素对象
- 恢复默认页面
- driver.switch_to.default_content()
- 切换指定iframe
演练
案例:打开‘注册实例.html’页面,完成以下操作 填写主页面的注册信息 填写注册页面A中的注册信息 填写注册页面B中的注册信息
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By import config # 1、获取浏览器 driver = webdriver.Chrome() driver.implicitly_wait(10) # 2、打开url driver.get(config.html_b_register_path) """ 页面注册A在iframe标签中,验证不处理是否能操作 """ # 设置注册用户 default = driver.find_element(By.CSS_SELECTOR, "#user") default.send_keys("123") sleep(2) # 获取注册A iframe元素 A = driver.find_element(By.CSS_SELECTOR, "#idframe1") # 1、切换到A driver.switch_to.frame(A) # 2、注册A操作 driver.find_element(By.CSS_SELECTOR, "#userA").send_keys("admin_a") # 3、回到默认目录 注册实例.html driver.switch_to.default_content() default.clear() default.send_keys("niguolaia") # 4、获取注册B iframe元素 B = driver.find_element(By.CSS_SELECTOR, "#idframe2") # 5、切换到B driver.switch_to.frame(B) # 6、注册B操作 driver.find_element(By.CSS_SELECTOR, "#userB").send_keys("admin_b") # 4、关闭浏览器 sleep(3) driver.quit()
2. 多窗口
认识多窗口
- 多窗口:在HTML页面中,当点击超链接或者按钮时,有的会在新的窗口打开页面。
- Selenium只能定位当前窗口中的元素,要定位新的窗口的元素必须进行窗口切换
多窗口切换方法
窗口切换
- selenium需要通过窗口的句柄来实现窗口的切换
句柄
- 因为handle,窗口的唯一标识码
多窗口切换步骤
- 切换所有窗口句柄
- handles = driver.window_handles
- 切换指定窗口
- driver.switch_to.window(handles[n])
- 切换所有窗口句柄
演练
案例:打开‘注册实例.html’页面,完成以下操作 点击 访问 百度 网站 超链接 在百度搜索输入框输入软件测试
完成下面的操作 需求:打开‘注册实例.html’页面,完成以下操作 点击‘注册A页面’链接 在打开的页面中,填写注册信息
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By import config # 1、获取浏览器 driver = webdriver.Chrome() driver.implicitly_wait(10) # 2、打开url driver.get(config.html_b_register_path) """ 为什么要处理多窗口?-- selenium默认焦点在启动窗口,要操作其他窗口必须处理。 需求: 1、打开注册示例页面 2、点击注册A网页链接 3、填写注册A网页内容 """ print("操作之前所有窗口的句柄:", driver.window_handles) driver.find_element(By.ID, 'user').send_keys("admin") driver.find_element(By.LINK_TEXT, "注册A网页").click() handles = driver.window_handles print("操作之后所有窗口的句柄:", handles) # 重点:切换窗口 driver.switch_to.window(handles[1]) # 填写注册A网页 用户名 driver.find_element(By.CSS_SELECTOR, "#userA").send_keys("admin_a") driver.switch_to.window(handles[0]) driver.find_element(By.ID, 'user').send_keys(" back") # 4、关闭浏览器 sleep(3) driver.quit()
多窗口工具封装
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By import config # 1、获取浏览器 driver = webdriver.Chrome() driver.implicitly_wait(10) # 2、打开url driver.get(config.html_b_register_path) """ 需求: 如何随心所欲切换窗口? 思路: 1、获取所有窗口句柄 2、切换窗口 3、获取当前所在窗口title 4、判断title是否为需要的窗口 5、执行代码 需求: 1、打开注册示例页面 2、点击 注册A网页 注册B网页 3、在A网页和B网页中输入 对用户名输入 admin """ def switch_window(title): # 1、获取所有窗口句柄 handels = driver.window_handles # 2、遍历句柄进行切换 for handel in handels: # 操作 driver.switch_to.window(handel) # 获取当前窗口title 并且 判断是否自己需要的窗口 if driver.title == title: # 操作代码 return "已找到{}窗口,并且已切换成功".format(title) else: print("不是要找的窗口") title_A = "注册A" title_B = "注册B" # 打开注册A和注册B网页 driver.find_element(By.LINK_TEXT, "注册A网页").click() driver.find_element(By.LINK_TEXT, "注册B网页").click() # 填写注册A网页 用户名 print(switch_window(title_A)) driver.find_element(By.CSS_SELECTOR, "#userA").send_keys("admin") print(switch_window(title_B)) driver.find_element(By.CSS_SELECTOR, "#userB").send_keys("admin") # 4、关闭浏览器 sleep(3) driver.quit()
3. 执行UI自动化时如找不到元素该分析哪些原因?
元素定位代码是否正确
是否是匹配到唯一元素
是否有做元素等待
是否需要鼠标悬浮
元素是否在新窗口
元素是否存在于iframe标签中
3. 窗口截图
错误到底在哪呀?
- UI自动测试统一运行时无人值守
- 错误信息记录不是十分明确
- 有截图结合错误信息方便快速分析错误
- driver.get_screenshot_as_file(imgpath)
- imgpath:图片保存路径
案例
需求:打开‘注册A.html’页面,完成以下操作 填写注册信息 截图保存
import time from time import sleep from selenium import webdriver # 1、获取浏览器 from selenium.webdriver.common.by import By import config driver = webdriver.Chrome() # 2、打开url driver.get(config.html_b_register_a_normal_path) # 3、查找操作元素 driver.find_element(By.CSS_SELECTOR, "#userA").send_keys("admin") driver.get_screenshot_as_file("userA.png") driver.find_element(By.CSS_SELECTOR, "#passwordA").send_keys("123456") driver.find_element(By.CSS_SELECTOR, "#telA").send_keys("13600001111") driver.find_element(By.CSS_SELECTOR, "#emailA").send_keys("123@qq.com") # 截图 driver.get_screenshot_as_file("register.png") driver.get_screenshot_as_file("error_{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S"))) # 4、关闭浏览器 sleep(3) driver.quit()
4. 验证码处理
认识验证码
说明:Selenium中并没有对验证码处理的方法,在这里我们介绍一下针对验证码的几种常用处理方式 方式: 1). 去掉验证码 (测试环境下-采用) 2). 设置万能验证码 (生产环境和测试环境下-采用) 3). 验证码识别技术 (通过Python-tesseract来识别图片类型验证码;识别率很难达到100%) 4). 记录cookie (通过记录cookie进行跳过登录) 提示 1. 去掉验证码、设置万能验证码:都是开发来完成,我们在这里不做讲解 2. 验证码识别技术:成功率不高,验证码种类繁多,不太适合 3. 记录cookie:比较实用,我们对它进行下讲解
要进行后续业务操就必须登陆,那自动化该如何处理这些验证码操作?
- 验证码识别技术
- 去掉验证码、万能验证码
- 记录cookie
认识cookie
- Cookie是由Web服务器生成的,并且保存在用户浏览器上的小文本文件,它可以包含用户相关的信息。
- Cookie数据格式:键值对组成(python中的字典)
- Cookie产生:客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个Cookie 数据
- Cookie使用:当浏览器再次请求该网站时,浏览器把请求的数据和Cookie数据一同提交给服务器,服务器检查该Cookie,以此来辨认用户状态。
Cookie跳过登陆
手工登陆 > 获取cookie > 脚本添加cookie > 刷新页面
Cookie操作方法
- driver.get_cookie(name) --> 获取指定cookie
- driver.get_cookies() --> 获取本网站所有本地cookies
- driver.add_cookie(cookie_dict) --> 添加cookie
- cookie_dict:一个字典对象,必选的键包括:"name" and "value"
演练
需求:使用cookie实现跳过登录 手动登录百度,获取cookie 使用获取到的cookie,达到登录目的,然后就可以执行登录之后的操作 BDUSS是登录百度后的唯一身份凭证(*.baidu.com),拿到BDUSS就等于拿到帐号的控制权, 通行贴吧、知道、百科、文库、空间、百度云等百度主要产品。
""" 需求:使用cookie实现百度登录 依赖kookies: BDUSS """ from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://www.baidu.com") driver.maximize_window() # 添加cookie data = { "name": "BDUSS", "value": "由于安全问题,暂时删除。" } driver.add_cookie(data) print(driver.get_cookies()) # 暂停3秒 sleep(3) # 刷新 driver.refresh() # 个人中心 sleep(3) driver.find_element(By.ID, 's-top-username').click() sleep(3) driver.quit()
5. 综合练习
import unittest
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestLogin(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get("http://192.168.10.31:9003/Home/user/login.html")
self.driver.implicitly_wait(10)
def tearDown(self) -> None:
sleep(5)
self.driver.quit()
def test01_login(self):
# 输入用户名
self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("13600001111")
# 输入密码
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123456")
# 输入验证码
self.driver.find_element(By.CSS_SELECTOR, "#verify_code").send_keys("8888")
# 点击登录
self.driver.find_element(By.CSS_SELECTOR, ".J-login-submit").click()
# 退出
self.driver.find_element(By.PARTIAL_LINK_TEXT, '退出').click()