第三章:数据采集与清洗——金融数据的“淘金”之路

做金融大模型,数据就是命根子。这话一点都不夸张。

我见过太多团队,模型架构搞得花里胡哨,结果喂进去的数据一塌糊涂,最后出来的结果自然也是惨不忍睹。说白了,你喂的是金子,模型才能吐出金子;你喂的是垃圾,那产出只能是垃圾。

这一章,我们就来聊聊怎么搞到这些“金子”,以及怎么把“矿石”提炼成“纯金”。

3.1 金融数据的三大来源:财报、新闻、公告

金融数据来源很多,但最核心的,我个人认为就三个:财报、新闻、公告。这三者构成了金融市场的“信息三角”。

数据来源 核心内容 更新频率 获取难度
财报 营收、利润、现金流、资产负债等 季度/年度 中等(结构化较好)
新闻 行业动态、政策解读、公司事件 实时/每日 较高(非结构化)
公告 重大合同、人事变动、股权变更 不定期 中等(格式较规范)

为什么是这三个?财报告诉你公司“过去”怎么样,新闻告诉你“现在”发生了什么,公告则暗示“未来”可能有什么变化。三者结合,才能拼凑出一个相对完整的图景。

我的经验: 别只盯着财报。很多量化策略的失效,就是因为忽略了新闻情绪。我记得有一次,一家公司财报数据非常漂亮,但新闻里全是负面报道,结果股价第二天就崩了。所以,多源数据融合才是王道。

3.2 网络爬虫基础:Requests vs. Scrapy

数据不会自己送上门来。你得去“拿”。网络爬虫就是干这个的。

对于初学者,我建议从 Requests 入手。它简单、直接,就像一把瑞士军刀,适合处理小规模、结构简单的页面。

import requests

url = "https://api.example.com/financial/report?code=600519"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
response = requests.get(url, headers=headers)

if response.status_code == 200:
    data = response.json()
    print(data)
else:
    print(f"请求失败,状态码:{response.status_code}")

嗯,这里要注意。很多金融网站都有反爬机制。你直接拿 requests.get() 去抓,大概率会被封IP。所以,headers 里的 User-Agent 一定要伪装成浏览器。

那什么时候用 Scrapy 呢?当你需要大规模、持续性地采集数据时。比如,你要抓取过去十年所有上市公司的财报数据。Scrapy 就像一个工业级的挖掘机,支持异步、分布式、自动重试等高级功能。

避坑指南: 我曾经为了图省事,直接用 Requests 写了个循环去抓几千个页面。结果跑了半小时,IP 被封了,数据全丢了。后来改用 Scrapy,配合代理池和自动重试机制,才顺利搞定。所以,小项目用 Requests,大项目上 Scrapy,别犹豫。

3.3 数据清洗:去重、去噪、标准化

数据采集回来,只是第一步。真正的“脏活累活”才刚刚开始。

你想想看,从网上扒下来的数据,什么情况都有:重复的、缺失的、格式混乱的、夹杂着HTML标签的……不洗干净,模型根本没法用。

3.3.1 去重

重复数据是最大的噪音。同一个公告,可能被多个网站转载,你抓下来就是好几份。最简单的去重方法就是基于 内容哈希

import hashlib

def get_content_hash(text):
    return hashlib.md5(text.encode('utf-8')).hexdigest()

seen_hashes = set()
unique_data = []

for item in raw_data:
    content_hash = get_content_hash(item['content'])
    if content_hash not in seen_hashes:
        seen_hashes.add(content_hash)
        unique_data.append(item)

3.3.2 去噪

去噪就是去掉那些“没用”的信息。比如,新闻页面里的广告、导航栏、版权声明等。对于金融数据,我常用的方法是 正则表达式 + 规则过滤

import re

def clean_text(text):
    # 去除HTML标签
    text = re.sub(r'<[^>]+>', '', text)
    # 去除多余空白
    text = re.sub(r'\s+', ' ', text).strip()
    # 去除常见的广告关键词
    ad_keywords = ['广告', '推广', '点击这里']
    for keyword in ad_keywords:
        text = text.replace(keyword, '')
    return text

警告: 正则表达式虽然强大,但容易误伤。比如,你本想去除“广告”二字,结果把“广告法”也去掉了。所以,清洗规则一定要在真实数据上反复测试,别想当然。

3.3.3 标准化

标准化是让数据“说同一种语言”。比如,日期格式,有的用“2024-01-01”,有的用“2024年1月1日”。金额单位,有的用“元”,有的用“万元”。

from datetime import datetime

def standardize_date(date_str):
    # 尝试多种格式解析
    formats = ['%Y-%m-%d', '%Y年%m月%d日', '%Y/%m/%d']
    for fmt in formats:
        try:
            return datetime.strptime(date_str, fmt).strftime('%Y-%m-%d')
        except ValueError:
            continue
    return None  # 解析失败

3.4 数据存储:CSV / JSON / 数据库

清洗干净的数据,得找个地方存起来。选哪种存储方式,取决于你的使用场景。

存储方式 优点 缺点 适用场景
CSV 简单、通用、Excel可直接打开 不支持复杂结构、查询慢 小规模数据、快速预览
JSON 支持嵌套结构、可读性好 文件体积大、解析慢 API交互、配置文件
数据库 支持复杂查询、事务、并发 需要安装、学习成本高 大规模数据、生产环境

我个人习惯是:原始数据存 JSON,保留最完整的信息;清洗后的结构化数据存数据库,方便后续查询和分析;中间结果或小批量数据用 CSV,方便调试和分享。

import json
import csv
import sqlite3

# 存为 JSON
with open('financial_data.json', 'w', encoding='utf-8') as f:
    json.dump(cleaned_data, f, ensure_ascii=False, indent=2)

# 存为 CSV
with open('financial_data.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=['date', 'title', 'content'])
    writer.writeheader()
    writer.writerows(cleaned_data)

# 存入 SQLite 数据库
conn = sqlite3.connect('financial.db')
cursor = conn.cursor()
cursor.execute('''
    CREATE TABLE IF NOT EXISTS news (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        date TEXT,
        title TEXT,
        content TEXT
    )
''')
for item in cleaned_data:
    cursor.execute('INSERT INTO news (date, title, content) VALUES (?, ?, ?)',
                   (item['date'], item['title'], item['content']))
conn.commit()
conn.close()

核心逻辑: 数据采集与清洗,本质上是一个“从无序到有序”的过程。你从互联网这个巨大的“信息海洋”里,把有用的“鱼”捞出来,去掉“泥沙”,再按类别放进不同的“鱼缸”里。这个过程决定了你模型的天花板。

金融数据采集与清洗流程 数据来源 财报 / 新闻 / 公告 网络爬虫 Requests / Scrapy 数据清洗 去重 / 去噪 / 标准化 数据存储 CSV / JSON / 数据库 核心原则:多源融合 → 清洗提纯 → 结构化存储 数据质量决定了模型效果的上限

好了,这一章的内容就到这里。数据采集与清洗,听起来枯燥,但它是整个金融大模型项目的基石。你花在清洗上的每一分钟,都会在模型训练和推理阶段得到回报。


专注资料整理