通常代码执行的速度⽐页⾯渲染的速度要快,如果避免因为渲染过慢出现的⾃动化误报的问题呢?可以使⽤selenium中提供的三种等待⽅法:
1. 隐式等待(Implicit Wait)
隐式等待适用于全局,它告诉 WebDriver 在查找元素时等待一定的时间,直到元素出现。
如果超时,WebDriver 不会抛出异常,而是返回 NoSuchElementException
。
适用场景
- 页面加载速度不稳定,元素可能会晚一点出现。
- 适合不需要精确等待时间的情况。
from selenium import webdriver
# 设置 Edge 浏览器
driver = webdriver.Edge()
# 设置隐式等待 10 秒
driver.implicitly_wait(10)
# 访问网页
driver.get("https://example.com")
# 查找元素(如果元素未出现,则最多等待 10 秒)
element = driver.find_element("id", "someElement")
# 关闭浏览器
driver.quit()
implicitly_wait(10)
适用于 整个 WebDriver 生命周期。- 只需要设置一次,之后所有
find_element()
调用都会等待。- 无法针对特定元素设置不同的等待时间。
2. 显式等待(Explicit Wait)
显式等待用于等待某个特定元素出现,在超时时间内不断检查,直到条件满足。
它比隐式等待更精确,可以用于特定的元素。
适用场景
- 只想等待某个特定元素,而不是所有元素。
- 需要等待的条件较复杂,例如元素可见、可点击等。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 设置 Edge 浏览器
driver = webdriver.Edge()
# 访问网页
driver.get("https://example.com")
# 等待最多 10 秒,直到元素可见
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "someElement"))
)
# 进行操作
element.click()
# 关闭浏览器
driver.quit()
WebDriverWait(driver, 10).until()
只会等待指定元素,不会影响其他查找操作。expected_conditions
(简称EC
)提供了很多等待条件,例如:
EC.presence_of_element_located()
:元素存在(但可能不可见)。EC.visibility_of_element_located()
:元素可见。EC.element_to_be_clickable()
:元素可点击。
3. 强制等待 & Fluent Wait(流畅等待)
time.sleep()
(强制等待,不推荐)
使用 time.sleep()
让程序无条件等待,但它不够智能,会浪费时间。
import time
# 强制等待 5 秒
time.sleep(5)
time.sleep()
会无论元素是否出现都等待完整的时间,容易影响效率。- 不推荐在 Selenium 自动化测试中使用,除非是调试代码。
Fluent Wait(流畅等待)
Fluent Wait 允许设置轮询间隔,并在超时前不断尝试查找元素。
适用于元素加载速度不稳定的情况。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 等待最多 10 秒,每隔 0.5 秒检查一次
wait = WebDriverWait(driver, 10, poll_frequency=0.5)
element = wait.until(
EC.presence_of_element_located((By.ID, "someElement"))
)
poll_frequency=0.5
代表 每 0.5 秒检查一次,直到超时。- Fluent Wait 适用于需要轮询检查的情况。
完全结论!
- 一般推荐使用 显式等待(Explicit Wait),因为它更精准、灵活。
- 隐式等待 适用于整个 WebDriver,但可能导致等待时间过长或冲突。
- 流畅等待(Fluent Wait) 适用于元素加载时间不确定的情况。
time.sleep()
强制等待 仅在调试或临时测试时使用,不建议在正式代码中使用。
既然如此,就来扩展讲讲显示等待
常见等待条件
元素是否存在(presence_of_element_located)
等待元素 出现在 DOM(HTML 结构)中,但不一定可见。
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(
EC.presence_of_element_located((By.ID, "someElement"))
)
- 适用于后台加载元素(如 AJAX 请求加载的内容)。
- 适用于检查是否有该元素,即使它是
display: none
也会被认为存在。
元素是否可见(visibility_of_element_located)
等待元素 出现在 DOM 中,并且可见(即 display != none
、visibility != hidden
)。
element = wait.until(
EC.visibility_of_element_located((By.ID, "someElement"))
)
- 需要确保元素可见(用户可以看到),适用于点击、输入等操作。
区别:
presence_of_element_located
仅检查是否存在,不关心是否可见。visibility_of_element_located
额外检查是否可见。
元素是否可点击(element_to_be_clickable)
等待元素 可见并且可点击(即 visibility_of_element_located
+ enabled = True
)。
element = wait.until(
EC.element_to_be_clickable((By.ID, "someButton"))
)
element.click()
- 适用于 按钮、链接等可交互元素。
- 确保不会因为元素被遮挡或未加载完成导致
element.click()
失败。
元素是否不可见(invisibility_of_element_located)
等待元素消失(即 display: none
或 DOM 中不存在
)。
wait.until(
EC.invisibility_of_element_located((By.ID, "loadingSpinner"))
)
- 适用于等待 加载动画(Loading Spinner) 消失后,再继续执行操作。
元素内文本是否更新(text_to_be_present_in_element)
等待某个元素的文本等于或包含特定内容。
wait.until(
EC.text_to_be_present_in_element((By.ID, "status"), "已完成")
)
- 适用于页面加载完成后,文字发生变化的情况,比如 "处理中" 变成 "已完成"。
检查多个元素是否存在(presence_of_all_elements_located)
等待多个元素都出现在 DOM 中。
elements = wait.until(
EC.presence_of_all_elements_located((By.CLASS_NAME, "item"))
)
- 适用于批量加载的列表元素,比如产品列表、评论列表等。
切换到新窗口(new_window_is_opened)
等待新窗口打开。
wait.until(EC.new_window_is_opened)
driver.switch_to.window(driver.window_handles[-1])
- 适用于点击某个链接后,会打开 新窗口/新标签页。
切换到 alert 弹窗(alert_is_present)
等待 alert
弹窗出现。
alert = wait.until(EC.alert_is_present())
alert.accept() # 关闭弹窗
- 适用于处理 JavaScript
alert()
弹窗,或者浏览器的确认框(如删除确认)。
综合示例
等待一个元素可见,并且文本内容变为“已加载完成”,然后点击它:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 打开浏览器
driver = webdriver.Edge()
driver.get("https://example.com")
wait = WebDriverWait(driver, 10)
# 1. 等待按钮可见并可点击
button = wait.until(EC.element_to_be_clickable((By.ID, "confirmButton")))
# 2. 等待文本变为 "已加载完成"
wait.until(EC.text_to_be_present_in_element((By.ID, "statusText"), "已加载完成"))
# 3. 点击按钮
button.click()
# 关闭浏览器
driver.quit()
- 推荐使用
WebDriverWait + expected_conditions
,避免time.sleep()
造成等待时间过长。- 使用
element_to_be_clickable
代替presence_of_element_located
,确保元素可以操作。- 结合多个等待条件,比如:
wait.until(EC.visibility_of_element_located((By.ID, "someElement"))) wait.until(EC.text_to_be_present_in_element((By.ID, "someElement"), "目标文本"))