设置超时时间与等待策略
Selenium 稳定性的 核心专题:80% 的"偶发失败"都来自等待问题。搞清楚三层超时配置 + 三种等待方式的区别,是从入门到熟练的分水岭。
三层超时配置:
driver.set_page_load_timeout(30) → 整个页面 load 事件最多等 30s,超时抛 TimeoutExceptiondriver.set_script_timeout(10) → JS 脚本执行最多等 10s(execute_script/execute_async_script)driver.implicitly_wait(5) → 全局生效,所有 find_element 最多等 5s三种等待对比:
time.sleep(t) → 强制睡 t 秒,不管元素出没出现,不推荐(不稳定且慢)implicitly_wait(t) → 全局隐式等待,元素出现立即返回。陷阱:和显式混用时,显式等待的超时会被隐式等待"加长"WebDriverWait(driver, t).until(EC.presence_of(...)) → 显式等待,每个场景单独设超时 + 轮询条件,最灵活最可控💡 最佳实践:默认只设一个较短的 implicitly_wait(1),复杂场景用 WebDriverWait 显式等待。永远不要混用长隐式 + 短显式!
from selenium.webdriver.common.timeouts import Timeoutsdriver.timeouts = Timeouts(implicit_wait=3, page_load=30, script=10)print(driver.timeouts.page_load) → 返回当前 page_load 值
driver.execute_script("window.stop()")
driver.save_screenshot("timeout.png")
page_load_timeout 管页面加载,
script_timeout 管 execute_script,
implicitly_wait 管 find_element。
set_page_load_timeout() 就会一直用页面加载超时初始值 300s(太长,正常页面加载用不了这么久)
driver.execute_script("window.stop()") → 重试/跳过/截图留证每隔 N 毫秒问一次"条件满足了吗?" → 满足就返回,超时就报错。
time.sleep 傻等不管页面 → 推荐用 WebDriverWait 精准等条件。
time.sleep 代替 —— 机器快白等、慢就崩,CI/CD 上尤其不稳定clickable > visibility > presence# ① 启动浏览器 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.Chrome() # ② 三类超时设置(单位:秒) driver.set_page_load_timeout(30) # 页面导航加载最多等 30s driver.set_script_timeout(10) # execute_script 最多等 10s driver.implicitly_wait(1) # find_element 兜底轮询最多 1s driver.get("https://autotest-505.pages.dev/browser_op_tech_sections/timeout_wait_tech.html") # ③ JS 注入:execute_script 受 set_script_timeout(10) 保护,脚本卡住最多抛超时异常 ready_state = driver.execute_script("return document.readyState") print("页面加载状态:", ready_state) # complete # 注入 JS 直接读取元素文本(不经过 Selenium 定位器) card_text = driver.execute_script("return document.getElementById('mockCard1').innerText;") print("卡片内容:", card_text) # ④ 普通定位:find_element 受 implicitly_wait(1) 保护,元素没立即出现时兜底轮询最多 1s sleep_btn = driver.find_element(By.ID, "waitBtnSleep") print("定位到按钮:", sleep_btn.text) # ⑤ 显式等待(推荐):每 0.5s 轮询一次,最长等 10s wait = WebDriverWait(driver, 10, poll_frequency=0.5) # 等按钮可点击后再点击(id 与本演示页“显式等待”按钮一致) btn = wait.until(EC.element_to_be_clickable((By.ID, "waitBtnExp"))) btn.click() # 等异步加载的卡片变为可见(id 与本演示页动态元素一致) wait.until(EC.visibility_of_element_located((By.ID, "mockCard1"))) # ⑥ 结束会话 driver.quit()
| 因素 | 本地 | CI/CD 云服务器 |
| 网络 | 专线稳定 | 数据中心共享,偶发抖动 |
| CPU | 独占 | 多租户,可能被抢占 |
| 浏览器缓存 | 有 | 没有(每次全新启动) |
| 页面加载速度 | 有缓存,秒出 | 全量下载,慢 2~5 倍 |
| 并发任务 | 只跑你这一份 | 可能几十上百个同时抢资源 |
"A session has an associated session implicit wait timeout that specifies a time to wait for the implicit element location strategy"implicit=0.5s → 驱动最多等待 500ms 后必须放弃
→ 驱动在一次 findElement / findElements 调用中,最多愿意等待的总时间即为该值,不得超时。
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
def test_polling(d, delay):
d.implicitly_wait(2)
d.get('about:blank')
d.execute_script(f"setTimeout(()=>{{document.body.innerHTML='t'}},{delay})")
t0 = time.perf_counter()
try:
cost = (time.perf_counter() - t0) * 1000
print(f"delay={delay:4d} 耗时={cost:6.0f} 差值={cost-delay:+5.0f}")
except: print(f"delay={delay} 超时")
driver = webdriver.Chrome()
for delay in range(10, 1550, 50): # 50ms 步进,覆盖 10~1500ms
test_polling(driver, delay)
driver.quit()
最坏 = implicit × (explicit超时 / pollFreq)try: find_element ... except NoSuchElementException:| 值 | 兜底窗口 (规范定义) |
叠加成本 explicit=15s |
白等 10次不存在 |
依据类型 | 推荐 |
| 不设(=0) | 0ms | 0 秒 | 0 秒 | 规范 | 最严谨 |
| 1s | 1000ms | 30 秒 | 10 秒 | 经验+权衡 | 默认推荐 |
| 0.5s | 500ms | 15 秒 | 5 秒 | 经验+权衡 | 确认页面 <500ms |
| 2s | 2000ms | 60 秒 | 20 秒 | 代价太大 | 谨慎 |
| ≥5s | ≥5000ms | 150 秒+ | 50 秒+ | 爆炸 | ❌ 绝对避免 |