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

Selenium XPATH定位仅打开检查窗口生效 关闭报NoSuchElementException

Selenium 定位元素仅在打开浏览器检查窗口时生效,关闭后抛出NoSuchElementException

问题描述

基于Selenium 4开发爬取选手名称、赔率数据的项目时,调用driver.find_element(By.XPATH)方法出现元素定位异常:编写的XPath仅在目标页面打开浏览器开发者检查窗口时可正常定位元素,一旦关闭检查窗口,就会抛出如下报错:

NoSuchElementException: no such element: Unable to locate element:

复现代码

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

driver = webdriver.Chrome()

url = 'https://www.bet365.com.au/#/AC/B13/C1/D50/E2/F163/'
driver.get(url)

Player1 = driver.find_element(By.XPATH, '/html/body/div[1]/div/div[4]/div[3]/div/div/div/div[1]/div/div/div[2]/div/div/div[1]/div[2]/div/div[1]/div[2]/div[1]/div/div[2]/div/div[1]/div').text
Player2 = driver.find_element(By.XPATH, '/html/body/div[1]/div/div[4]/div[3]/div/div/div/div[1]/div/div/div[2]/div/div/div[1]/div[2]/div/div[1]/div[2]/div[1]/div/div[2]/div/div[2]/div').text
Odds1 = driver.find_element(By.XPATH, '/html/body/div[1]/div/div[4]/div[3]/div/div/div/div[1]/div/div/div[2]/div/div/div[1]/div[2]/div/div[2]/div[2]/span').text
Odds2 = driver.find_element(By.XPATH, '/html/body/div[1]/div/div[4]/div[3]/div/div/div/div[1]/div/div/div[2]/div/div/div[1]/div[2]/div/div[3]/div[2]/span').text
print(f'{Player1}\t{Odds1}')
print(f'{Player2}\t{Odds2}')

复现方式:分别在打开、关闭浏览器检查窗口的状态下,运行Player1变量定义及之后的代码段即可稳定复现问题。

额外编写的元素存在性验证代码如下:

try:
    if driver.find_element(By.XPATH, '/html/body/div[1]/div/div[4]/div[3]/div/div/div/div[1]/div/div/div[2]/div/div/div[1]/div[2]/div/div[1]/div[2]/div[1]/div/div[2]/div/div[1]/div').text:
        print("yay")
        
except:
    print("nay")

验证结果与之前一致:关闭检查窗口时无法定位到目标元素,使用的XPath为浏览器开发者工具直接复制的绝对路径。


问题原因

核心触发原因有3个:

  • 所用定位语句是浏览器检查窗口直接复制的全路径绝对XPath,这类路径完全绑定DOM节点的层级顺序,bet365本身配置了反爬机制:打开开发者工具时会触发反爬逻辑,出现节点重排、插入临时占位div的情况,此时DOM结构和无开发者工具的正常访问状态不一致,直接复制的绝对路径自然匹配不到元素。
  • 页面内容为动态异步加载,代码中没有加任何等待逻辑,打开检查窗口时页面加载、渲染节奏会变慢,执行定位语句时刚好赶上元素渲染完成;关闭窗口后页面渲染速度变快,执行find_element时目标节点还没加载进DOM。
  • 网站存在响应式适配逻辑,默认启动的Chrome窗口尺寸和手动打开检查窗口时的视口尺寸不一致,视口尺寸不满足要求时,赛事赔率模块会切换DOM结构或者直接隐藏对应节点。

解决方案

按优先级依次调整即可解决问题:

  1. 替换绝对XPath为相对定位逻辑,不要用从根节点html开始的全路径,基于元素的文本、类名、属性特征写相对路径,比如选手名、赔率所在节点都有固定的类名前缀,定位逻辑不受父节点层级变动影响。
  2. 用显式等待替代直接执行find_element,等目标元素加载完成、可见之后再获取内容,不要用固定时长的time.sleep,优先用Selenium自带的WebDriverWait:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 等待最多15秒直到元素可见
wait = WebDriverWait(driver, 15)
player1_ele = wait.until(EC.visibility_of_element_located((By.XPATH, '//div[contains(@class, "rcl-ParticipantFixtureDetailsTeam_TeamName")][1]')))
  1. 启动浏览器时固定窗口尺寸,隐藏自动化特征,绕过基础反爬检测:
options = webdriver.ChromeOptions()
# 固定桌面端视口尺寸,避免响应式结构变动
options.add_argument("--window-size=1920,1080")
# 隐藏webdriver自动化标识
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(options=options)
# 注入脚本覆盖navigator.webdriver属性
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
  1. 如果调整后仍定位失败,可在执行定位逻辑前打印driver.page_source,对比开关检查窗口时的页面源码差异,找到具体变动的DOM节点后对应调整XPath即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 00:18:22