0


Python+Selenium4三大等待&预期条件_web自动化(4)

0. 上节回顾

  • WebDriver的角度看,有8种元素定位策略
  • 从浏览器的角度来看,有2种元素选择器: - CSS选择器执行效率高 - XPath选择器使用效率高
  • 底层通过JS实现,可以通过F12进行获取、调试

1. 定位失败的原因

元素交互过程中出错:

  1. 元素不存在
  2. 元素不可见
  3. 元素被遮挡
  4. 元素被禁用

如:元素被延迟渲染

with get_webdriver() as driver:
    driver.get("http://118.24.147.95:8086/delay.html")
    ele = driver.find_element(By.XPATH, '//*[@id="content"]/input')
    print(ele)
selenium.common.exceptions.NoSuchElementException: Message: no such element:
Unable to locate element: {"method":"xpath","selector":"//*[@id="content"]/input"}

DEBUG秘技:

控制台输入 debugger 让网页停下来

#cdp:chrome devtools 协议
driver.execute_cdp_cmd("Debugger.enable", {}) # JS断点 selenium 4 新特性 (执行的慢的话有概率失败)
driver.execute_script("setTimeout('debugger',0.1*1000)") #JS断电 selenium 3
pdb.set_trace()#python 断点

解决了定位失败的问题

with get_webdriver() as driver:
    driver.get("http://118.24.147.95:8086/delay.html")
    # cdp:chrome devtools 协议
    driver.execute_cdp_cmd("Debugger.enable", {})  # JS断点 selenium 4 新特性 (执行的慢的话有概率失败)
    driver.execute_script("setTimeout('debugger',0.1*1000)")  # JS断电 selenium 3
    pdb.set_trace()  # python 断点
    ele = driver.find_element(By.XPATH, '//*[@id="content"]/input')
    print(ele)
 > f:\pythonworkspace\ui_p39_selenium4\1.py(18)<module>() 

-> ele = driver.find_element(By.XPATH, '//*[@id="content"]/input')

(Pdb)

通过DEBUG,发现很多的元素是通过JS动态创建、改变、修改的,如果要定位准许,需要“等待”JS完成

相关的操作:

  • 强制等待 sleep
  • 隐式等待 implicitly_wait
  • 显式等待 WebDriverWait
  • 流畅等待 FluentWait

2. 强制等待

sleep 实际上编程语言中的语句:当程序执行到sleep指令时,会暂停x 秒,然后再继续执行

import time
time.sleep(6) # 定位代码,延迟6秒再执行
  • 以秒为单位
  • 可以是浮点数:(0.1秒)

使用方法简单粗暴,但是相对呆板,应用场景不多

如:验证 【登录成功】

with get_webdriver() as driver:
    driver.get("http://101.34.221.219:8010/?s=user/loginInfo.html")
    driver.find_element(By.XPATH, "/html/body/div[4]/div/div[2]/div[2]/div/div/div[1]/form/div[1]/input", ).send_keys(
        "tiancao")
    driver.find_element(By.XPATH,
                        "/html/body/div[4]/div/div[2]/div[2]/div/div/div[1]/form/div[2]/div/input", ).send_keys(
        "ganju123")
    driver.find_element(By.XPATH,
                        "/html/body/div[4]/div/div[2]/div[2]/div/div/div[1]/form/div[3]/button", ).click()  # 点击登录
    time.sleep(1)  # sleep的值不好取,太大 或者 太小,都会失败
    msg = driver.find_element(By.XPATH, "//p[@class='prompt-msg']", ).text
    assert msg == "登录成功"  # 没有任何输出,说明断言成功

对于出现之后会消失的元素来讲,要求sleep的秒数相当精确

学习selenium中提供 **等待 **来进行解决

3. 隐式等待

原理:让selenium在查找元素时,如果失败,就重试

默认:参数为0 表示禁用

启用:参数大于1 即可

特点:一旦启用,全局(driver)生效

弊端:

  • 只会等待元素**出现 **
  • 不会等待元素就绪
with get_webdriver() as driver:
    # driver.implicitly_wait(0) #禁用
    driver.implicitly_wait(10)  # 启用隐式等待,每一次等待最长不超过10秒
    driver.get("http://118.24.147.95:8086/delay.html")
    msg = driver.find_element(By.XPATH, '//*[@id="content"]/p').text
    ele = driver.find_element(By.XPATH, '//*[@id="content"]/input')
    assert msg == "大家好,我是北凡"

对于复杂的业务场景,不只要求元素存在,还要求元素的状态就绪

http://118.24.147.95:8086/flash.html

如果要对等待条件,进行定制,就需要用到显式等待

4. 显式等待 【重点难点】

显示等待指的是 WebDriverWait 对象

所谓“显式”,是为了相对于前面的“隐式”而言的,

在显式等待中:等待的时机、内容,根据清晰、直观、可控

**4.1. ****实例化 **WebDriverWait **对象 **

  • 两个参数 (固定写法) driver: WebDriver实例 (浏览器对象)
  • 10 :超时时间,等待最多不超过10秒
WebDriverWait(driver, 10)

**4.2. ****指定等待条件 **

灵活写法(难写法)

msg = WebDriverWait(driver, 10).until(
lambda x: driver.find_element(
By.XPATH,
"//p[@class='prompt-msg']",
).text
)
# 等待条件(匿名函数)
lambda x: driver.find_element(
By.XPATH,
"//p[@class='prompt-msg']",
).text

x 是匿名函数的参数,被传递了driver

driver = webdriver.Chrome()  # 启动浏览器 是空白页

driver.get("http://101.34.221.219:8010/?s=user/loginInfo.html")
driver.find_element(By.XPATH,"/html/body/div[4]/div/div[2]/div[2]/div/div/div[1]/form/div[1]/input",).send_keys("tiancao")
driver.find_element(By.XPATH,"/html/body/div[4]/div/div[2]/div[2]/div/div/div[1]/form/div[2]/div/input",).send_keys("ganju123")
driver.find_element(By.XPATH,"/html/body/div[4]/div/div[2]/div[2]/div/div/div[1]/form/div[3]/button",).click() # 点击登录

msg = WebDriverWait(driver, 10).until(lambda x: driver.find_element(
By.XPATH,
"//p[@class='prompt-msg']",
).text)
assert msg == "登录成功",f"{msg}" # 没有任何输出,说明断言成功
#driver.quit()

**4.3. ****等待条件的具体要求 **

成功例子:在等待中,定位元素,函数返回了布尔值True 再交互

with get_webdriver() as driver:
    driver.get("http://118.24.147.95:8086/delay.html")
    ele = WebDriverWait(driver, 10).until(
        lambda x: driver.find_element(By.XPATH, '//*[@id="content"]/input')
    )
    ele.click()  # 元素交互

driver.find_element(By.XPATH, '//*[@id="content"]/input') 的返回值, 是一个对象,它布尔值是 True

失败的例子:在等待中,交互元素

   WebDriverWait(driver, 10).until(  # 定位元素
        lambda x: driver.find_element(By.XPATH, '//*[@id ="content"] /input').click()
    )

返回值是 driver.find_element(By.XPATH, '//* [@id="content"]/input').click() 是None,它的布尔值是 False

4.3. 1. 等待条件是一个函数

可以是普通函数

也可以是匿名函数

匿名函数 和普通函数有什么区别?

**区别 **

**普通函数 **

匿名函数

关键

def

lambda

名字

有名字

没有名字

长度

可以多行

只能一行

返回值

可选,用return指定

必选,返回表达式结果

**4.3. 2. 返回值是布尔值 **

  • 必须是布尔值,不是布尔值, 也会按照布尔值进行判断
  • 如果判断为Ture,表示等待成功,停止等待
  • 如判断为False,表示等待失败,继续等到,直到超时,

*4.3. 3. 只有一个参数,参数值是***driver **

**4.3. 4. 出现异常 **

出现 NoSuchElementException 异常表示等待失败,将继续等待

出现其他异常,表示出错,停止等待

出现TimeOut异常,表示超时,停止等待

**总结 **

  1. 是个函数

  2. 有且只有一个参数,参数值是driver

  3. 返回值应该是布尔值如果是Ture,表示等待成功,停止等待

  • 如果是False,表示等待失败,继续等待,直到超时
  • 如果是 NoSuchElementException 异常,表示等待失败,**继续等待 **
  • 如果是其他异常,表示出错,**停止等待 **

如果,想要以False表示成功怎么办?可以使用 until_not 方法:

  • 如果是Ture,表示等待失败,继续等待,直到超时
  • 如果是False,表示等待成功,停止等待
# WebDriverWait(driver, 10).until(lambda x: False) # 会超时
WebDriverWait(driver, 10).until_not(lambda x: False) # 会成功

5. 流畅等待 (最底层,最强大,最难)

selenium 核心是用什么语言开发的? **java **

在Java 语言中,流畅等待指的是 FluentWait 对象,是 WebDriverWait 的父类

在Python中,没有定义 FluentWait 对象,直接使用 WebDriverWait 对象完成流畅等待

和显式等待相比,流畅等待增加2****个参数

  • 重试频率 (等待的原理:失败重试,多久重试一次?)
  • 忽略的异常列表

可以实现更加复杂的业务场景

**5. 1. 元素闪现太快 **

with get_webdriver() as driver:
    driver.get("http://118.24.147.95:8086/flash_fast.html")
    WebDriverWait(driver, 10, 0.01).until(  # 调整了重试频率
        lambda x: driver.find_element(By.XPATH, "//p")
    )

5. 2. 出现特殊异常

with get_webdriver() as driver:
    driver.get("http://118.24.147.95:8086/delay_alert.html")
    alert = WebDriverWait(
    driver,
    10,
    ignored_exceptions=[
    NoAlertPresentException
    ], # 在等待过程中,如果出现NoAlertPresentException, 就继续等待
    ).until(lambda x: driver.switch_to.alert)
    print(alert.text)

6. 等待策略可以复用

复用前

with get_webdriver() as driver:
    driver.implicitly_wait(10)  # 隐式等待只要设置一次
    driver.get("http://118.24.147.95:8086/flash.html")

    p = WebDriverWait(driver, 10).until(  # 显式等待要设置1次
        lambda x: driver.find_element(By.XPATH, "//p"))

    p = WebDriverWait(driver, 10).until(  # 显式等待要设置1次
        lambda x: driver.find_element(By.XPATH, "//input"))

复用后

with get_webdriver() as driver:
    driver.wait = WebDriverWait(driver, 10)  # 等待策略 设置1次
    driver.get("http://118.24.147.95:8086/flash.html")
    p = driver.wait.until(lambda x: driver.find_element(By.XPATH, "//p"))
    i = driver.wait.until(lambda x: driver.find_element(By.XPATH, "//input"))  # 到处使用

7. Selenium官网中:等待的警告

隐式等待 和显式 等待不要混用

在框架,只用显式等待(或者流畅等待)


本文转载自: https://blog.csdn.net/weixin_41121249/article/details/128563429
版权归原作者 天草柑橘 所有, 如有侵权,请联系我们删除。

“Python+Selenium4三大等待&预期条件_web自动化(4)”的评论:

还没有评论