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

Python Selenium WebDriverWait偶发返回异常问题排查求助

Selenium代码不稳定问题排查与修复

报错原因分析

  • Selenium版本兼容问题:代码中使用的find_element_by_id、find_elements_by_css_selector是Selenium 3的旧API,在Selenium 4+版本中已被移除,运行时会偶发调用失败
  • 弹窗遮挡元素:目标网站首次访问会弹出cookie同意框,未处理的情况下会遮挡搜索框,导致输入、点击操作偶发无法执行
  • 元素引用失效:提前获取的全量产品列表,在页面DOM动态更新(懒加载、广告插入、DOM重绘)后引用会失效,遍历操作时会抛出StaleElementReferenceException
  • 异常处理逻辑不全:主容器加载失败的分支里仅执行了driver.quit(),没有终止后续代码执行,后续操作空引用、已销毁的driver都会触发报错
  • 文本解析无边界判断:非Apple产品的名称如果没有cu关键字,raw_name.find("cu")会返回-1,计算得到的索引是负数,字符串切片会触发索引越界异常
  • 元素等待逻辑漏洞:遍历单个产品时用WebDriverWait(product, 10)等待子元素,当product本身已经失效的情况下,等待逻辑完全不生效

修复方案

  1. 统一使用Selenium 4标准的find_element(By.xxx, 选择器)写法,兼容所有主流版本
  2. 进入网站后先处理cookie同意弹窗,避免元素被遮挡导致操作失败
  3. 放弃预获取全量产品列表,改为按索引动态获取单个产品元素,每次获取都是最新的DOM引用,彻底避免stale元素异常
  4. 全局包裹异常捕获逻辑,所有失败场景统一处理,最终无论是否成功都关闭driver,避免资源泄漏
  5. 给文本解析增加边界判断,找不到指定关键字时 fallback 取完整名称,避免索引越界
  6. 所有元素等待统一使用driver层级的显性等待,确保等待逻辑稳定生效

修复后完整代码

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# 可选:使用webdriver-manager自动管理chromedriver,不需要手动指定路径
# 不想安装的话可以注释掉下面两行,换回你原来的路径写法即可
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install())

# 原手动指定路径的Selenium4兼容写法:
# Path = "C:\Program Files (x86)\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=Path)

driver.get("https://www.emag.ro/")
driver.maximize_window()

try:
    # 处理cookie同意弹窗
    WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.XPATH, "//button[text()='Accept']"))
    ).click()
    time.sleep(1)

    # 操作搜索框
    search_bar = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, "searchboxTrigger"))
    )
    search_bar.send_keys("laptopuri")
    search_bar.send_keys(Keys.RETURN)

    # 等待主容器加载
    main = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "main-container"))
    )
    print("Page loaded,main retrived succesfully")

    # 等待产品列表容器加载
    WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "card_grid"))
    )
    # 先获取产品总数量
    products_count = len(driver.find_elements(By.CSS_SELECTOR, "div.card-item.js-product-data"))
    count = 0

    # 按索引遍历,每次重新获取元素避免stale异常
    for i in range(products_count):
        product = driver.find_elements(By.CSS_SELECTOR, "div.card-item.js-product-data")[i]
        # 等待名称元素加载
        raw_name = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "h2.card-body.product-title-zone"))
        ).text
        # 等待价格元素加载
        raw_price = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CLASS_NAME, "product-new-price"))
        ).text

        # 解析产品名,增加边界判断
        raw_name = raw_name.replace("Laptop", "").strip()
        if raw_name.startswith("Apple"):
            sEnd = raw_name.find(",")
        else:
            sEnd = raw_name.find("cu") - 1
        product_name = raw_name[:sEnd] if sEnd > 0 else raw_name

        # 解析价格,增加边界判断
        space_idx = raw_price.find(" ")
        parsed_price = raw_price[:space_idx] if space_idx > 0 else raw_price
        print(f"产品名:{product_name},价格:{parsed_price}")
        count += 1

    print(f"{count} results returned")
except Exception as e:
    print(f"运行出错:{str(e)}")
finally:
    driver.quit()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 17:30:06