第三章 数据采集策略:金融数据源分类与合规清洗

兄弟们,咱们接着聊。上一章我们把RAG系统的整体架构搭起来了,但有个问题一直悬在心头——数据从哪来?

我在金融科技这行干了快十年,见过太多团队把精力全花在模型调优上,结果数据源一塌糊涂。你想想,RAG系统本质上就是个“检索+生成”的管道,如果检索到的都是垃圾,那生成出来的东西能看吗?我踩过的坑,今天全给你们抖出来。

3.1 金融数据源四大金刚

金融数据源,我习惯把它们分成四类:公告、研报、新闻、行情。这四类数据,就像厨房里的油盐酱醋,缺一个菜就做不香。

数据类别典型来源更新频率结构化程度RAG中的用途
公告上交所、深交所、巨潮资讯实时/每日半结构化(PDF/HTML)事实核查、合规问答
研报东方财富、万得、券商官网每日/每周非结构化(PDF/图片)观点总结、趋势分析
新闻财联社、路透、新浪财经实时/分钟级非结构化(文本)事件驱动、舆情监控
行情交易所API、Tushare、AKShareTick级/秒级高度结构化(CSV/JSON)量化回测、指标计算

这里我多说一句:公告和研报是RAG的“主食”,因为它们的权威性高、信息密度大。新闻是“配菜”,能提供时效性,但噪音也多。行情数据呢?它更适合做向量检索的“锚点”,比如“某只股票在财报发布前后的价格走势”。

我的经验:别一上来就全量采集。先问自己三个问题:用户最常问什么?哪些数据能直接回答?哪些数据需要交叉验证?比如做“分红问答”,那公告里的分红方案就是核心,研报里的预测只能当参考。

3.2 API采集与爬虫的合规边界

说到采集,很多新手第一反应就是写爬虫。但金融数据不是你想爬就能爬的。我见过有团队因为爬取交易所数据被发律师函,也见过因为滥用API被永久封号。

咱们得把合规这事掰扯清楚。

3.2.1 API采集:正规军的玩法

API是官方给的“合法通道”。比如Tushare、AKShare这些开源库,背后都有数据授权。用API的好处是:数据结构化、更新稳定、法律风险低。

但API也有坑:

  • 频率限制:很多免费API每分钟只能请求几次。我当年做实时行情采集,没注意限流,结果IP被拉黑了三天。
  • 字段不全:免费API往往只提供基础字段,比如“开盘价、收盘价”,但你要的“龙虎榜数据”可能得付费。
  • 数据延迟:免费API通常有15分钟延迟,做实时交易肯定不行。

# 一个简单的AKShare示例(合规使用)
import akshare as ak

# 获取A股实时行情(注意:免费版有延迟)
stock_zh_a_spot_df = ak.stock_zh_a_spot()
print(stock_zh_a_spot_df.head())

# 获取个股公告(来源:巨潮资讯)
stock_notice_df = ak.stock_notice_report(symbol="600519")
print(stock_notice_df[['title', 'date']])

3.2.2 爬虫:游击队的生存法则

爬虫不是不能用,但得守规矩。我总结了几条“红线”:

  1. robots.txt必须看:很多金融网站明确禁止爬取。比如东方财富的研报页面,robots.txt里写了Disallow: /report/*,你硬爬就是违法。
  2. 频率控制:别把人家服务器搞崩了。我一般设置每次请求间隔1-3秒,加随机User-Agent。
  3. 只爬公开数据:需要登录才能看的内容,比如付费研报、VIP行情,千万别碰。这属于“突破技术保护措施”,刑法第285条了解一下。
  4. 数据用途:爬下来的数据只能用于内部研究或非商业用途。你要是拿去卖钱,那就等着吃官司吧。
避坑指南:我见过最惨的案例——某团队爬取某财经网站的新闻,用了多线程+代理池,结果触发了对方的反爬机制,不仅IP被封,还被对方安全团队溯源到了公司服务器。最后法务出面才摆平。记住:金融数据采集,合规第一,效率第二。

3.3 数据去重与清洗:从垃圾到黄金

数据采回来了,但你会发现:同一篇公告,巨潮资讯和东方财富各发一遍;同一则新闻,财联社和路透社内容几乎一样。如果不做去重,RAG检索时就会返回一堆重复结果,用户体验极差。

我常用的去重策略分三层:

3.3.1 精确去重(MD5哈希)

最简单的方法:对文本内容计算MD5值,存到数据库里。新数据来的时候,先查哈希值是否存在。


import hashlib

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

# 假设已有哈希集合
existing_hashes = set()

def is_duplicate(new_text):
    h = get_md5(new_text)
    if h in existing_hashes:
        return True
    existing_hashes.add(h)
    return False

但这个方法有个问题:如果两篇新闻只差一个标点符号,MD5就不同了。所以还得上模糊去重。

3.3.2 模糊去重(SimHash + 汉明距离)

SimHash是Google用来去重网页的算法。它能将文本转成一个64位的指纹,然后通过比较指纹的“汉明距离”来判断相似度。一般距离小于3就算重复。

我当年做研报去重时,用SimHash把上万篇研报压缩到几千篇,效果立竿见影。

3.3.3 语义去重(向量相似度)

这是RAG时代的进阶玩法。用BERT或Sentence-BERT把文本转成向量,然后计算余弦相似度。如果相似度大于0.95,就认为是重复。

但注意:语义去重计算量大,不适合实时场景。我一般把它用在离线清洗环节。

3.4 数据清洗实战:公告文本的“格式化”

金融数据最头疼的就是PDF公告。你从巨潮资讯下载的PDF,里面可能包含表格、页眉页脚、乱码字符。如果不清洗,直接喂给RAG,检索效果会大打折扣。

我分享一个清洗流程:

  1. PDF解析:用PyMuPDF或pdfplumber提取文本。注意表格数据要单独处理,否则会变成一堆乱码。
  2. 去除页眉页脚:公告的页眉通常是“XX公司公告”,页脚是“第X页”。用正则表达式干掉它们。
  3. 统一编码:很多PDF里会有全角半角混用、特殊符号。比如“(”和“(”要统一成半角。
  4. 段落合并:PDF解析后经常出现断行。比如“本公\n司”要合并成“本公司”。

import re

def clean_pdf_text(text):
    # 去除页眉页脚(假设页眉是“XX公司公告”)
    text = re.sub(r'^.*?公司公告', '', text, flags=re.MULTILINE)
    # 合并断行
    text = re.sub(r'(?
核心观点:数据清洗不是一次性工作。我建议建立“清洗管道”,每次有新数据进来,自动走一遍流程。而且清洗规则要持续迭代——比如你发现某个券商研报的页脚格式变了,就得及时更新正则。

3.5 数据采集架构图

说了这么多,咱们用一张图把整个流程串起来。下面是我自己设计的“金融数据采集与清洗管道”架构图,用SVG画的,你们可以直接拿去用。

金融数据采集与清洗管道 公告(PDF/HTML) 研报(PDF/图片) 新闻(HTML/JSON) 行情(CSV) 采集层:API调用 / 爬虫(合规控制) 清洗层:去重(MD5/SimHash/向量)→ 格式化 → 编码统一 → 段落合并 → 表格提取 → 质量评分 存储层:向量数据库(Milvus/Pinecone)+ 关系型DB 反馈优化

这张图里,我特意加了一条“反馈优化”回路。什么意思呢?就是清洗后的数据质量,要能反馈到采集层。比如你发现某个数据源经常出现乱码,那就得调整解析策略,或者干脆换一个数据源。

3.6 我的避坑清单

最后,我把自己这些年踩过的坑,整理成一份清单,你们直接复制到项目文档里:

  • 别信“免费”的金融数据:很多免费API的数据质量堪忧,比如缺失值、时间戳错误。我建议至少用两个数据源交叉验证。
  • PDF解析永远有意外:有些公告是扫描件,PDF解析出来全是图片。这时候得用OCR(比如PaddleOCR),但OCR又慢又容易出错。我的方案是:优先找HTML版本的公告。
  • 去重阈值要调:SimHash的汉明距离设3还是5?得根据你的数据量试。我一般先采样1000条,人工标注重复,然后调参。
  • 合规不是摆设:我见过有人爬取某券商研报,结果对方在robots.txt里写了“禁止爬取”,但那人用了代理IP绕过去。这已经违法了。记住:金融数据采集,宁可慢,不要险。
一句话总结:数据采集是RAG系统的“地基”。地基不稳,上面盖的楼再漂亮也得塌。公告、研报、新闻、行情,分类采;API优先,爬虫谨慎;去重清洗做到位,后面检索才能准。

好了,这一章的内容就到这。数据采回来、洗干净了,下一章咱们就聊聊怎么把这些数据切分成适合RAG检索的“块”——也就是文本分块策略。到时候见。


公众号:蓝海资料掘金营,微信deep3321

专注资料整理