Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.
Documents
上市公司年报/研报抓取
Try it上市公司年报/研报自动抓取。覆盖巨潮资讯、东方财富等数据源,支持按公司代码/名称/年份/行业批量下载 PDF。内置反爬绕过、PDF 解析。
What it does
**目标**:通过自然语言指令,自动从东方财富、巨潮资讯、上交所、深交所等权威财经网站获取上市公司年报、季报、研报等 PDF 文档。 **核心能力**:智能数据源路由 + 反爬绕过 + 登录模拟 + 批量下载 + PDF 解析
The skill document
上市公司年报/研报抓取 Skill
目标:通过自然语言指令,自动从东方财富、巨潮资讯、上交所、深交所等权威财经网站获取上市公司年报、季报、研报等 PDF 文档。 核心能力:智能数据源路由 + 反爬绕过 + 登录模拟 + 批量下载 + PDF 解析
架构总览
用户指令 → 参数解析 → 数据源路由 → 抓取执行 → 反爬/登录处理 → 下载存储 → (可选) PDF解析 → 结果交付
依赖模块(复用现有技能)
| 依赖 | 用途 | Skill/工具 |
|---|---|---|
| smart-search | 公司代码/名称查询、公告页面定位 | skills/smart-search |
| scrapling | 反爬绕过(隐身/动态模式) | skills/scrapling-web-scraper |
| Crawl4AI | 深度页面抓取 + 结构化提取 | skills/crawl4ai |
| Firecrawl | 搜索 + 单页抓取降级 | skills/firecrawl-cli |
| web_fetch | Agent 内置抓取降级 | 内置工具 |
| Playwright | 登录态模拟、动态内容等待 | 已安装 |
| PyMuPDF | PDF 解析/文本提取 | 已安装 |
| requests | 原始 HTTP 请求、PDF 下载 | Python 标准库 |
已验证的 API(2026-06-18 实测通过)
巨潮资讯 — 年报/公告 PDF
- 搜索 API:
POST http://www.cninfo.com.cn/new/hisAnnouncement/query- 需要
stock参数格式:{code},{orgId},orgId 格式gssz{code}(深)/gssh{code}(沪) seDate需覆盖发布窗口:{year}-01-01~{year+1}-06-30searchkey精准匹配:{year}年年度报告
- 需要
- PDF 直链:
http://static.cninfo.com.cn/{adjunctUrl} - 反爬: UA 轮换 + 1-3s 随机延迟,无需登录
东方财富 — 行业/个股研报
- 列表 API:
GET https://reportapi.eastmoney.com/report/listqType: 0=个股研报, 1=行业研报, 2=策略报告, 3=宏观研究, 4=券商晨会industryCode: 行业分类 ID(旅游及景区=1272, 酒店餐饮=1271)code: 股票代码(个股研报时用)beginTime/endTime: 日期范围- 返回 JSONP 格式,需剥离 callback 包装
- PDF 直链:
https://pdf.dfcfw.com/pdf/H3_{infoCode}_1.pdf- 无需登录,直接 GET 即可下载
- 需检查 content-type 是否为
application/pdf,防止 404 返回 HTML
- 详情页:
https://data.eastmoney.com/report/info/{infoCode}.html - 反爬: 列表 API 无需登录、无反爬;PDF 直链也无需登录。页面抓取需 Playwright(JS 渲染)
行业代码参考
| 行业代码 | 行业名称 | 行业代码 | 行业名称 |
|---|---|---|---|
| 1272 | 旅游及景区 | 1271 | 酒店餐饮 |
| 420 | 航空机场 | 1268 | 互联网电商 |
| 1287 | 工业金属 | 1238 | IT服务Ⅱ |
| 422 | 物流 | 1221 | 数字媒体 |
支持的数据源(已验证 ✅ 未验证 ❌)
| 数据源 | 年报 | 季报 | 研报 | 反爬强度 | 需要登录 |
|---|---|---|---|---|---|
| 巨潮资讯 (cninfo.com.cn) | ✅ | ✅ | ❌ | 中 | 否 |
| 东方财富 (eastmoney.com) | ✅ | ✅ | ✅ | 低(列表API)/高(页面) | 否(列表+PDF)/部分(页面) |
| 上交所 (sse.com.cn) | ❌ | ❌ | ❌ | 低 | 否 |
| 深交所 (szse.cn) | ❌ | ❌ | ❌ | 低 | 否 |
| 慧博投研 (hibor.com) | ❌ | ❌ | ❌ | 高 | ✅ |
| 萝卜投研 (robo.datayes.com) | ❌ | ❌ | ❌ | 中 | 部分 |
实测验证记录(2026-06-18)
✅ 验证通过:巨潮资讯 + 万科A 历年年报
- 下载 6 份年报 PDF(2019-2024),全部可正常解析
- 关键发现:
stock参数需{code},{orgId}格式(如000002,gssz0000002) seDate需覆盖次年发布窗口(如 2024 年报在 2025 年 4 月发布)category参数过滤过严,改用searchkey精准匹配更可靠- 文件:
downloads/000002_万科A/annual/共 66 MB
✅ 验证通过:东方财富 + 旅游行业研报
- 列表 API 无需登录,直接 GET 返回 JSONP 格式数据
- PDF 直链
pdf.dfcfw.com/pdf/H3_{infoCode}_1.pdf无需登录直接下载 - 下载 5 份 PDF,4 份成功(1 份 PDF URL 无效→需加 404 校验重试)
- 携程集团研报 61 页 / 10.7 MB,内容完整可解析
industryCode参数:旅游及景区=1272, 酒店餐饮=1271- 文件:
downloads/旅游行业研报_PDF/共 14 MB
使用方法
自然语言指令
# 按公司下载
"下载腾讯2025年年报PDF"
"下载贵州茅台2023-2025年所有年报"
"下载平安银行最新季度报告"
# 按行业/批量下载
"下载所有银行板块公司的2024年年报"
"下载沪深300成分股2024年年报(限前10家)"
# 研报抓取
"下载茅台的券商研报,最近3个月"
"抓取东方财富上宁德时代的所有研报"
# 解析提取
"下载腾讯2024年年报并提取财务数据"
"抓取茅台年报PDF,提取营收和净利润"
脚本调用
# 基本下载(巨潮资讯优先)
python3 scripts/financial_report_fetcher.py --stock "000858" --year 2024
# 多公司批量下载
python3 scripts/financial_report_fetcher.py --stocks "000858,600519,000001" --years "2023,2024"
# 指定数据源
python3 scripts/financial_report_fetcher.py --stock "0700.HK" --source eastmoney
# 下载报告类型(年报/季报/半年报/研报)
python3 scripts/financial_report_fetcher.py --stock "600519" --type "annual" --years "2022,2023,2024"
# 仅搜索不下载
python3 scripts/financial_report_fetcher.py --stock "600519" --dry-run
# 下载后解析PDF
python3 scripts/financial_report_fetcher.py --stock "600519" --year 2024 --parse-pdf
# 研报模式
python3 scripts/financial_report_fetcher.py --research --stock "000858" --months 3
核心流程
Phase 1: 参数解析
将自然语言指令转换为结构化参数:
{
"stocks": ["000858", "600519"], # 股票代码
"years": ["2023", "2024"], # 年份范围
"report_types": ["annual"], # annual|semi-annual|quarterly|research
"source": "auto", # auto|cninfo|eastmoney|sse|szse|hibor
"action": "download", # download|search|parse
"parse_fields": [], # 需要提取的PDF字段
"output_dir": "./downloads/", # 输出目录
"max_concurrent": 3, # 并发数
}
Phase 2: 数据源路由(智能降级)
1. cninfo(巨潮资讯) ← 法定披露平台,覆盖最全,无登录要求
↓ 失败或无结果
2. sse.com.cn(上交所) ← 上交所上市公司
↓ 失败或无结果
3. szse.cn(深交所) ← 深交所上市公司
↓ 失败或无结果
4. eastmoney(东方财富) ← 研报+年报,部分需登录
↓ 失败或无结果
5. hibor(慧博投研) ← 研报为主,需登录
Phase 3: 抓取执行(按数据源)
3A. 巨潮资讯(首选,无需登录)
API 接口:
import requests
# 搜索公告
search_url = "http://www.cninfo.com.cn/new/hisAnnouncement/query"
payload = {
"stock": "000858", # 股票代码
"tabName": "fulltext",
"pageSize": 30,
"pageNum": 1,
"column": "szse", # szse/sse
"category": "category_ndbg_szsh", # 年报: category_ndbg_szsh
"seDate": "2024-01-01~2024-12-31",
"searchkey": "年度报告"
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Referer": "http://www.cninfo.com.cn/new/disclosure",
"Content-Type": "application/x-www-form-urlencoded"
}
resp = requests.post(search_url, data=payload, headers=headers)
announcements = resp.json()["announcements"]
# 下载 PDF
for ann in announcements:
adjunct_url = ann["adjunctUrl"] # 如: finalpage/2025-04-01/123456.PDF
pdf_url = f"http://static.cninfo.com.cn/{adjunct_url}"
pdf_resp = requests.get(pdf_url, headers=headers)
with open(f"downloads/{ann['secCode']}_{ann['announcementTitle']}.pdf", "wb") as f:
f.write(pdf_resp.content)
报告类型 category 映射:
- 年报:
category_ndbg_szsh - 半年报:
category_bndbg_szsh - 季报:
category_jdbg_szsh - 招股书:
category_first_szsh
反爬策略:
- 每次请求间隔 1-3 秒随机延迟
- 轮换 User-Agent(5 组常见 UA)
- 使用 Referer 伪装
- 批量下载时并发 ≤ 3
- 如返回 403,启用 Scrapling stealth 模式
3B. 上交所 SSE
API 接口:
# 搜索公告
search_url = "http://query.sse.com.cn/sseQuery/commonQuery.do"
params = {
"jsonCallBack": "jsonpCallback",
"isPagination": "true",
"stockCode": "600519",
"companyCode": "",
"pageHelp.pageSize": 25,
"pageHelp.pageNo": 1,
"pageHelp.beginPage": 1,
"product": "600519",
"bulletintype": "periodic", # 定期报告
"filetype": "PDF",
"sqlId": "common_ssepany_disclosure_info_product_bulletin_index",
"_": int(time.time() * 1000)
}
headers = {
"Referer": "http://www.sse.com.cn/disclosure/listedinfo/announcement/",
"User-Agent": "..."
}
3C. 深交所 SZSE
API 接口:
# 搜索公告
search_url = "https://disc.szse.cn/api/disc/info/ann/twoCategory"
params = {
"random": str(time.time()),
"seDate": "",
"channelCode": "listedNotice",
"bigCategoryId": "category_ndbg_szsh", # 年报
"subBigCategoryId": "",
"stock": "000858",
"pageNum": 1,
"pageSize": 30
}
3D. 东方财富(研报 + 年报)
挑战:部分页面需登录,有反爬机制。
解决方案:
# 方式1:直接 API(无需登录)
research_url = "https://np-anotice-stock.eastmoney.com/api/security/ann"
# 类似 cninfo 的 POST 请求
# 方式2:Scrapling stealth 模式(需要登录/有反爬时)
from scrapling.fetchers import StealthyFetcher
page = StealthyFetcher.fetch(
"https://data.eastmoney.com/report/{stock_code}.html",
headless=True,
solve_cloudflare=False,
timeout=30
)
# 方式3:Playwright 登录态(慧博等需登录平台)
# 见下方"登录态管理"部分
东方财富研报页面解析:
# 研报列表页
url = f"https://data.eastmoney.com/report/{stock_code}.html"
# CSS 选择器提取研报标题、日期、机构、PDF链接
selectors = {
"title": ".report-title a::text",
"date": ".report-date::text",
"org": ".org-name::text",
"pdf_link": "a[href*='.pdf']::attr(href)"
}
3E. 慧博投研(需登录,研报为主)
登录态管理:
from playwright.sync_api import sync_playwright
def login_hibor(username: str, password: str, storage_state: str = "hibor_state.json"):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(storage_state=storage_state if os.path.exists(storage_state) else None)
if not os.path.exists(storage_state):
page = context.new_page()
page.goto("https://www.hibor.com.cn/login")
page.fill("#username", username)
page.fill("#password", password)
page.click("button[type='submit']")
page.wait_for_url("**/user/**", timeout=10000)
context.storage_state(path=storage_state)
return context
Phase 4: 反爬/登录策略矩阵
| 挑战 | 应对方案 | 工具 |
|---|---|---|
| User-Agent 检测 | 轮换 UA 池(5-10组) | requests + 自定义 headers |
| IP 频率限制 | 随机延迟 1-3s + 并发≤3 | time.sleep(random) |
| Cloudflare 验证 | Scrapling stealth 模式 | scrapling |
| 动态加载(JS) | Crawl4AI / Playwright | crawl4ai / playwright |
| 需要登录 | Playwright 登录态持久化 | playwright + storage_state |
| 验证码 | 人工介入提示 + Playwright 截图等待输入 | playwright |
| Cookie 过期 | 自动检测 + 重新登录 | playwright |
Phase 5: 下载与存储
downloads/
├── {公司代码}/
│ ├── annual/
│ │ ├── 2024_{股票简称}_年报.pdf
│ │ └── 2023_{股票简称}_年报.pdf
│ ├── semi-annual/
│ ├── quarterly/
│ └── research/
│ ├── 2026-06_{机构}_{标题}.pdf
│ └── ...
├── metadata.json # 下载元数据记录
└── download_log.md # 本次下载摘要
metadata.json 格式:
{
"downloads": [
{
"stock_code": "600519",
"stock_name": "贵州茅台",
"report_type": "annual",
"year": "2024",
"source": "cninfo",
"file_path": "downloads/600519/annual/2024_贵州茅台_年报.pdf",
"title": "贵州茅台2024年年度报告",
"announcement_id": "12345678",
"download_time": "2026-06-18T10:00:00+08:00",
"file_size_mb": 5.2
}
]
}
Phase 6: PDF 解析(可选)
import fitz # PyMuPDF
def extract_financial_data(pdf_path: str, fields: list = None) -> dict:
"""从年报PDF中提取关键财务数据"""
doc = fitz.open(pdf_path)
text = ""
for page in doc:
text += page.get_text()
doc.close()
# 关键词定位提取
data = {}
patterns = {
"营收": r"营业收入[::]\s*([\d,\.]+)\s*元",
"净利润": r"归属于.*?[::]\s*([\d,\.]+)\s*元",
"总资产": r"资产总计[::]\s*([\d,\.]+)\s*元",
"每股收益": r"基本每股收益[::]\s*([\d,\.]+)\s*元",
"ROE": r"加权平均净资产收益率[::]\s*([\d,\.]+)%",
}
for key, pattern in patterns.items():
match = re.search(pattern, text)
if match:
data[key] = match.group(1)
return data
错误处理
ERROR_CODES = {
"CNINFO_403": "巨潮反爬触发,切换 Scrapling stealth 模式重试",
"CNINFO_EMPTY": "未找到相关年报,检查股票代码/年份是否正确",
"EASTMONEY_LOGIN": "东方财富需要登录,请配置 cookies 或使用 Playwright 登录",
"PDF_DOWNLOAD_FAIL": "PDF 下载失败,尝试备用数据源",
"STOCK_NOT_FOUND": "未找到该公司,使用 smart-search 确认股票代码",
"RATE_LIMIT": "请求过于频繁,等待 10 秒后重试",
}
Agent 集成工作流
用户: "下载贵州茅台2024年年报"
↓
1. 解析 → stock_code=600519, year=2024, type=annual
2. 首选巨潮资讯:
a. POST hisAnnouncement/query 搜索
b. 返回结果 → 提取 PDF URL
c. GET PDF → 保存
3. 巨潮失败 → 尝试上交所
4. 上交所失败 → 尝试东方财富
5. 所有数据源失败 → 报错告知用户
用户: "下载并分析腾讯2024年报的营收结构"
↓
1. 下载 PDF(港股→优先东方财富/港交所)
2. PyMuPDF 提取文本
3. 关键词定位"营业收入"+"分部收入"
4. 返回结构化数据
快速开始
# 1. 安装依赖(已有大部分)
pip3 install requests playwright PyMuPDF
# 2. 安装浏览器(如果未安装)
python3 -m playwright install chromium
# 3. 运行测试
python3 scripts/financial_report_fetcher.py --stock "600519" --year 2024 --dry-run
注意事项
- 合规使用:仅下载公开披露的年报/研报,不用于商业再分发
- 频率控制:巨潮资讯建议 ≤10 次/分钟,东方财富 ≤5 次/分钟
- 登录态安全:cookies 和 storage_state 文件不提交到代码库
- 数据源时效性:年报披露有固定时间窗口(每年 1-4 月年报,7-8 月半年报)
- 港股/美股:需要额外数据源(HKEX披露易、SEC EDGAR)
- 反爬升级:如果巨潮 API 返回结构变化,需要更新 payload 参数
TODO / 扩展方向
- 增加 HKEX 披露易支持(港股年报)
- 增加 SEC EDGAR 支持(美股 10-K/10-Q)
- 增加研报 AI 摘要(用 LLM 自动总结研报观点)
- 增加财报数据对比(多年度趋势分析)
- 增加飞书多维表格存储(自动同步下载记录)
- 增加定时任务(财报季自动监控披露)
创建于:2026-06-18 by 小七 版本:0.1.0(方案设计)
Related skills
Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.
Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.
Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.
Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.
Write, debug, and tune Playwright specs with locator strategy, trace diagnosis, and CI-aware timeouts.
More from tuobadaidai
Browse all skillsConvert fuzzy organizational problems into structured diagnostic reports with graded recommendations.
Convert vague strategic questions into structured analysis with framework selection, audit gates, and explicit trade-offs.
Grade AI-era candidates on a six-dimension L1–L4 scale from resumes and interview notes.
工资数据审核系统,基于确定性规则引擎 + Python 脚本执行。 全量对齐《工资审核标准流程 SOP》6 步流程。v7.2 修复P0阻断bug:_get_pay_month() 支持 中文格式("2026年4月"/"2026年04月"/"202604"),RL-003/RL-007 排除逻辑完全生效。 v7.1...
谛听培训专家。培训需求分析、培训方案设计、效果评估、能力建设。Use when 培训需求分析、培训方案设计、培训效果评估、能力建设体系、管理者赋能、新员工培训、领导力培训、技能培训体系、培训预算规划。不适用于薪酬结构、劳动法合规、绩效考核等非培训类问题。
创建高质量 Skill 的技能。当用户说"创建技能""新建 Skill""把这个流程变成技能""做一个 XX 的 skill""帮我写个技能"时触发。不适用于使用已有技能执行任务——那是 use_skill 的工作。