从新浪爬取的最新期货数据(GC、CL、NQ、ES)只有前一天的结算价,芝加哥商业交易所(CME)官方网站可以提供过去五天的历史结算价。
昨天,套利程序的编程告一段落。我今天腾出手来,开始收拾之前遗漏的多个"未解之谜"。
鉴于 CME 网站极高的反爬机制与动态渲染技术,我在Gemini的帮助下,一次就搞定,当然也离不开TRAE打下的基础和我的耐心投喂。采用 Selenium 自动化 + 本地智能缓存的架构,确保数据的稳定获取和程序的鲁棒性,。
PS-再一次证明TRAE的无能,野花的芬芳
CME 网站的数据表格并非传统的静态 HTML 内容,而是通过现代前端 JavaScript 框架(例如 React/Angular)在页面加载完成后,异步请求后端 API 并动态渲染生成的。
这意味着,如果直接使用 Python 的 requests 库去请求网页的原始 HTML 源码,将只能得到一个不包含实际数据表格的“骨架”页面。
此外,CME 的后端 API 受到严格的 Web 应用防火墙(WAF,如 Cloudflare/Akamai)保护。任何直接针对 API 的请求都极易被识别为自动化机器人行为,并立即遭到拦截(通常表现为 HTTP 403 Forbidden 错误)。
为了有效应对这些挑战,选择使用 Selenium。Selenium 能够驱动真实的 Chrome 浏览器内核,完全模拟人类用户的正常访问行为。它会等待页面上的所有 JavaScript 脚本执行完毕,确保数据完全渲染到 DOM(文档对象模型)树中,然后再从这个完整的 DOM 树中提取所需的目标数据。这种方式极大地提高了数据获取的成功率和稳定性。
为了让 Selenium 驱动的浏览器行为更接近一个真实的普通用户,从而有效规避 CME 网站的反爬检测,在 get_cme_settlement 函数中进行了深度的环境伪装和策略优化。
通过配置 Chrome 浏览器的启动选项,来模拟真实用户的环境特征,并隐藏自动化工具的痕迹。
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless') # 无头模式,后台静默运行,不弹出实体浏览器窗口
chrome_options.add_argument('--disable-gpu') # 禁用 GPU 硬件加速,在某些无头环境下可能需要
chrome_options.add_argument('--window-size=1920,1080') # 伪装真实桌面显示器分辨率,避免被识别为移动设备或异常尺寸
# 核心伪装:设置真实的 User-Agent,防止被识别为无头浏览器默认的 User-Agent
# 注意:User-Agent 应定期更新以保持其真实性,以应对网站可能的检测更新
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36')
# --- 新增:高级反爬伪装配置 ---
# 1. 禁用浏览器正在被自动化程序控制的提示(例如 Chrome 顶部的"Chrome 正在受到自动化测试软件的控制")
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
# 2. 禁用 Blink 引擎中的自动化特征 (window.navigator.webdriver = true),这是许多 WAF 检测 Selenium 的关键点
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
# 3. 避免加载图片,可以加快页面加载速度,并减少网络流量(可选,根据需求决定是否开启)
# chrome_options.add_argument('--blink-settings=imagesEnabled=false')
# 4. (可选) 配置代理,强烈建议用于访问海外网站
# chrome_options.add_argument('--proxy-server=http://127.0.0.1:10808')
chrome_options = Options()
chrome_options.add_argument('--headless') # 无头模式,后台静默运行,不弹出实体浏览器窗口
chrome_options.add_argument('--disable-gpu') # 禁用 GPU 硬件加速,在某些无头环境下可能需要
chrome_options.add_argument('--window-size=1920,1080') # 伪装真实桌面显示器分辨率,避免被识别为移动设备或异常尺寸
# 核心伪装:设置真实的 User-Agent,防止被识别为无头浏览器默认的 User-Agent
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36')
CME 的历史数据页面通常通过 URL Hash(例如 #tradeDate=04/10/2026)来切换日期。如果短时间内重复请求同一基础 URL,内容分发网络(CDN)可能会返回旧的缓存页面,导致数据不是最新的。
为了强制 CDN 穿透并触发真实的路由更新,在 URL 拼接时动态加入了一个毫秒级的时间戳参数。这使得每次请求的 URL 都是独一无二的,从而绕过 CDN 缓存。
import time
timestamp = int(time.time() * 1000) # 获取当前时间的毫秒级时间戳
base_url = "https://www.cmegroup.com/markets/futures/..." # **请替换为实际的 CME 基础 URL**
target_date = "04/10/2026" # 示例目标日期,实际使用时应动态生成
url = f"{base_url}?_t={timestamp}#tradeDate={target_date}"
在单页应用(SPA)中,需要循环爬取不同日期的数据时,旧的表格 DOM 元素可能会残留在页面上。这会导致 Selenium 的 WebDriverWait 瞬间误判页面已加载完成,从而抓取到上一天的重复数据。
为了彻底销毁旧的 DOM 树,确保每次都是从一个干净的页面开始加载新数据,通过在每次请求真实 URL 前,先跳转一次空白页 (about:blank)。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options # 导入 Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 假设 chrome_options 已按 2.1 节配置
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36')
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
# ... 其他 chrome_options 配置 ...
driver = webdriver.Chrome(options=chrome_options)
wait = WebDriverWait(driver, 10) # 10秒超时
# 示例 URL (请替换为实际的 CME 目标 URL)
example_url = "https://www.cmegroup.com/markets/futures/metals/gold/gold.html#tradeDate=04/10/2026"
# 强制清空上一次循环遗留的 DOM,防止旧表格干扰 Wait
driver.get("about:blank")
driver.get(example_url) # 加载新的目标 URL
# 优化后的等待:等待具有特定 class 或特定结构的表格元素,提高等待的精确度
# 假设 CME 的数据表格有一个 class 为 'cme-data-table'
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'table.cme-data-table')))
# 或者等待表格内的数据行渲染完成,确保数据已经加载
# wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'table.cme-data-table tbody tr')))
# 完成操作后,记得关闭浏览器
driver.quit()
如果你发现使用原生的 Selenium + 配置项仍然偶尔遭遇 HTTP 403 或无尽的人机验证(Captcha),可以在文档的备选方案中考虑使用 undetected-chromedriver。这是一个经过特殊编译和优化的 WebDriver,专门用于绕过各类 WAF。
# 安装: pip install undetected-chromedriver
import undetected_chromedriver as uc
options = uc.ChromeOptions()
options.add_argument('--headless')
# undetected-chromedriver 默认已经处理了 webdriver 特征抹除,无需额外配置
# 它会自动管理 ChromeDriver,无需 webdriver-manager
driver = uc.Chrome(options=options)
# 完成操作后,记得关闭浏览器
driver.quit()
直接高频请求 CME 网站不仅速度极慢(受限于 Selenium 渲染速度),而且面临被封禁 IP 的高风险。为了解决这些问题,引入了 cme_history_cache.csv 文件作为轻量级的本地微型数据库。
这个智能缓存机制旨在最大限度地减少对 CME 网站的实际访问,从而提高效率并降低风险:
这个本地智能缓存机制为工具带来了显著的性能和稳定性提升:
如何快速部署和运行 CME 期货历史结算价爬虫与对比工具。
在运行本工具之前,请确保系统满足以下环境要求:
pip install requests beautifulsoup4 selenium webdriver-manager pandas
requests: 用于发送 HTTP 请求(例如,获取新浪财经数据)。
beautifulsoup4: 用于解析 HTML 内容(可能用于新浪财经数据)。
selenium: 驱动浏览器进行自动化操作。
webdriver-manager: 自动管理和下载 ChromeDriver,省去手动配置的麻烦。
pandas: 用于数据处理和 CSV 文件的读写(尤其在缓存机制中)。
代理配置: 由于 CME 网站是海外网站,且反爬机制严格,强烈建议在运行环境配置代理。代码默认配置为 127.0.0.1:XXXX。请根据各自实际的代理服务地址和端口进行修改。
# 示例:在 Python 代码中设置代理
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
# ... 其他 chrome_options 配置,例如无头模式、User-Agent 等
chrome_options.add_argument('--proxy-server=http://127.0.0.1:XXXXX')
# driver = webdriver.Chrome(options=chrome_options)
完成环境依赖的安装和代理配置后,你可以通过以下命令运行本工具:
python Test_sina_futures.py
程序运行结束后,将在当前目录下看到以下输出:
这份说明文档不仅清晰地阐述了工具的实现细节,更重要的是,它深入解释了每个技术选择背后的原因,尤其是在应对 CME 网站复杂反爬机制方面的策略。本地智能缓存机制的设计,更是切中了爬取海外金融数据时对效率和稳定性的核心需求。
