Python 测开28期 - WL - 学习笔记 - 显式等待与控件交互

显式等待高级使用

显式等待原理

  • 在代码中定义等待一定条件发生后再进一步执行代码
  • 在最长等待时间内循环执行结束条件的函数
  • 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()

键盘事件

键盘事件 - 使用 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)