第三章 数据采集策略:金融数据源分类与合规清洗
兄弟们,咱们接着聊。上一章我们把RAG系统的整体架构搭起来了,但有个问题一直悬在心头——数据从哪来?
我在金融科技这行干了快十年,见过太多团队把精力全花在模型调优上,结果数据源一塌糊涂。你想想,RAG系统本质上就是个“检索+生成”的管道,如果检索到的都是垃圾,那生成出来的东西能看吗?我踩过的坑,今天全给你们抖出来。
3.1 金融数据源四大金刚
金融数据源,我习惯把它们分成四类:公告、研报、新闻、行情。这四类数据,就像厨房里的油盐酱醋,缺一个菜就做不香。
| 数据类别 | 典型来源 | 更新频率 | 结构化程度 | RAG中的用途 |
|---|---|---|---|---|
| 公告 | 上交所、深交所、巨潮资讯 | 实时/每日 | 半结构化(PDF/HTML) | 事实核查、合规问答 |
| 研报 | 东方财富、万得、券商官网 | 每日/每周 | 非结构化(PDF/图片) | 观点总结、趋势分析 |
| 新闻 | 财联社、路透、新浪财经 | 实时/分钟级 | 非结构化(文本) | 事件驱动、舆情监控 |
| 行情 | 交易所API、Tushare、AKShare | Tick级/秒级 | 高度结构化(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 爬虫:游击队的生存法则
爬虫不是不能用,但得守规矩。我总结了几条“红线”:
- robots.txt必须看:很多金融网站明确禁止爬取。比如东方财富的研报页面,robots.txt里写了Disallow: /report/*,你硬爬就是违法。
- 频率控制:别把人家服务器搞崩了。我一般设置每次请求间隔1-3秒,加随机User-Agent。
- 只爬公开数据:需要登录才能看的内容,比如付费研报、VIP行情,千万别碰。这属于“突破技术保护措施”,刑法第285条了解一下。
- 数据用途:爬下来的数据只能用于内部研究或非商业用途。你要是拿去卖钱,那就等着吃官司吧。
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,检索效果会大打折扣。
我分享一个清洗流程:
- PDF解析:用PyMuPDF或pdfplumber提取文本。注意表格数据要单独处理,否则会变成一堆乱码。
- 去除页眉页脚:公告的页眉通常是“XX公司公告”,页脚是“第X页”。用正则表达式干掉它们。
- 统一编码:很多PDF里会有全角半角混用、特殊符号。比如“(”和“(”要统一成半角。
- 段落合并: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画的,你们可以直接拿去用。
这张图里,我特意加了一条“反馈优化”回路。什么意思呢?就是清洗后的数据质量,要能反馈到采集层。比如你发现某个数据源经常出现乱码,那就得调整解析策略,或者干脆换一个数据源。
3.6 我的避坑清单
最后,我把自己这些年踩过的坑,整理成一份清单,你们直接复制到项目文档里:
- 别信“免费”的金融数据:很多免费API的数据质量堪忧,比如缺失值、时间戳错误。我建议至少用两个数据源交叉验证。
- PDF解析永远有意外:有些公告是扫描件,PDF解析出来全是图片。这时候得用OCR(比如PaddleOCR),但OCR又慢又容易出错。我的方案是:优先找HTML版本的公告。
- 去重阈值要调:SimHash的汉明距离设3还是5?得根据你的数据量试。我一般先采样1000条,人工标注重复,然后调参。
- 合规不是摆设:我见过有人爬取某券商研报,结果对方在robots.txt里写了“禁止爬取”,但那人用了代理IP绕过去。这已经违法了。记住:金融数据采集,宁可慢,不要险。
好了,这一章的内容就到这。数据采回来、洗干净了,下一章咱们就聊聊怎么把这些数据切分成适合RAG检索的“块”——也就是文本分块策略。到时候见。
公众号:蓝海资料掘金营,微信deep3321