2、数据源获取:公告数据来源与爬虫基础
做事件驱动策略,第一步就是搞定数据。没有数据,再牛的策略也是空中楼阁。
我个人习惯把公告数据源分成三类:官方渠道、商业终端、财经门户。这三类各有优劣,咱们一个一个说。
2.1 三大数据源对比
先看一张表,你心里就有数了:
| 数据源 | 覆盖范围 | 更新速度 | 获取成本 | 适合场景 |
|---|---|---|---|---|
| 巨潮资讯网 | 沪深京A股全量公告 | 实时(交易所直连) | 免费 | 个人研究、小规模策略 |
| 东方财富 | A股+港股+基金 | 延迟5-15分钟 | 免费/付费API | 快速原型、回测验证 |
| Wind | 全市场+历史数据 | 实时 | 昂贵(年费数万) | 机构级、高频交易 |
巨潮资讯网是证监会指定的信息披露网站。说白了,所有上市公司必须在这里发公告。这是最权威的源头,而且免费。我刚开始做策略时,就是靠爬巨潮的数据起家的。
东方财富的数据其实是从巨潮拿的,但它做了二次加工。比如把PDF转成文本、提取关键字段。这对我们做文本分析很有帮助。不过要注意,它偶尔会漏公告或者格式出错。
Wind是机构标配。数据全、接口稳定、售后好。但价格嘛...嗯,个人用户基本不用考虑。我在私募工作时用过Wind的API,确实方便,但每年十几万的费用不是小数目。
2.2 API接口调用实战
我个人最推荐的方式是直接调API。为什么?稳定、高效、不用跟反爬斗智斗勇。
以东方财富的开放平台为例,获取公告列表的代码很简单:
import requests
import json
# 东方财富公告API示例
url = "https://push2.eastmoney.com/api/qt/stock/get"
params = {
"secid": "1.600519", # 贵州茅台
"fields": "f57,f58,f170"
}
headers = {
"User-Agent": "Mozilla/5.0"
}
resp = requests.get(url, params=params, headers=headers)
data = resp.json()
print(data)
你看,几行代码就能拿到实时数据。但这里有个坑——API的调用频率限制。我曾经在回测时没注意限流,直接发了上千个请求,结果IP被封了24小时。嗯,从那以后我都在代码里加上了sleep。
2.3 数据爬虫基础
如果API满足不了你,或者你想爬巨潮这种没有开放接口的网站,那就得用爬虫了。
爬公告数据,核心就三步:
- 找到公告列表页——通常是按日期分页的HTML页面
- 解析公告链接——提取每个公告的详情页URL
- 下载公告内容——一般是PDF或HTML格式
举个例子,爬巨潮的公告列表:
import requests
from bs4 import BeautifulSoup
base_url = "http://www.cninfo.com.cn/new/disclosure"
params = {
"stockCode": "600519",
"pageNum": 1,
"pageSize": 30
}
resp = requests.get(base_url, params=params)
soup = BeautifulSoup(resp.text, 'html.parser')
# 找到所有公告条目
items = soup.select('.announcement-item')
for item in items:
title = item.select_one('.title').text.strip()
link = item.select_one('a')['href']
date = item.select_one('.date').text.strip()
print(f"{date} - {title}")
这里要注意,巨潮的页面结构偶尔会改。我去年就遇到过,某天突然发现爬虫全挂了,排查了半天才发现是CSS类名变了。所以建议你定期检查爬虫是否正常工作。
2.4 数据存储与清洗
数据拿到手,不能直接扔进策略里。公告数据通常很脏,需要清洗。
常见的坑:
- PDF乱码——有些公告是扫描件,OCR识别率低
- 重复公告——同一份公告可能在多个平台出现
- 格式不统一——有的用"万元",有的用"元"
我的做法是:先存成JSON格式,保留原始字段。然后写一个清洗函数,统一处理数值单位、去除空白字符、去重。最后再入库。
# 数据清洗示例
def clean_announcement(data):
# 去除前后空格
data['title'] = data['title'].strip()
# 统一日期格式
data['date'] = data['date'].replace('年', '-').replace('月', '-').replace('日', '')
# 数值单位转换
if '万元' in data['amount']:
data['amount'] = float(data['amount'].replace('万元', '')) * 10000
return data
核心要点:数据源的选择取决于你的预算和需求。个人做策略,巨潮+东方财富完全够用。机构用户可以考虑Wind。爬虫是最后的手段,能用API就别爬。
好了,数据源这块就聊到这儿。你想想看,其实核心就三个问题:数据从哪来、怎么拿、怎么存。搞定了这些,后面的策略分析才有基础。
公众号:蓝海资料掘金营,微信deep3321