使用WebDriverWait替换time.sleep后出现StaleElementReferenceException如何解决
错误原因
selenium.common.exceptions.StaleElementReferenceException本质是提前获取的WebElement对象对应的DOM节点,已经被页面刷新更新/删除,和当前页面的DOM树解绑,无法再访问其属性。
你的场景中触发该错误的核心逻辑是:点击「加载更多」按钮后,仅判断了按钮可点击就立刻执行元素查找,此时页面还在异步加载新的赛事卡片数据,原有DOM节点会被替换,你提前查找到的ATeams列表里的部分元素还是旧DOM的引用,遍历的时候旧DOM已经被销毁,就抛出了该错误。之前使用time.sleep时因为硬等待的时间足够让页面加载完全,所以不会触发问题。
解决方案
以下三种方案可按需选择:
- 方案1:点击加载更多后增加等待逻辑,确认页面加载完成再查找元素
你可以等待加载状态消失、或者赛事卡片数量稳定后再执行元素查找,修改原有代码片段如下:
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC PATH = 'C:\Program Files (x86)\Chromedriver.exe' driver = webdriver.Chrome(PATH) driver.get(URL) WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.ID, 'accept-cookie-consent'))) driver.find_element(By.ID, 'accept-cookie-consent').click() WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.CLASS_NAME, 'content-loader__load-more-link'))) driver.find_element(By.CLASS_NAME, 'content-loader__load-more-link').click() # 新增:等待页面加载完成,所有球队元素渲染完毕 WebDriverWait(driver, 10).until( lambda d: "loading" not in d.find_element(By.CLASS_NAME, 'content-loader__load-more-link').get_attribute("class") and len(d.find_elements(By.CLASS_NAME, 'event-card__body__name__home')) > 0 ) # 再查找球队并生成列表 HTeams = driver.find_elements(By.CLASS_NAME, 'event-card__body__name__home') ATeams = driver.find_elements(By.CLASS_NAME, 'event-card__body__name__away') MatchList = Matchmaker1(HTeams, ATeams, 'Toto', League)
- 方案2:遍历元素时添加异常捕获重试逻辑
如果页面会不定时刷新DOM,可以在遍历获取属性时增加重试,避免单次失效:
from selenium.common.exceptions import StaleElementReferenceException import time from selenium.webdriver.common.by import By ATeamListUncorrected = [] for idx in range(len(ATeams)): for retry in range(3): # 最多重试3次 try: # 每次重新定位元素,避免缓存过期 current_ateam = driver.find_elements(By.CLASS_NAME, 'event-card__body__name__away')[idx] ATeamListUncorrected.append(current_ateam.get_attribute('textContent')) break except StaleElementReferenceException: time.sleep(0.3) if retry == 2: raise # 重试3次都失败再抛出异常
- 方案3:直接拉取当前页面完整DOM后解析数据
如果不需要后续交互操作,可以把当前页面的HTML源码拉下来,用BeautifulSoup等解析库提取球队名称,完全避开Selenium元素过期的问题。
内容的提问来源于stack exchange,提问作者AxelotlZ
相关产品推荐
相关产品推荐

