Python + Selenium 报错 StaleElementReferenceException 解决方法

>>StaleElementReferenceException

  • 当引用的元素对象 ”过时“ 时抛出(页面刷新,窗口(标签页)切换,网址切换,当前页面下的”下一集“或”下一页“等操作都有可能引发对象过时错误)

  • ”过时“意味着之前你通过css ,xpath等方法定位的元素,暂未出现在当前DOM上,重新定位元素是解决方案之一

  • 原文解释:

Possible causes of StaleElementReferenceException include, but not
limited to:
You are no longer on the same page, or the page may have
refreshed since the element was located. The element may have been
removed and re-added to the screen, since it was located. Such as an
element being relocated. This can happen typically with a javascript
framework when values are updated and the node is rebuilt. Element may
have been inside an iframe or another context which was refreshed.

>>问题描述

  • 我在做一个模拟登陆+自动播放视频的脚本时,遇到了这个错误。具体原因就是一集进度结束后,点击播放下一集,页面没有跳转,没有出现新的窗口,网页链接没有改变,但页面元素重定向。导致find 方法 或者click 交互等操作报错。

>>解决方案

1. 引入等待步骤
  • 不管是显式、隐式、全局等待还是其他间隔性操作,达到元素对象刷新完毕后再交互的目的即可。
  • -举个栗子:
# 调出隐藏元素
donSee = WebDriverWait(self.api, 5, ).until(
    EC.presence_of_element_located((
    By.XPATH, "//div[@class='videoArea']" )))
onPear = self.api.find_element_by_xpath(
		"//span[@id='lessonOrder']")
self.action.move_to_element(onPear).pause(1). \
    move_to_element(donSee).pause(0.5)

# 倍速盒-->调整倍速
box = WebDriverWait(self.api, 6, ).until(
    EC.presence_of_element_located((
    By.XPATH, "//div[@class='speedBox']")))
rate = WebDriverWait(self.api, 6, ).until(
    EC.presence_of_element_located((
    By.XPATH, "//div[@class='speedBox']/div/div[@rate='1.5']")))
self.action.move_to_element(box).click().perform()
self.action.double_click(rate).perform()

2.页面元素重定向。
  • 如果使用Action模拟键鼠则需要释放当前元素,重新定位元素。
  • 举个例子:
def MediaPanel(self) :
    """
    一个高度封装的自动脚本的模块
    :return: 
    """
        try:
            self.MonitorProgress()  
            # 监听进度
            nex = self.api.find_element_by_xpath(
                "//div[@class='controlsBar']//div[@id='nextBtn']")
            # 本集播放结束,预备下一集工作
            self.action.move_to_element(onPear).pause(1). \
                move_to_element(donSee).pause(0.5).\
                click(nex).perform()
    		#模拟操作呼出隐藏面板,点击“下一集”按钮
        except StaleElementReferenceException:
        #当元素”过时“,执行以下操作
            self.action.reset_actions()
            # 关键语法-更新dom树-元素重定向
        finally:
            self.AudioPanel()
            #递归调用;重新定位元素
>>其他
>>Selenium 中其他类型错误
  • Selenium常见报错汇总(转译自官方API文档)
# 详解 `StaleElementReferenceException` 表示尝试操作一个**已经失效的页面元素引用**。这通常发生在元素被定位后,页面发生了刷新、AJAX 更新、导航或 DOM 重新渲染,导致原始元素不再存在于当前页面中。 要解决该问题,核心思路是:**避免使用过期的元素引用,重新获取元素**。 --- ### ✅ 解决方案如下: #### 1. **重新查找元素(推荐做法)** 在操作元素前,每次都重新查找元素,避免使用之前存储的变量。 ```python from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 正确方式:每次操作都重新定位 wait = WebDriverWait(driver, 10) element = wait.until(EC.element_to_be_clickable(loc_pro_name)) element.click() ``` 如果需要多次操作,可在每次操作前重新定位。 --- #### 2. **加入重试机制(适用于频繁变动的页面)** 使用 `try-except` 捕获异常并重试: ```python from selenium.common.exceptions import StaleElementReferenceException import time def click_with_retry(driver, locator, max_retries=3): for i in range(max_retries): try: element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable(locator) ) element.click() return True except StaleElementReferenceException: print(f"元素过期,正在重试... ({i+1}/{max_retries})") time.sleep(1) raise Exception("多次重试失败") # 调用 click_with_retry(driver, loc_pro_name) ``` --- #### 3. **确保页面稳定后再操作** 避免在页面加载未完成、动画未结束或 AJAX 请求进行中时进行点击操作。 可以等待关键元素出现或某些条件满足后再继续。 ```python # 等待某个容器加载完毕 WebDriverWait(driver, 10).until(lambda d: d.find_element(*loc_pro_name).is_displayed()) ``` --- #### 4. **避免保存 WebElement 变量太久** 不要将 `find_element()` 结果长期保存为变量,尤其是在页面可能发生变更的操作之间。 ❌ 错误示例: ```python elem = driver.find_element(*loc) # 定位后很久才点击 time.sleep(3) elem.click() # 可能抛出 StaleElementReferenceException ``` ✅ 正确做法: ```python # 接近点击时再定位 elem = driver.find_element(*loc) elem.click() ``` --- # 知识点(列出解答该问题需要的知识点) - **Selenium 元素生命周期管理**:元素引用依赖于 DOM 存在,DOM 更新后需重新获取。 - **StaleElementReferenceException 触发机制**:元素曾存在但已被移除或替换,引用失效。 - **显式等待与异常重试策略**:结合 `WebDriverWait` 与重试逻辑提升脚本健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值