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

Python使用Selenium爬取下拉表格出现StaleElementException问题

问题原因

你遇到的是Selenium常见的StaleElementReferenceException(元素未附加到文档异常),触发的核心原因有两个:

  • 你在循环开始前提前缓存了下拉框的options集合,点击提交按钮触发页面刷新后,之前缓存的所有DOM元素引用全部失效,下一轮循环调用旧引用就会触发报错
  • 页面刷新后,之前选中的单选按钮、下拉框选中状态全部重置,你没有重新定位选中就直接循环旧的option引用,进一步加剧了元素失效问题
修复方案

核心调整逻辑

  1. 不要提前缓存任何下拉框、选项集合,每次进入对应层级循环前,重新定位对应的页面元素
  2. 替换所有固定time.sleep为显式等待,增加页面刷新完成校验,确保上一次提交后的页面刷新完全结束后,再执行下一轮定位操作
  3. 最外层加循环重置状态:每次提交页面刷新后,重新选中「PANCHAYAT SAMITY」单选按钮,再执行后续下拉框选择逻辑

修复后代码

###Purpose: To retrieve gp election data 
import time
from selenium import webdriver
from selenium.webdriver.support.ui import Select
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(executable_path = '/usr/local/bin/chromedriver')
driver.get('http://wbsec.gov.in/results/panchayat_election_detailed_result?election_year=2013')
driver.maximize_window()
wait = WebDriverWait(driver, 10)

# 先获取区县总数,避免每次刷新重复获取
# 首次定位单选按钮并点击
wait.until(EC.element_to_be_clickable((By.XPATH, "//input[@value='PANCHAYAT SAMITY']"))).click()
# 首次获取区县总数
districts_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'zilla_parishad'))))
district_count = len(districts_select.options)

# 遍历区县
for district_idx in range(district_count):
    # 每次进入区县循环,先重置单选按钮状态
    wait.until(EC.element_to_be_clickable((By.XPATH, "//input[@value='PANCHAYAT SAMITY']"))).click()
    # 重新获取区县下拉框,选择对应索引的区县
    districts_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'zilla_parishad'))))
    district = districts_select.options[district_idx]
    district.click()
    
    # 获取当前区县下的块总数
    blocks_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'panchayat_samity'))))
    block_count = len(blocks_select.options)
    
    # 遍历块
    for block_idx in range(block_count):
        # 重新选区县(防止刷新后状态丢失,可根据实际情况判断是否需要省略)
        districts_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'zilla_parishad'))))
        districts_select.options[district_idx].click()
        # 重新获取块下拉框,选对应索引的块
        blocks_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'panchayat_samity'))))
        block = blocks_select.options[block_idx]
        block.click()
        
        # 获取当前块下的选举日期总数
        poles_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'election_date'))))
        pole_count = len(poles_select.options)
        
        # 遍历选举日期
        for pole_idx in range(pole_count):
            # 重新选区县、块
            districts_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'zilla_parishad'))))
            districts_select.options[district_idx].click()
            blocks_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'panchayat_samity'))))
            blocks_select.options[block_idx].click()
            # 重新获取日期下拉框,选对应索引的日期
            poles_select = Select(wait.until(EC.presence_of_element_located((By.ID, 'election_date'))))
            pole = poles_select.options[pole_idx]
            pole.click()
            
            # 定位提交按钮点击
            submit_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//input[@type='submit']")))
            submit_btn.click()
            
            # 等待页面刷新完成:判断旧的提交按钮已经失效,说明页面已经开始刷新
            wait.until(EC.staleness_of(submit_btn))
            # 等待新页面的提交按钮加载完成,说明刷新结束
            wait.until(EC.presence_of_element_located((By.XPATH, "//input[@type='submit']")))
            
            # 这里加你提取表格数据的逻辑
            # **********
补充说明

如果还是偶发报错,可以适当调大显式等待的最长时长(代码里是10秒,可根据网络情况改到15-20秒),不需要加额外的time.sleep。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:57:01