4. 公告新闻数据获取

事件抽取与事件研究的第一步不是建模,而是把“事件”从原始信息流中稳定地拿回来。上市公司公告、交易所新闻与财经媒体构成了三类互补的数据源:公告是法定披露、结构相对规范、权威性最高;交易所新闻带有监管与市场提示属性;财经媒体则时效快、覆盖面广,但噪声与重复也最多。本节围绕这三类来源,讲清数据来源、采集方法与合规边界。

一、核心原理:三类数据源的分层结构

理解数据获取,关键是理解它们的“生成—发布—传播”链路。上市公司公告由公司通过交易所信息披露系统提交,经交易所审核后发布,具有明确的公告编号、标题、类型与时间戳;交易所新闻由交易所或监管机构发布,常涉及监管问询、纪律处分、交易提示;财经媒体内容则由记者、编辑或自动化系统生产,转载、改写、标题党现象普遍。三者的权威性、结构化程度与时效性并不一致,采集策略也应分层。

公告新闻数据获取的三层来源与采集通道 上市公司公告 交易所披露系统 / 巨潮资讯 公告编号 · 类型 · PDF/HTML 权威性高 · 结构较规范 交易所新闻 监管问询 · 纪律处分 · 交易提示 官网栏目 / RSS / 公告栏 监管属性强 · 更新有节奏 财经媒体 门户 · 财经App · 公众号 标题 · 正文 · 发布时间 时效快 · 噪声与重复多 统一采集与清洗层 去重 · 时间对齐 · 字段标准化 · 正文抽取 事件抽取与事件研究输入 事件类型 · 主体 · 时间 · 情感 · 影响窗口

二、方法流程:从来源到可用数据的采集链路

无论哪类来源,采集链路都可以抽象为“发现—抓取—解析—清洗—存储”五步。发现阶段要确定入口:公告可用交易所披露页或巨潮资讯的按日期、按公司检索;交易所新闻可用官网栏目页或 RSS;财经媒体可用栏目页、搜索页或 API。抓取阶段要处理分页、动态渲染与反爬;解析阶段要把 HTML/PDF 转成结构化字段;清洗阶段要统一时间格式、去除转载重复、补全股票代码;存储阶段建议保留原始快照与解析结果两套数据。

下面是一个最小可用的公告列表抓取示例,重点在于保留原始链接与发布时间,便于后续回溯:

import requests, time, hashlib, json
from bs4 import BeautifulSoup

HEADERS = {"User-Agent": "Mozilla/5.0 (compatible; ResearchBot/1.0)"}
BASE = "https://www.cninfo.com.cn/new/hisAnnouncement/query"

def fetch_announcements(page=1, page_size=30):
    payload = {
        "pageNum": page,
        "pageSize": page_size,
        "column": "szse",
        "tabName": "fulltext",
        "plate": "",
        "stock": "",
        "searchkey": "",
        "secid": "",
        "category": "",
        "trade": "",
        "seDate": "2024-01-01~2024-01-31",
        "sortName": "",
        "sortType": "",
        "isHLtitle": "true"
    }
    r = requests.post(BASE, data=payload, headers=HEADERS, timeout=15)
    r.raise_for_status()
    return r.json().get("announcements", [])

def normalize(item):
    return {
        "ann_id": item.get("announcementId"),
        "title": item.get("announcementTitle"),
        "sec_code": item.get("secCode"),
        "sec_name": item.get("secName"),
        "time": item.get("announcementTime"),
        "url": "https://static.cninfo.com.cn/" + item.get("adjunctUrl", ""),
        "hash": hashlib.md5((item.get("announcementTitle","") + str(item.get("announcementTime"))).encode()).hexdigest()
    }

records = []
for p in range(1, 4):
    for it in fetch_announcements(p):
        records.append(normalize(it))
    time.sleep(1.2)

with open("announcements.jsonl", "w", encoding="utf-8") as f:
    for r in records:
        f.write(json.dumps(r, ensure_ascii=False) + "\n")
print("saved", len(records))

财经媒体采集通常更复杂,因为页面结构变化频繁。建议优先使用官方 API 或 RSS;若必须解析 HTML,应把“列表页字段”和“详情页正文”分开处理,并对正文做去广告、去推荐位、去版权声明的清洗。

三、案例/场景:一次“业绩预告”事件的采集复盘

假设我们要研究某公司发布“业绩预告”后三日的市场反应。公告侧,我们从巨潮按股票代码与日期区间检索,拿到公告标题、发布时间与 PDF 链接;交易所新闻侧,检查是否有问询或关注函;媒体侧,抓取主流财经媒体在公告后 24 小时内的报道。实际执行中常见的情况是:公告 16:30 发布,媒体 16:45 转载,交易所新闻次日才出现。若只按“新闻发布时间”对齐,事件窗口会整体后移,导致研究结论偏差。因此,事件时间应以“首次权威披露时间”为准,媒体时间作为传播强度变量。

建议为每条记录保留 source_type(公告/交易所/媒体)、publish_time、first_seen_time、url、content_hash 五个字段,便于去重与时间对齐。

四、误区与合规注意事项

第一个误区是“抓到就算数”。公告 PDF 中的表格、附件与正文往往包含关键信息,只抓标题会漏掉业绩区间、交易金额等要素。第二个误区是忽视重复:同一公告可能被多家媒体改写,若不去重,事件会被重复计数。第三个误区是时间字段混用:公告时间、采集时间、媒体发布时间含义不同,必须分开存储。

合规方面,需重点关注以下几点:

  • 遵守 robots.txt 与网站服务条款,不绕过登录、验证码或付费墙;
  • 控制请求频率,设置合理间隔与并发上限,避免对目标站点造成压力;
  • 不采集、不传播内幕信息或未公开重大信息,不将采集数据用于交易操纵;
  • 尊重著作权,媒体正文仅用于研究分析,不对外全文转载;
  • 保存采集日志与原始快照,便于审计与结果复现。
若采集范围涉及个人信息或非公开数据,应重新评估合法性;涉及金融交易信号的研究,还需符合所在机构与监管的合规要求。
数据源 典型入口 关键字段 主要风险 建议频率
上市公司公告 交易所披露系统、巨潮资讯 公告编号、标题、类型、时间、PDF PDF 解析难、附件遗漏 每日增量 + 历史回补
交易所新闻 交易所官网栏目、RSS 标题、栏目、发布时间、正文 栏目改版、更新不规律 每日 2–4 次
财经媒体 门户财经、财经App、公众号 标题、正文、作者、发布时间 重复转载、标题党、反爬 按需 + 事件触发

把来源分层、把时间对齐、把合规前置,公告新闻数据获取才能成为事件抽取与事件研究的可靠底座,而不是后续误差的来源。