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

使用Selenium爬取TradingView图表数据时无限循环遭遇StaleElementReferenceException异常的解决求助

解决Selenium爬取TradingView时的StaleElementReferenceException异常

你遇到的StaleElementReferenceException在TradingView这类实时动态更新的页面里特别常见——本质原因是页面元素会随着行情数据刷新被重新渲染,你之前定位到的元素引用会因为DOM结构变化而失效,哪怕用了显式等待也可能踩坑,因为presence_of_element_located只保证元素在DOM中存在,但不保证它是最新的、可交互的。

下面给你几个针对性的优化方案和修改后的代码:

核心优化方向

1. 改用visibility_of_element_located代替presence_of_element_located

presence_of_element_located仅检查元素是否存在于DOM中,但元素可能还没加载完成或者不可见,这时候获取文本大概率会失败。visibility_of_element_located会确保元素可见,更适合需要读取文本的场景。

2. 优化定位函数的逻辑

  • 用elif替代多个独立if,避免逻辑分支混乱
  • 不要依赖全局变量chrome,把driver作为参数传入,让函数更健壮
  • 增加异常捕获后的提示,方便排查问题

3. 每次获取数据都重新定位元素

在无限循环中,永远不要复用之前的元素对象——下一次循环时,这个元素很可能已经被页面刷新替换了,必须重新定位才能拿到有效的引用。

4. 替换脆弱的绝对XPath

你用的绝对XPath(比如/html/body/div[11]/div/div[2]/div/...)非常容易失效,只要页面结构有微小变化(比如弹窗顺序、div层级调整)就会定位失败。建议用相对XPath,结合元素的class、属性等特征来定位。

修改后的完整代码示例

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

def locate(driver, path, locator_type="xpath", timeout=5):
    """改进后的定位函数,传入driver,改用可见性检查"""
    ignored_exceptions = (NoSuchElementException, StaleElementReferenceException)
    try:
        if locator_type == "xpath":
            element = WebDriverWait(driver, timeout, ignored_exceptions=ignored_exceptions).until(
                EC.visibility_of_element_located((By.XPATH, path))
            )
        elif locator_type == "link_text":
            element = WebDriverWait(driver, timeout, ignored_exceptions=ignored_exceptions).until(
                EC.visibility_of_element_located((By.LINK_TEXT, path))
            )
        elif locator_type == "name":
            element = WebDriverWait(driver, timeout, ignored_exceptions=ignored_exceptions).until(
                EC.visibility_of_element_located((By.NAME, path))
            )
        else:
            raise ValueError(f"不支持的定位类型: {locator_type}")
        return element
    except Exception as e:
        print(f"定位元素失败: {e}")
        return None

def login(driver):
    driver.get("https://in.tradingview.com/chart/iVucV9D0/")
    driver.maximize_window()
    sign_in_btn = locate(driver, "Sign in", "link_text")
    if sign_in_btn:
        sign_in_btn.click()
    
    # 替换绝对XPath为更稳定的相对路径(你需要根据实际页面调整)
    google_login_btn = locate(driver, "//span[contains(text(), 'Google')]/parent::div")
    if google_login_btn:
        google_login_btn.click()
    
    username_input = locate(driver, "username", "name")
    if username_input:
        username_input.send_keys("myemail")
    
    password_input = locate(driver, "password", "name")
    if password_input:
        password_input.send_keys("mypassword" + Keys.ENTER)
    
    time.sleep(3)
    confirm_btn = locate(driver, "//button[contains(text(), 'Continue')]")
    if confirm_btn:
        confirm_btn.click()

def get_buy_price(driver):
    # 建议替换为更稳定的相对XPath(示例,需根据实际页面元素调整)
    price_element = locate(driver, "//div[contains(@class, 'supertrend-buy')]/span")
    if price_element and price_element.text != "n/a":
        try:
            return float(price_element.text)
        except ValueError:
            print("价格格式解析失败")
            return "na"
    return "na"

def get_sell_price(driver):
    price_element = locate(driver, "//div[contains(@class, 'supertrend-sell')]/span")
    if price_element and price_element.text != "n/a":
        try:
            return float(price_element.text)
        except ValueError:
            print("价格格式解析失败")
            return "na"
    return "na"

if __name__ == "__main__":
    driver_path = "D:\\Repositories\\Bot\\chromedriver v89.0.4389.23.exe"
    with webdriver.Chrome(driver_path) as chrome:
        login(chrome)
        while True:
            buy_price = get_buy_price(chrome)
            if buy_price != "na":
                print(f"Supertrend Buy detected, 价格: {buy_price}")
                # 执行后续逻辑
            
            sell_price = get_sell_price(chrome)
            if sell_price != "na":
                print(f"Supertrend Sell Detected, 价格: {sell_price}")
                # 执行后续逻辑
            
            # 加短延迟,避免频繁请求导致页面卡顿或触发反爬
            time.sleep(1)

额外注意事项

  • TradingView反爬机制:TradingView有严格的反爬措施,频繁的自动化操作可能会导致账号被限制或IP被封,建议控制请求频率,不要过于激进。
  • ChromeDriver版本匹配:确保你的ChromeDriver版本和本地Chrome浏览器版本一致,版本不兼容也可能导致各种奇怪的异常。
  • 元素定位优化:尽量用ID、class、data-*属性等更稳定的定位方式,避免依赖绝对XPath或页面层级结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 14:12:48