核心概念
-
WebDriverWait.until() 的本質
python傳入的是函數對象(函數地址),不是函數調用結果
wait.until(函數對象) # ✅ 正確:傳入函數本身
wait.until(函數調用()) # ❌ 錯誤:傳入函數返回值 -
返回值類型
返回值取決於傳入的條件函數返回什麼,常見的有:
● WebElement 對象(最常見)
● Boolean 值
● List[WebElement] 列表
● 其他任何類型
🔄 工作原理
內部執行流程
python偽代碼展示 wait.until() 內部邏輯
def until(self, method):
for _ in range(重試次數):try: # 關鍵:調用傳入的函數,並傳遞 driver result = method(self._driver) if result: # 非 False/None return result except 允許的異常: pass sleep(輪詢間隔)raise TimeoutException()
🛠️ 兩種使用方式
方式一:使用 EC 模塊(95% 場景)
python
from selenium.webdriver.support import expected_conditions as EC
簡潔、可讀性高
element = wait.until(EC.presence_of_element_located((By.ID, "id")))
element = wait.until(EC.element_to_be_clickable((By.CSS, ".btn")))
element = wait.until(EC.visibility_of_element_located((By.NAME, "name")))
方式二:自定義函數(5% 複雜場景)
python
def 自定義條件(driver):
# 複雜業務邏輯
if 條件1 and 條件2:
return element
return False
result = wait.until(自定義條件)
🔗 閉包機制
EC 模塊的閉包本質
python
EC 函數實際上是閉包工廠
def presence_of_element_located(locator):
def _predicate(driver): # 閉包函數
return driver.find_element(*locator) # 使用外部的 locator
return _predicate # 返回閉包
使用過程:
閉包 = EC.presence_of_element_located((By.ID, "test"))
元素 = wait.until(閉包) # wait 內部調用閉包並傳入 driver
自定義閉包示例
python
def 創建文本檢查器(元素ID, 期望文本):
def 檢查函數(driver): # 閉包
element = driver.find_element(By.ID, 元素ID)
return element if element.text == 期望文本 else False
return 檢查函數 # 返回配置好的閉包
檢查器 = 創建文本檢查器("status", "完成")
結果 = wait.until(檢查器)
💡 關鍵要點
-
driver 的生命週期
pythondriver 必須在 wait 之前創建
driver = webdriver.Chrome() # 1. 創建驅動
wait = WebDriverWait(driver, 10) # 2. 創建等待器
元素 = wait.until(條件函數) # 3. 使用等待 - 參數傳遞機制
● WebDriverWait 創建時保存 driver 引用
● until() 調用時自動將 driver 傳遞給條件函數
● 條件函數的第一個參數接收這個 driver - 異常處理
python
from selenium.common.exceptions import TimeoutException
try:
element = wait.until(條件函數)
except TimeoutException:
print("等待超時,元素未找到")
📊 使用建議
場景 推薦方案 示例
簡單元素等待 EC 內置條件 EC.presence_of_element_located()
複雜業務邏輯 自定義函數 多條件組合判斷
可複用條件 閉包工廠 創建帶參數的等待條件
簡單一次性 lambda lambda d: d.find_element(...).text == "x"
🎯 最佳實踐
python
完整示例
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
class PageObject:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def 安全操作(self):
# 使用 EC 等待
按鈕 = self.wait.until(
EC.element_to_be_clickable((By.ID, "submit"))
)
按鈕.click()
# 自定義複雜等待
def 加載完成(driver):
return "完成" in driver.find_element(By.ID, "status").text
self.wait.until(加載完成)
總結
核心一句話:wait.until() 接受一個函數對象,WebDriverWait 會反覆調用這個函數直到它返回非 False 值或超時。EC 模塊提供了常用條件的閉包工廠,自定義函數處理複雜邏輯。