You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Selenium遍历绑定JS函数的锚点遇StaleElementReferenceException求解

Selenium遍历分页锚点时的StaleElementReferenceException问题

问题背景

使用Python的Selenium做网页爬虫,已抓取到一组分页锚点,需要遍历点击每个锚点,跳转页面后提取数据,再处理下一个锚点。

锚点示例

<a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$GridView1','Page$2')">2</a>
<a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$GridView1','Page$3')">3</a>

当前代码逻辑

通过XPath获取所有锚点:

anchors = d.find_elements(By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr/td/table/tbody/tr/td/a')

遍历点击时触发错误:

i = 0
for a in anchors:
    anchors[i].click()
    # 提取页面数据的代码
    i += 1

错误信息

selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: stale element not found

已确认分页表格及锚点结构未变,XPath也保持一致,尝试过多种方案仍未解决。


解决方案

核心原因

点击锚点后,页面发生DOM重渲染(即使视觉上分页栏无变化),之前获取的anchors列表中的元素引用会失效,从而触发stale错误。

方案1:每次循环重新定位锚点

不要一次性获取所有锚点,先获取总页数,再在循环中每次重新定位当前页码的锚点:

注意:需提前导入显式等待依赖模块:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 获取总页数(假设锚点文本为页码,取最后一个锚点的文本转数字)
total_pages = int(d.find_element(By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr/td/table/tbody/tr/td/a[last()]').text)

for page in range(2, total_pages + 1):
    # 每次循环重新定位当前页码的锚点
    current_anchor = d.find_element(By.XPATH, f'//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr/td/table/tbody/tr/td/a[text()="{page}"]')
    current_anchor.click()
    
    # 等待页面加载完成(根据页面实际加载逻辑调整等待条件)
    WebDriverWait(d, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]')))
    
    # 提取页面数据的代码
    # ...

方案2:直接执行锚点的JavaScript逻辑

观察到锚点的href是__doPostBack函数调用,可以直接通过Selenium执行该JavaScript,避免元素定位失效问题:

# 先提取所有锚点的JavaScript执行命令
anchors = d.find_elements(By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr/td/table/tbody/tr/td/a')
postback_commands = [a.get_attribute('href').replace('javascript:', '') for a in anchors]

for cmd in postback_commands:
    # 直接执行JavaScript完成分页跳转
    d.execute_script(cmd)
    
    # 等待页面加载完成
    WebDriverWait(d, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]')))
    
    # 提取页面数据的代码
    # ...

方案3:添加重试机制捕获Stale错误

如果需要保留遍历逻辑,可以添加重试机制,捕获stale错误后重新获取元素:

from selenium.common.exceptions import StaleElementReferenceException

# 先获取锚点总数
anchor_count = len(d.find_elements(By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr/td/table/tbody/tr/td/a'))

for i in range(anchor_count):
    attempts = 0
    while attempts < 3:
        try:
            # 每次重试时重新获取锚点列表
            anchor = d.find_elements(By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]/tbody/tr/td/table/tbody/tr/td/a')[i]
            anchor.click()
            break
        except StaleElementReferenceException:
            attempts += 1
    
    # 等待页面加载完成
    WebDriverWait(d, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="ContentPlaceHolder1_GridView1"]')))
    
    # 提取页面数据的代码
    # ...

内容的提问来源于stack exchange,提问作者Tyler Schnerch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:26:29