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

Selenium元素失效报错:免费食品查找脚本求助

解决Selenium中的StaleElementReferenceException问题(外卖平台免费食品爬取脚本)

问题根源

你碰到的StaleElementReferenceException,本质是循环中切换页面后,原餐厅列表页的元素引用失效了。当你打开新标签页访问餐厅详情、再关闭返回列表页时,原页面DOM可能已重新渲染,之前获取的all_restaurant元素不再附着于当前页面文档,后续循环调用get_attribute自然报错。

修复方案

核心思路是提前提取所有餐厅的关键信息到本地列表,再遍历本地数据访问详情页,彻底摆脱对原页面元素的依赖。

1. 预提取餐厅信息,重构循环逻辑

先在列表页一次性抓取所有餐厅的链接和名称,保存到本地列表,之后循环这个列表操作:

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By

url = 'https://www.rappi.com.ar/restaurantes'
driver.get(url)

# 提前提取所有餐厅的链接、名称到本地列表
restaurant_links = []
restaurant_names = []
all_restaurant = driver.find_elements(By.CLASS_NAME, 'hbaEIe.sc-5674cfe4-2')
for restaurant in all_restaurant:
    link = restaurant.get_attribute("href")
    name = restaurant.get_attribute("aria-label")
    restaurant_links.append(link)
    restaurant_names.append(name)

# 遍历本地列表,不再依赖原页面元素
base_url = "https://www.rappi.com.ar"  # 根据实际情况调整,确保full_link有效
for idx in range(len(restaurant_links)):
    link = restaurant_links[idx]
    full_link = base_url + link if not link.startswith("http") else link
    name = restaurant_names[idx]

    # 打开新标签页并切换到该标签页
    driver.execute_script("window.open('');")
    driver.switch_to.window(driver.window_handles[-1])

    # 加载餐厅详情页
    driver.get(full_link)

    getFreeStuff(name, full_link)

    # 关闭当前标签页,切回原列表页
    driver.close()
    driver.switch_to.window(driver.window_handles[0])

    print(name)

2. 修复getFreeStuff函数的逻辑错误

原函数存在两个明显问题:获取的是元素对象而非文本内容、未确保全局列表初始化,修改后如下:

# 提前初始化结果存储列表
restaurants = []
links = []
products = []

def getFreeStuff(restaurant_name, restaurant_link):
    time.sleep(1)  # 建议后续替换为显式等待,提升稳定性
    prices = driver.find_elements(By.CLASS_NAME, "css-kowr8")
    names = driver.find_elements(By.CLASS_NAME, "css-puxjan")
    
    # 用zip同时遍历价格和元素,避免索引越界
    for price_elem, name_elem in zip(prices, names):
        price_text = price_elem.text.strip()
        if price_text == "$ 0,00":
            restaurants.append(restaurant_name)
            links.append(restaurant_link)
            products.append(name_elem.text.strip())
    return 0

3. 进阶优化:用显式等待替代固定sleep

固定time.sleep稳定性差,页面加载慢时会出错,建议替换为Selenium显式等待:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def getFreeStuff(restaurant_name, restaurant_link):
    # 等待价格元素加载完成,最多等待5秒
    WebDriverWait(driver, 5).until(
        EC.presence_of_all_elements_located((By.CLASS_NAME, "css-kowr8"))
    )
    
    prices = driver.find_elements(By.CLASS_NAME, "css-kowr8")
    names = driver.find_elements(By.CLASS_NAME, "css-puxjan")
    
    for price_elem, name_elem in zip(prices, names):
        price_text = price_elem.text.strip()
        if price_text == "$ 0,00":
            restaurants.append(restaurant_name)
            links.append(restaurant_link)
            products.append(name_elem.text.strip())
    return 0

关键注意事项

  • 切换标签页后必须调用driver.switch_to.window切换上下文,否则操作会在原标签页执行,直接破坏列表页DOM
  • 关闭详情页标签后,务必切回原列表页,保证后续循环的页面环境正确
  • 永远避免长时间持有原页面的WebElement对象,优先提取文本、链接等数据到本地变量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:25:18