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

Python运行时与VSCode调试模式下NoSuchElementException异常行为差异排查

环境信息

  • Python 3.10.5
  • Selenium 4.3.0
  • Seleniumwire 4.6.5
  • geckodriver 0.31.0
  • Firefox 91.11.0esr (64-bit)
  • IDE VSCode 1.70.1

需求与问题

我需要从维基百科超链接的悬停预览中提取图片链接和段落文本,但代码在Python直接运行和VSCode内置调试器中的表现不一致:

  1. 调试模式下代码符合预期,能正确捕获无图片预览场景的NoSuchElementException异常;
  2. 直接运行代码时,本该触发异常的无图片项(比如"Rassestandard")没被捕获,反而生成字典并加入结果列表,之后才进入except块打印错误信息。

代码片段

def get_breed(a, driver, action):
    url = unquote(a.get_attribute("href"))
    if page_exist(url):
        scroll_shim(driver, a)
        action.move_to_element(a).perform()
        div_popup = driver.find_element(By.CLASS_NAME, "mwe-popups-container")
        if div_popup:
            try:
                img = div_popup.find_element(By.CLASS_NAME, "mwe-popups-thumbnail")
                p = div_popup.find_element(By.TAG_NAME, "p")
                print("test-1")
            except NoSuchElementException:
                print("test-4")
                print(err)
                return
            print("test-2")
            breed = {
                "name": a.text,
                "img": unquote(img.get_attribute("src")),
                "desc": p.text
                }
            return breed
def get_breeds_from_ul(breeds_url):
    driver = get_driver(breeds_url)
    action = ActionChains(driver)
    uls = driver.find_elements(By.XPATH, "//div[@class='mw-parser-output']/ul")
    breeds = []
    for ul_tag in uls[:-2]:
        all_a = ul_tag.find_elements(By.TAG_NAME, "a")
        for a in all_a:
            breed = get_breed(a, driver, action)
            if breed:
                breeds.append(breed)
                print(breed)
                print("test-3")
    driver.close()
    return breeds

预期结果

无图片的预览项应该被跳过,不会生成字典并加入结果列表,输出示例如下:

$ python get_animals.py
test-1
test-2
{'name': 'Bayerische Landgans', 'img': 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8b/Bayerische_Landgans.jpg/319px-Bayerische_Landgans.jpg', 'desc': 'Bayerische Landgänse sind Hausgänse, die in Franken, der Oberpfalz, Niederbayern und Schwaben gezüchtet wurden. „Bayerische Landgans“ ist ein Oberbegriff für die in diesen Regionen beheimateten Landschläge.'}
test-3
test-1
test-4
test-1
test-2
{'name': 'Another animal name', 'img': 'another link', 'desc': 'Another description.'}
test-3

疑问

为什么Python直接运行时会出现异常捕获延迟、逻辑执行顺序混乱的情况?是我在代码逻辑或异常处理上有错误吗?


问题分析与解决

核心问题点

  1. 时序不匹配:调试模式下代码逐行执行,悬停后的弹窗有足够时间渲染完成;直接运行时代码执行速度快,弹窗内部元素还没加载就开始查找,导致后续逻辑混乱——比如暂时找不到元素但后续又加载出来,异常捕获逻辑失效。
  2. 异常处理错误:except块中引用了未定义的err变量,会触发新的NameError,干扰原异常的捕获流程,导致代码执行顺序错乱。
  3. 无效判断冗余:div_popup = driver.find_element(...)如果找不到元素会直接抛出异常,后面的if div_popup:完全多余,因为查找成功后div_popup必然是非空对象。

修复方案

  1. 添加显式等待:对弹窗及内部元素使用显式等待,确保元素加载完成后再操作,解决时序问题。
  2. 修正异常处理:要么移除未定义的err,要么正确捕获异常对象(except NoSuchElementException as err:)。
  3. 清理无效代码:删除多余的if div_popup:判断。

修复后的get_breed函数示例:

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

def get_breed(a, driver, action):
    url = unquote(a.get_attribute("href"))
    if page_exist(url):
        scroll_shim(driver, a)
        action.move_to_element(a).perform()
        # 等待弹窗容器加载
        try:
            div_popup = WebDriverWait(driver, 5).until(
                EC.presence_of_element_located((By.CLASS_NAME, "mwe-popups-container"))
            )
        except:
            return
        
        try:
            # 等待图片和段落元素加载完成
            img = WebDriverWait(div_popup, 3).until(
                EC.presence_of_element_located((By.CLASS_NAME, "mwe-popups-thumbnail"))
            )
            p = WebDriverWait(div_popup, 3).until(
                EC.presence_of_element_located((By.TAG_NAME, "p"))
            )
            print("test-1")
        except NoSuchElementException as err:
            print("test-4")
            print(err)
            return
        print("test-2")
        breed = {
            "name": a.text,
            "img": unquote(img.get_attribute("src")),
            "desc": p.text
        }
        return breed

补充说明

调试模式的逐行执行给了弹窗足够的加载时间,所以异常能被正确捕获;直接运行时速度快,元素加载不及时就会导致逻辑出错,显式等待是解决这类Selenium时序问题的标准方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 07:09:12