使用Selenium爬取总统候选人信息时遇StaleElementReferenceException错误求解
解决Selenium爬取2024总统候选人信息时的StaleElementReferenceException错误
错误原因
你遇到的StaleElementReferenceException是因为:当你在循环里调用parse_profile函数跳转到候选人个人主页后,初始页面的DOM已经被销毁,之前获取的elems列表里的元素全部失效,循环到下一个元素时就会报错。
修复方案
核心思路是先把所有候选人的姓名和主页URL从初始页面一次性提取出来,存储到本地列表,再遍历这个列表去访问每个候选人的主页,这样就不会依赖已经失效的DOM元素了。同时加入显式等待,避免页面未加载完成就查找元素。
修改后的完整代码
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException driver = webdriver.Chrome() pres_candidates_url = "https://ballotpedia.org/Presidential_candidates,_2024" driver.get(pres_candidates_url) def parse_profile(profile_url): driver.get(profile_url) wait = WebDriverWait(driver, 10) party = "Unknown" official_image = "No image found" # 获取党派信息,加入等待 try: party_elem = wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='widget-row value-only white']//a"))) party = party_elem.text except (TimeoutException, NoSuchElementException): print(f"无法获取{profile_url}的党派信息") # 获取图片链接,优先找widget里的图片,再找正文里的 try: image_elem = wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='widget-row']//img"))) official_image = image_elem.get_attribute("src") except (TimeoutException, NoSuchElementException): try: image_elem = wait.until(EC.presence_of_element_located((By.XPATH, "//div[@class='mw-parser-output']//p//img"))) official_image = image_elem.get_attribute("src") except (TimeoutException, NoSuchElementException): print(f"无法获取{profile_url}的图片链接") metadata = {"Party": party} return official_image, metadata # 先一次性提取所有候选人的姓名和URL,存储到列表 candidates = [] try: wait = WebDriverWait(driver, 10) elems = wait.until(EC.presence_of_all_elements_located((By.XPATH, "//div[@class='mw-parser-output']//ul//li//b//a"))) for elem in elems: words = elem.text.split() count = sum(1 for word in words if word[0].islower()) if count < 1: name = elem.text member_url = elem.get_attribute("href") candidates.append({"name": name, "url": member_url}) except TimeoutException: print("无法加载初始页面的候选人列表") # 遍历预存的候选人列表,爬取详细信息 all_members = [] for candidate in candidates: name = candidate["name"] member_url = candidate["url"] print(f"正在处理: {name} - {member_url}") official_image, metadata = parse_profile(member_url) member = { "name": name, "url": member_url, "official_image": official_image, "metadata": metadata } all_members.append(member) print(f"完成处理: {name}") print("\n爬取结果:") for member in all_members: print(member) driver.quit()
关键修改说明
- 预存候选人信息:先从初始页面把所有需要的姓名和URL提取到本地列表,之后循环只操作这个列表,彻底避免了页面跳转后元素失效的问题。
- 加入显式等待:使用
WebDriverWait配合expected_conditions,确保元素加载完成后再进行操作,减少因页面加载慢导致的查找失败。 - 增强异常处理:给每个元素查找都添加了异常捕获,避免单个候选人的信息爬取失败导致整个程序崩溃。
- 优化变量命名:把原代码里的
metadata键名从Party:改成Party,更符合常规字典键的命名规范。
内容的提问来源于stack exchange,提问作者Noey
相关产品推荐
相关产品推荐

