0. 上节回顾
- WebDriver的角度看,有8种元素定位策略
- 从浏览器的角度来看,有2种元素选择器: - CSS选择器执行效率高 - XPath选择器使用效率高
- 底层通过JS实现,可以通过F12进行获取、调试
1. 定位失败的原因
元素交互过程中出错:
- 元素不存在
- 元素不可见
- 元素被遮挡
- 元素被禁用
如:元素被延迟渲染
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异常,表示超时,停止等待
**总结 **
是个函数
有且只有一个参数,参数值是driver
返回值应该是布尔值如果是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官网中:等待的警告
隐式等待 和显式 等待不要混用
在框架,只用显式等待(或者流畅等待)
版权归原作者 天草柑橘 所有, 如有侵权,请联系我们删除。