显式等待高级使用
显式等待原理
- 在代码中定义等待一定条件发生后再进一步执行代码
- 在最长等待时间内循环执行结束条件的函数
- WebDriverWait(driver 实例, 最长等待时间, 轮询时间).until(结束条件函数)
# 设定超时时间:开始时间加上传入的超时时间
end_time = time.monotonic() + self._timeout
while True:
try:
# 执行传入的函数参数,获取执行结果,若结果为真,则返回函数执行结果
value = method(self._driver)
if value:
return value
except self._ignored_exceptions as exc:
screen = getattr(exc, 'screen', None)
stacktrace = getattr(exc, 'stacktrace', None)
# 每次循环间隔时间,默认0.5s,可以传入参数设定
time.sleep(self._poll)
# 如果超时,则退出循环并抛出异常
if time.monotonic() > end_time:
break
# 循环正常结束,超时异常
raise TimeoutException(message, screen, stacktrace)
excepted_conditions
- Selenium 显式等待官网说明
- 演示网站:霍格沃兹测试开发
- 确定返回值是否为 webelement对象,要点到condition中的源码进行查看,不能生搬硬套
- 不是所有的 expected_conditions 的返回值都u是 webelement对象
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium. webdrivef.support import expected _conditions
from selenium. webdriver.support.wait import WebDriverWait
def wait until() :
driver = webdriver. Chrome ()
driver.get("https://vip.ceshiren. com/#/ui study")
WebDriverWait(driver, 10).until(expected_conditions.element_to_be_clickable((By.CSS_SELECTOR,'#success btn')))"
driver.find element(By.CSS SELECTOR,#success btn").click ()
- 常见 expected_conditions
类型 | 示例方法 | 说明 |
---|---|---|
element | element_to_be_clickable() visibility_of_element_located() |
针对于元素,比如判断元素是否可点击,或者元素是否可见 |
url | url_contains() | 针对于 url |
title | title_is() | 针对于标题 |
frame | frame_to_be_available_and_switch_to_it(locator) | 针对于frame |
alert | alert_is_present() | 针对于弹窗 |
封装等待条件
- 官方的 excepted_conditions 不可能覆盖所有场景
- 定制封装条件会更加灵活、可控
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
# 问题: 使用官方提供的expected condition 已经无法满足需求
# 解决方案: 自己封装期望条件
# 期望条件的设计: 需求: 一直点击按钮,直到下一个页面出现为止
class TestWebdriverWait:
driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(5)
driver.get("https://vip.ceshiren.com/#/ui_study")
def teardown(self):
self.driver.quit()
def test_webdriver_wait(self):
# 解决的问题:有的按钮点击一次没有反应,可能要点击多次,比如企业微信的添加成员
# 解决的方案:一直点击按钮,直到下个页面出现,封装成显式等待的一个条件
def muliti_click(button_element,until_ele):
# 函数封装
def inner(driver):
# 封装点击方法
driver.find_element(By.XPATH,button_element).click()
return driver.find_element(By.XPATH,until_ele)
return inner
time.sleep(5)
# 在限制时间内会一直点击按钮,直到展示弹框
WebDriverWait(self.driver,10).until(muliti_click("//*[text()='点击两次响应']","//*[text()='该弹框点击两次后才会弹出']"))
time.sleep(5)
高级控件交互方法
- 使用场景
使用场景 | 对应事件 |
---|---|
复制粘贴 | 键盘事件 |
拖动元素到某个位置 | 鼠标事件 |
鼠标悬停 | 鼠标事件 |
滚动到某个元素 | 滚动事件 |
使用触控笔点击 | 触控笔事件 |
ActionChains 解析
- 实例化类 ActionChains,参数为 driver 实例
- 中间可以有多个操作
- .perform() 代表确定执行
- ActionChains(self.driver).操作.perform()
键盘事件
- 按下、释放键盘键位
- 结合 send_keys回车
- https://www.selenium.dev/documentation/webdriver/actions_api/keyboard/#tabs-1-1
键盘事件 - 使用 shift 实现大写
- ActionChains(self.driver):实例化 ActionChains类
- key_down(Key.SHIFT, ele):按下 shift键实现大写
- send_keys(“selenium”):输入大写的selenium
- perform():确认执行
键盘事件 - 输入后回车
- 直接输入回车:元素.send_keys(Keys.ENTER)
- 使用 ActionChains:key_down(Keys.ENTER)
键盘事件 - 复制粘贴
-
多系统兼容
- mac 的复制按钮为 COMMAND
- windows 的复制按钮为 CONTROL
-
左箭头:Keys.ARROW_LEFT
-
按下 COMMAND 或者 CONTROL:key_down(cmd_ctrl)
-
按下剪切与粘贴按钮:send_keys(“sssss")
-
示例代码
import sys
import time
from selenium import webdriver
from selenium.webdriver import ActionChains, Keys
from selenium.webdriver.common.by import By
class TestKeyBoardDemo:
def setup_class(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(3)
def teardiwn_class(self):
self.driver.quit()
def test_shift(self):
# 1.访问 https: // ceshiren.com / 官方网站
# 2. 点击搜索按钮
# 3.输入搜索的内容,输入的同时按着shift键
self.driver.get("http://ceshiren.com/")
self.driver.find_element(By.ID, 'search-buttun').click()
# 目标元素即为输入框
ele = self.driver.find_element(By.ID, "search-term")
# 1/ key down 代表按下某个键位
# 2/输入内容
# 3.执行以上操作
ActionChains(self.driver).key_down(Keys.SHIFT, ele).send_keys("selenium").perform()
time.sleep(3)
def test_enter(self):
self.driver.get("https://www.sogou.com/")
ele = self.driver.find_element(By.ID, "query")
ele.send_keys("selenium")
# 第一种方式
ele.send_keys(Keys.ENTER)
# 第二种方式
ActionChains(self.driver).key_down(Keys.ENTER).perform()
time.sleep(3)
def test_copy_and_paste(self):
self.driver.get("https://ceshiren.com/")
# 兼容性,判断操作系统的ctrl按钮
cmd_ctrl = Keys.COMMAND if sys.platform == 'darwin' else Keys.CONTROL
self.driver.find_element(By.CSS_SELECTOR, '#search-button>svg').click()
ele = self.driver.find_element(By.ID, "search-term")
# 打开搜索,选择搜索框,输入 element,剪切后复制,几个v就代表复制几次
ActionChains(self.driver).key_down(Keys.SHIFT, ele).send_keys("element").send_keys(Keys.ARROW_LEFT).send_keys(
Keys.ARROW_LEFT).send_keys(Keys.ARROW_LEFT).send_keys(Keys.ARROW_LEFT).send_keys(Keys.ARROW_LEFT).send_keys(
Keys.ARROW_LEFT).send_keys(Keys.ARROW_LEFT).key_down(cmd_ctrl).send_keys('xvvv').key_up(cmd_ctrl).perform()
time.sleep(5)
鼠标事件
鼠标事件 - 双击
- double_click(元素对象):双击元素
拖动元素
- drag_and_drop(起始元素对象, 结束元素对象):拖动并放开元素
鼠标事件 - 悬浮
- move_to_element(元素对象):移动到某个元素
鼠标事件 - 滚动
- 滚动到元素
- 根据坐标滚动
- 注意:selenium版本需要在4.2之后
- 注意:只有 chrome 内核可以使用
- Scroll wheel actions | Selenium
- 滚动方式 - 两种
- scroll_to_element(WebElement对象):滚动到某个元素
- scroll_by_amount(横坐标, 纵坐标)
def test_double_click(self):
self.driver.get("https://vip.ceshiren.com/#/ui_study/frame")
ele = self.driver.find_element(By.ID, 'primary_btn')
# 调用 actionchains 的鼠标双击事件方法
ActionChains(self.driver).double_click(ele).perform()
time.sleep(3)
def test_drag_and_drop(self):
self.driver.get('https://vip.ceshiren.com/#/ui_study/frame')
# 跳转目标页面
self.driver.find_element(By.CSS_SELECTOR, '#action_chains>span').click()
time.sleep(2)
# 获取起始位置元素
item_lift = self.driver.find_element(By.ID, 'item1')
# 获取结束位置元素
item_right = self.driver.find_element(By.ID, 'item3')
# 拖拽并放开元素
ActionChains(self.driver).drag_and_drop(item_lift,item_right).perform()
time.sleep(3)
def test_move_to_element(self):
self.driver.get('https://vip.ceshiren.com/#/ui_study/frame')
# 跳转目标页面
self.driver.find_element(By.CSS_SELECTOR, '#action_chains2>span').click()
# 获取目标元素位置
ele = self.driver.find_element(By.CSS_SELECTOR, '.menu>.title')
ActionChains(self.driver).move_to_element(ele).perform()
txt = self.driver.find_element(By.CSS_SELECTOR, '.options>div:nth-child(3)')
assert '测开班' in txt.text
txt.click()
def test_scroll_to_element(self):
self.driver.get("https://ceshiren.com/")
self.driver.find_element(By.CSS_SELECTOR, '#ember25>a').click()
ele = self.driver.find_element(By.CSS_SELECTOR, '.footer-message.ember-view')
ActionChains(self.driver).scroll_to_element(ele).perform()
time.sleep(2)
def test_scroll_by_amount(self):
self.driver.get("https://ceshiren.com/")
self.driver.find_element(By.CSS_SELECTOR, '#ember25>a').click()
ActionChains(self.driver).scroll_by_amount(0,200).perform()
time.sleep(2)