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

如何在Selenium遍历餐厅餐型时无需重启Driver避免失效元素错误

解决Selenium遍历餐厅餐型时无需重启浏览器的方案

需求是遍历斯坦福大学餐厅菜单页面的所有餐厅及对应餐型,控制台输出选中的餐厅和餐型,目前代码通过每次循环重启WebDriver来避免失效元素错误,但效率低下,希望找到无需重启浏览器的解决方法。

原代码

import time
import csv
from datetime import datetime
from pytz import timezone

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service 
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC 

from dining_info import *

# Setup timezones for PST to ensure continuity
pst_timezone = timezone('America/Los_Angeles')
pst_now = datetime.now(pst_timezone)

# SETUP VARIABLES FOR TEMPORARY TESTING
todays_date = pst_now.strftime('%m/%d/%Y').lstrip("0").replace("/0", "/")
meal_type = "Breakfast"
dining_hall = "Arrillaga"

# Set up Chrome options
chrome_options = webdriver.ChromeOptions()
# Uncomment the next line to run in headless mode
# chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-extensions')

# Set up WebDriver using WebDriver Manager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)

url = 'https://rdeapps.stanford.edu/dininghallmenu/'
driver.get(url)

# Wait for the date dropdown to be present
date_dropdown = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, 'MainContent_lstDay'))
)

# Retrieve currently selected date
selected_date = WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '#MainContent_lstDay option[selected="selected"]'))
).get_attribute('value')

# Convert selected date format to match today's date format
selected_date_converted = selected_date.split(' - ')[0]

print("Dates match:", selected_date_converted == todays_date)

# ------------------------------------------------------------------------------------------------- #

for hall in dining_hall_list:
    # Wait for the dining hall dropdown to be present
    dining_hall_dropdown = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, 'MainContent_lstLocations'))
    )

    # Select dining_hall from the dining hall dropdown
    Select(dining_hall_dropdown).select_by_value(hall)

    # Retrieve currently selected dining hall
            selected_dining_hall = Select(dining_hall_dropdown).first_selected_option.get_attribute('value')

    print("Selected dining hall:", dining_hall_alias[selected_dining_hall])

    for meal in meal_type_list:
    # Wait for the meal type dropdown to be present
    meal_type_dropdown = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, 'MainContent_lstMealType'))
    )

        # Select meal_type from the meal type dropdown
        Select(meal_type_dropdown).select_by_value(meal)

        # Retrieve currently selected meal type // using this method because stale element when trying method in line 61
        selected_meal_type = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#MainContent_lstMealType option[selected="selected"]'))
    ).get_attribute('value')

        print("Selected meal type:", selected_meal_type)

    # Close instance of WebDriver and reinstate to stop stale element
    driver.quit()
    time.sleep(0.5)
    driver = webdriver.Chrome(service=service, options=chrome_options)
    driver.get(url)

# ------------------------------------------------------------------------------------------------- #

# Wait for user input before closing the browser
input("Press enter to close the browser...")
driver.quit()

核心问题分析

失效元素错误(StaleElementReferenceException)的根源是:选择餐厅后页面会局部刷新,之前获取的下拉框元素引用失效。重启浏览器是极端解决方案,通过以下调整可以避免:

具体修改步骤

  • 移除循环内的WebDriver重启代码:直接删除driver.quit()、重新初始化和driver.get(url)的代码,全程复用同一个浏览器实例。
  • 修正代码缩进:原代码中selected_dining_hall和for meal循环的缩进错误,会导致语法执行异常,先统一修正缩进。
  • 优化等待条件:将EC.presence_of_element_located替换为EC.element_to_be_clickable,确保元素不仅存在还能交互,避免过早操作。
  • 选择餐厅后等待页面更新:选中餐厅后,等待餐型下拉框重新加载完成(比如等待其可交互),确保页面局部刷新完成后再操作餐型。

修改后的完整代码

import time
import csv
from datetime import datetime
from pytz import timezone

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service 
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support import expected_conditions as EC 

from dining_info import *

# Setup timezones for PST to ensure continuity
pst_timezone = timezone('America/Los_Angeles')
pst_now = datetime.now(pst_timezone)

# SETUP VARIABLES FOR TEMPORARY TESTING
todays_date = pst_now.strftime('%m/%d/%Y').lstrip("0").replace("/0", "/")
meal_type = "Breakfast"
dining_hall = "Arrillaga"

# Set up Chrome options
chrome_options = webdriver.ChromeOptions()
# Uncomment the next line to run in headless mode
# chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-extensions')

# Set up WebDriver using WebDriver Manager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)

url = 'https://rdeapps.stanford.edu/dininghallmenu/'
driver.get(url)

# Wait for the date dropdown to be clickable (更可靠的等待条件)
date_dropdown = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, 'MainContent_lstDay'))
)

# Retrieve currently selected date
selected_date = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, '#MainContent_lstDay option[selected="selected"]'))
).get_attribute('value')

# Convert selected date format to match today's date format
selected_date_converted = selected_date.split(' - ')[0]

print("Dates match:", selected_date_converted == todays_date)

# ------------------------------------------------------------------------------------------------- #

for hall in dining_hall_list:
    # 每次循环重新获取餐厅下拉框,避免引用失效
    dining_hall_dropdown = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, 'MainContent_lstLocations'))
    )

    # Select dining_hall from the dining hall dropdown
    Select(dining_hall_dropdown).select_by_value(hall)
    
    # 等待页面局部刷新完成:等待餐型下拉框可交互
    WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, 'MainContent_lstMealType'))
    )

    # Retrieve currently selected dining hall
    selected_dining_hall = Select(dining_hall_dropdown).first_selected_option.get_attribute('value')
    print("Selected dining hall:", dining_hall_alias[selected_dining_hall])

    for meal in meal_type_list:
        # 每次循环重新获取餐型下拉框
        meal_type_dropdown = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.ID, 'MainContent_lstMealType'))
        )

        # Select meal_type from the meal type dropdown
        Select(meal_type_dropdown).select_by_value(meal)

        # Retrieve currently selected meal type
        selected_meal_type = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, '#MainContent_lstMealType option[selected="selected"]'))
        ).get_attribute('value')

        print("Selected meal type:", selected_meal_type)
        # 可选:短暂等待,避免操作过快触发页面异常
        time.sleep(0.2)

# ------------------------------------------------------------------------------------------------- #

# Wait for user input before closing the browser
input("Press enter to close the browser...")
driver.quit()

关键改动说明

  • 全程复用同一个WebDriver实例,无需重启,大幅提升效率。
  • 每次操作下拉框前都重新获取元素并等待可交互,彻底避免失效元素引用。
  • 选中餐厅后增加餐型下拉框的等待,确保页面局部刷新完成后再进行下一步操作。
  • 修正了原代码的缩进错误,保证语法正确执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:07:33