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

MechanicalSoup无法获取已存在的cmeTradeDate标签内容问题求助

解决get_settldays()函数无法获取日期内容的问题

嘿,我见过不少类似的情况,你的问题大概率是目标页面的渲染逻辑在2018年3月31日后发生了变化:之前select#cmeTradeDate的选项是直接嵌入在初始HTML里的,后来改成了通过JavaScript动态加载(比如页面加载后异步请求数据再渲染选项)。而MechanicalSoup本质是基于Requests和BeautifulSoup,它只会抓取初始的HTML源码,不会执行页面中的JavaScript,所以自然拿不到动态生成的内容,导致settlDays.contents为空。

下面给你几个可行的解决方案:

方案1:用支持JS渲染的工具模拟浏览器

你可以换成Selenium或者Playwright这类能模拟真实浏览器行为的工具,它们会完整执行页面的JS代码,能获取到动态渲染后的完整内容。

举个Selenium的实现例子:

import sys, re, datetime
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def get_settldays():
    # 初始化Chrome浏览器(需要提前下载对应版本的ChromeDriver)
    driver = webdriver.Chrome()
    driver.get("http://www.cmegroup.com/t...")
    
    # 等待select标签加载完成,避免因网络延迟抓不到内容
    try:
        settl_select = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "cmeTradeDate"))
        )
        # 获取所有选项元素
        options = settl_select.find_elements(By.TAG_NAME, "option")
        # 提取符合格式的日期
        settl_days = []
        for opt in options:
            date_match = re.search(r'\d\d/\d\d/\d\d\d\d', opt.text)
            if date_match:
                settl_days.append(date_match.group())
        # 转换为datetime对象返回
        return [datetime.datetime.strptime(adat, '%m/%d/%Y') for adat in settl_days]
    finally:
        # 无论成功失败都关闭浏览器
        driver.quit()

方案2:抓包直接调用数据源接口

这是更高效稳定的方式——在浏览器里打开开发者工具(按F12),切换到Network标签,刷新页面,观察哪些XHR/Fetch请求是用来获取交易日期数据的。找到对应的API接口后,直接用requests调用接口拿数据,不需要解析HTML。

比如假设找到的接口是http://www.cmegroup.com/api/trade-dates,代码可以简化成这样:

import requests, datetime, re

def get_settldays():
    # 直接请求数据源接口
    response = requests.get("http://www.cmegroup.com/api/trade-dates")
    response.raise_for_status()  # 抛出请求异常
    date_data = response.json()  # 假设接口返回JSON格式
    
    # 提取符合格式的日期(根据实际返回的JSON结构调整)
    settl_days = [item['tradeDate'] for item in date_data if re.match(r'\d\d/\d\d/\d\d\d\d', item['tradeDate'])]
    return [datetime.datetime.strptime(adat, '%m/%d/%Y') for adat in settl_days]

方案3:优化原代码(仅适用于静态内容场景)

如果页面只是有小改动,还保留了静态的option标签,你可以优化原代码的提取逻辑,直接遍历option标签而不是转成字符串匹配:

import sys, mechanicalsoup, re, datetime

def get_settldays(soup):
    settl_select = soup.find('select', id="cmeTradeDate")
    settl_days = []
    # 直接遍历select下的option标签
    for option in settl_select.find_all('option'):
        date_match = re.search(r'\d\d/\d\d/\d\d\d\d', option.get_text())
        if date_match:
            settl_days.append(date_match.group())
    return [datetime.datetime.strptime(adat, '%m/%d/%Y') for adat in settl_days]

url = "http://www.cmegroup.com/t..."
browser = mechanicalsoup.Browser()
page = browser.get(url)
print(get_settldays(page.soup))

总结

优先推荐方案2,因为它不需要模拟浏览器,效率更高也更稳定;如果找不到数据源接口,再用方案1模拟浏览器;方案3只适合页面还保留静态内容的情况,对你的场景可能不太适用,但可以试试排除问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:41:40