在 Selenium 脚本中,等待是一个核心问题。不加等待可能会遇到:
NoSuchElementException
ElementNotInteractableException
StaleElementReferenceException
这是因为页面元素未加载完就被访问。本文介绍 Selenium 中的三种等待机制:强制等待、隐式等待、显式等待,及其最佳使用场景。
🧨 等待问题示例
driver.get("https://example.com")
driver.find_element(By.ID, "submit").click() # 页面还没加载好就执行,容易失败
🕐 一、强制等待(sleep)
import time
time.sleep(3) # 暂停 3 秒
📌 特点:
- 简单粗暴,无论页面是否加载完成都会等待固定时间
- 会拖慢测试效率
- 不推荐长期使用,只适用于调试或短暂缓冲
🧩 二、隐式等待(implicit wait)
driver.implicitly_wait(10)
📌 特点:
- 设置一次,对整个 WebDriver 实例全局生效
- 找不到元素时会等待最多 N 秒,直到找到或超时
- 不适用于需要等待某些特定状态(如元素可点击)
🔁 示例:
driver.implicitly_wait(5)
driver.find_element(By.ID, "username").send_keys("admin")
🔍 三、显式等待(WebDriverWait)
显式等待是最推荐、最灵活的等待方式。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "submit"))
)
📌 支持多种条件判断:
presence_of_element_located
(元素存在于 DOM 中)visibility_of_element_located
(元素可见)element_to_be_clickable
(元素可见且可点击)text_to_be_present_in_element
(某元素中包含指定文本)
✅ 示例:等待元素可点击
from selenium.webdriver.common.by import By
btn = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "login-button"))
)
btn.click()
🧼 三者对比总结
类型 | 是否推荐 | 使用方式 | 优点 | 缺点 |
---|---|---|---|---|
强制等待 | ❌ 不推荐 | time.sleep(x) |
简单 | 阻塞时间固定,效率低 |
隐式等待 | ⚠️ 一般 | driver.implicitly_wait(x) |
设置简单,全局生效 | 精度差,容易被覆盖 |
显式等待 | ✅ 推荐 | WebDriverWait + EC.xxx |
灵活、可组合判断 | 需手动写逻辑 |
🔥 实战建议
- 尽量使用 显式等待,针对具体页面行为进行条件判断
- 隐式等待和显式等待不要混用,可能产生冲突
- 尽量避免使用
sleep()
,除非确实无法判断加载状态
💬 常用显式等待条件(EC)
EC.presence_of_element_located
EC.visibility_of_element_located
EC.element_to_be_clickable
EC.invisibility_of_element_located
EC.text_to_be_present_in_element
文档参考:selenium.webdriver.support.expected_conditions
📌 延伸阅读:
- 如何封装自定义等待工具类
- 如何处理 AJAX 加载页面的动态等待
- Selenium 和 Playwright 中等待机制对比