Selenium Python下拉框迭代时StaleElementReferenceException问题排查求助
Hey there, let's break down what's causing that StaleElementReferenceException and fix it up.
问题根源
The error pops up because after you click the first dropdown option, the page (including the dropdown itself) gets re-rendered. The dropdown_menu_list you grabbed at the start of the loop holds references to the original elements from the initial page state. Once the page refreshes, those old element references are no longer attached to the current DOM—hence the stale reference error.
修复思路
Instead of storing the actual WebElement objects upfront, we'll first collect all the value attributes of the dropdown options as plain strings. Then, we'll loop through these string values, and for each iteration, we'll re-locate the dropdown and the specific option we need. This way, we always use fresh element references that are tied to the current DOM state.
修改后的完整代码
from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.select import Select from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait import time # Don't forget to import time! driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) driver.delete_all_cookies() def fetch_d(driver, locator): # First, collect all option values as plain strings (no WebElements stored) dropdown_menu = WebDriverWait(driver, 10).until(EC.element_to_be_clickable(locator)) option_values = [opt.get_property("value") for opt in Select(dropdown_menu).options] counter = 0 for tmp in option_values: print("I am in counter no", counter, "\n") # Re-locate the dropdown every iteration to avoid stale references dropdown_menu = WebDriverWait(driver, 10).until(EC.element_to_be_clickable(locator)) select = Select(dropdown_menu) if counter == 0: # Skip the first option (label information) counter += 1 continue # Select the target option using its stored value select.select_by_value(tmp) print(f"Selected option: {select.first_selected_option.text}") time.sleep(3) # Wait for the table to load and grab download links locator2 = (By.CSS_SELECTOR, "#GridView1") element = WebDriverWait(driver, 10).until(EC.presence_of_element_located(locator2)) a_tags = element.find_elements(By.TAG_NAME, "a") for link in a_tags: link.click() # Trigger file download # Optional: Add a small delay here if your downloads need time to initiate time.sleep(1) counter += 1 # Method call fetch_d(driver, (By.ID, "ddlacname"))
额外优化说明
- Replaced the deprecated
element.find_elements_by_tag_namewithelement.find_elements(By.TAG_NAME, "a")to align with modern Selenium standards. - Used
EC.presence_of_element_locatedfor the table instead ofelement_to_be_clickable—we only need the table to exist, not be interactive, to grab its links. - Added a small wait after each download click to ensure the browser has time to start the download process (adjust the duration based on your site's speed).
- Made the selected option text print clearer for debugging purposes.
内容的提问来源于stack exchange,提问作者Pritam

