前言¶
手工收集上市公司财报的典型流程是:打开巨潮资讯网,搜索公司名,筛选公告类型,逐条点开 PDF 下载,再按目录存进本地文件夹或知识库。重复多了以后,主要成本不在下载本身,而在「查哪份报告、存到哪、叫什么名字」这三步的反复确认。
下面介绍的 Skill「财报下载归集」(坐标 @user_f7659217/financial-report-download-collection,版本 1.0.0,社区来源,SkillHub 分类 data-analysis,评分 100000,下载 806)把这条路自动化:用户给出公司名称或股票代码,它先从巨潮资讯网取回财报 PDF,再通过 ima 知识库接口归档到指定文件夹。全程串行,先下载后归档,任一环节失败即停止。
这是什么¶
一个基于通用 SKILL.md 格式的 Agent Skill,定位是「财报抓取 + 知识库归档」两步流水线。发布者 user_f7659217,标签 requires_api_key=true,说明调用外部服务前需要配置凭证。
它解决的是三个具体问题:
- 免手工检索:用
searchkey+seDate一次查全某公司在某时间段内的公告,只保留 PDF 附件。 - 结构化取数:响应 JSON 里直接拿到公告标题、发布时间、大小、下载路径,可以列出候选让用户挑。
- 归档有归属:上传时可指定 ima 知识库和文件夹,并做重名检查。
凭证与依赖配置¶
这个 Skill 不自带下载上传逻辑的完整实现,阶段二依赖 ima-skill 提供封装好的脚本。开始前先把凭证准备好。
凭证来源有两个:环境变量 IMA_CLIENT_ID / IMA_API_KEY,或本地文件。安装说明(从 https://ima.qq.com/agent-interface 获取 Client ID 和 API Key 后写入):
mkdir -p ~/.config/ima
echo "your_client_id" > ~/.config/ima/client_id
echo "your_api_key" > ~/.config/ima/api_key
配置完成后用一条命令确认凭证到位:
test -f ~/.config/ima/client_id && test -f ~/.config/ima/api_key && echo "✅" || echo "⚠️ NO CREDENTIALS"
每次调用阶段二前还需要导出这几个变量:
export IMA_CLIENT_ID=$(cat ~/.config/ima/client_id)
export IMA_API_KEY=$(cat ~/.config/ima/api_key)
export IMA_SKILL_VERSION="1.1.7"
export SKILL_DIR="/workspace/skills/ima-skill"
export IMA_BASE_DIR="$SKILL_DIR"
其中 IMA_SKILL_VERSION 与 SKILL_DIR 指向 ima-skill 的安装位置,ima-skill 需自行安装到该目录,Skill 本身只负责调用。
触发条件¶
当用户消息中出现下列关键词时触发:财报、年报 / 年度报告 / 年度财报、季报 / 季度报告 / 一季报 / 半年报 / 三季报、下载财报 / 下载年报 / 下载季报、上市公司报告。
若用户同时给出公司名称/股票代码与目标文件夹名,直接执行完整流程;信息不全则分步收集。
阶段一:从巨潮资讯下载财报 PDF¶
这一阶段分四步:构造查询、发送请求、解析结果、下载 PDF。入口接口是巨潮资讯的公告全文检索接口:
POST http://www.cninfo.com.cn/new/hisAnnouncement/query
Content-Type: application/x-www-form-urlencoded
核心参数:
| 参数 | 值 | 说明 |
|---|---|---|
pageNum |
1 |
页码 |
pageSize |
30 |
每页条数 |
tabName |
fulltext |
全文搜索模式 |
searchkey |
{公司名/代码} {报告类型关键词} |
空格分隔多词 |
seDate |
可选,如 2024-01-01~2025-12-31 |
限定公告日期范围 |
报告类型关键词映射:年报 → 年度报告,一季报 → 第一季度报告,半年报 → 半年度报告,三季报 → 第三季度报告,未指定时默认 年度报告。
以搜索平安银行 2024 年年度报告为例:
curl -s -X POST "http://www.cninfo.com.cn/new/hisAnnouncement/query" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "pageNum=1" \
--data-urlencode "pageSize=30" \
--data-urlencode "tabName=fulltext" \
--data-urlencode "searchkey=平安银行 年度报告" \
--data-urlencode "seDate=2024-01-01~2025-06-01"
响应是 JSON,公告列表在 announcements[],每条包含 secCode、secName、announcementId、announcementTitle、announcementTime(Unix 毫秒)、adjunctUrl(PDF 相对路径,拼下载地址的核心字段)、adjunctSize、adjunctType。解析时筛选 adjunctType=PDF 且标题匹配报告类型的条目。
若 totalAnnouncement > 1,列出候选报告(标题、日期、大小)让用户选择,可输入序号或输入「全部」。只有一条匹配时直接进入下载。
下载 URL 为 http://static.cninfo.com.cn/{adjunctUrl}:
TMP_DIR=$(mktemp -d)
PDF_NAME="{公告标题}.pdf"
curl -sL -o "$TMP_DIR/$PDF_NAME" "http://static.cninfo.com.cn/{adjunctUrl}"
下载后验证文件存在且大小大于 0:
test -s "$TMP_DIR/$PDF_NAME" && echo "✅ 下载成功: $(ls -lh "$TMP_DIR/$PDF_NAME" | awk '{print $5}')" || echo "❌ 下载失败"
失败即终止流程并报告原因。这一步把 PDF 落到临时目录,阶段一才算完成。
阶段二:上传 PDF 至 ima 知识库¶
阶段一完全成功后才启动。同样分步执行,用到的脚本都在 ima-skill 里。
Step 5 前置检查,用 ima-skill 的 preflight 脚本校验文件,返回 pass=false 就终止:
PREFLIGHT=$(node "$SKILL_DIR/knowledge-base/scripts/preflight-check.cjs" --file "$PDF_FILE")
echo "$PREFLIGHT"
从返回 JSON 里提取 file_name、file_size、media_type、content_type、file_ext 供后续步骤使用。
Step 6 获取知识库 ID。用户指定了知识库名称时用搜索接口匹配:
ima_api "openapi/wiki/v1/search_knowledge_base" '{"query":"{知识库名称}","cursor":"","limit":20}'
未指定时列出可添加的知识库供用户选择,只有一个就自动选择。
Step 7 定位目标文件夹。用户给了文件夹名就在知识库里搜:
ima_api "openapi/wiki/v1/search_knowledge" "{
\"query\": \"{文件夹名称}\",
\"knowledge_base_id\": \"{kb_id}\",
\"cursor\": \"\"
}"
从 info_list 里筛 media_id 以 folder_ 开头的条目,取到即作为 FOLDER_ID;找不到就告知用户文件夹不存在,改上传到根目录(后续不传 folder_id)。未指定文件夹时跳过此步。
Step 8 先查重名,再创建媒体,最后做 COS 上传。重名检查:
ima_api "openapi/wiki/v1/check_repeated_names" "{
\"params\": [{\"name\": \"$FILE_NAME\", \"media_type\": $MEDIA_TYPE}],
\"knowledge_base_id\": \"{kb_id}\"
${FOLDER_ID:+, \"folder_id\": \"$FOLDER_ID\"}
}"
is_repeated=true 时在文件名后追加时间戳。接着创建媒体拿到 media_id 和临时 COS 凭证:
CREATE_RESP=$(ima_api "openapi/wiki/v1/create_media" "{
\"file_name\": \"$FILE_NAME\",
\"file_size\": $FILE_SIZE,
\"content_type\": \"$CONTENT_TYPE\",
\"knowledge_base_id\": \"{kb_id}\",
\"file_ext\": \"$FILE_EXT\"
}")
响应 code 非 0 即终止。从响应中提取 secret_id、secret_key、token、bucket_name、region、cos_key、start_time、expired_time,再调用 COS 上传脚本:
node "$SKILL_DIR/knowledge-base/scripts/cos-upload.cjs" \
--file "$PDF_FILE" \
--secret-id "{secret_id}" \
--secret-key "{secret_key}" \
--token "{token}" \
--bucket "{bucket_name}" \
--region "{region}" \
--cos-key "{cos_key}" \
--content-type "$CONTENT_TYPE"
上传完成后还有 Step 9「添加知识」,把已上传的媒体登记进知识库,随后向用户报告结果并清理临时文件。这一步的具体接口调用未在官方资料中展开,实际使用前需以 ima-skill 内封装的脚本为准。
交互边界与失败处理¶
官方资料给了一张缺项处理表,逻辑是一致的:缺公司名/代码就追问;缺报告类型默认最新年度报告;缺目标文件夹就上传到根目录;搜索到多条匹配就列候选让用户选;目标文件夹不存在就告知并退回根目录;凭证没配就引导先配置。
三条硬规则值得单独记:
- 串行执行,不可并行。阶段二的任何步骤必须在阶段一完全成功之后启动。
- 出错即停。任一环节失败立即终止并报告原因,不做补救性跳过。
- 仅输出一个 SKILL.md。不产生 api.md、示例 PDF 等附属文件。
适用场景与限制¶
适合需要把上市公司财报批量收进 ima 知识库的场景,例如按季度拉取一组标的的定期报告、做跨公司财报语料归档。触发词覆盖年报、季报、半年报,默认走年度报告。
限制主要有两点。一是只支持巨潮资讯网这个数据源,allowed_domains 限定为 www.cninfo.com.cn、static.cninfo.com.cn、ima.qq.com、*.myqcloud.com,不涉及港美股或新三板公告。二是它不自带上传实现,阶段二完全依赖 ima-skill 及其 ima_api.cjs、preflight-check.cjs、cos-upload.cjs 脚本,ima-skill 没装好或版本不对,归档这一步就跑不起来。另外当前 SkillHub 显示安装数为 0,属于发布初期,建议先小范围试一次完整流程再推广。
结尾¶
这个 Skill 的价值在于把「检索巨潮公告 + 下载 PDF + 归档 ima」这条重复链路收敛成一条串行流水线,输入只要公司名或代码,中间的候选确认、重名处理、文件夹定位都按既定规则走。官方地址:https://api.skillhub.cn/user_f7659217/financial-report-download-collection ,SkillHub 页面:https://www.skillhub.cn/skills/user_f7659217/financial-report-download-collection 。