年报财务数据提取

SKILL效率
效率 未标注权限 许可证不明确
安装这个技能

从上市公司年度报告PDF中提取三大综合财务报表(损益表、资产负债表、现金流量表), 自动完成数据解析、单位换算、勾稽关系验证,生成带同比标注的HTML可视化报告。 触发场景:(1) 提取年报财务数据 (2) 批量解析财务报表PDF (3) 生成财务报表对比分析报告 (4) 验证资产负债表等式与现金流勾稽关系 (5) 财务数据可视化呈现。 支持港股/美股中英双语年报格式,可通过模板配置扩展支持新公司。 A股支持已验证(2026-08-19 完成东鹏饮料 605499.SH 5 年合并报表提取),详见 A股年报处理指南.md。

一句话选型结论

按资料字段整理

年报财务数据提取是效率类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类效率 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_bf2a403c/sy-investment-arextract
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

效率
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_bf2a403c仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791625602
正文体量30.6 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
整理待办与日程

把零散任务收进清单,排出优先级。

批量处理重复任务

把固定动作做成模板,重复执行。

把流程写成清单

把口头流程整理成可复用的步骤。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在效率场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
年报财务数据提取当前 未标注权限 未标注 未标注 未标注 有
Nano PDF 文档 联网访问 ClawHub 市场 424.9 万 OpenClaw 有
自动更新程序 浏览器控制 ClawHub 市场 296.4 万 OpenClaw 有
Gemini 助手 联网访问 ClawHub 市场 254.7 万 OpenClaw 有
word DOCX 文档 联网访问 ClawHub 市场 239.6 万 OpenClaw 有
Excel XLSX 前端 联网访问 ClawHub 市场 227.0 万 OpenClaw 有

SKILL.md 全文

30.6 KB
模型实际读到的说明书原文,来自技能仓库

年报财务数据提取

概览

从年报 PDF 中自动化提取结构化财务数据,历经 文本提取 → 清洗 → 解析 → 核查 → 换算 → 输出 六阶段流程。核心输出为带同比标注的 HTML 报告(亿元为单位,红涨绿跌)。

架构(v2 起采用"通用引擎 + 公司模板"分离设计):

skills/年报财务数据提取/
├── SKILL.md                          ← 本文档(含异常情况库 + 接入指南)
├── scripts/
│   ├── generate_report.py            ← v1 单公司脚本(Pop Mart 版,参考实现)
│   └── generate_report_v2.py         ← v2 通用引擎(从模板加载配置)
└── templates/
    ├── _schema.json                  ← 模板字段规范(JSON Schema)
    ├── _default_hk.json              ← 港股默认模板(新公司接入起点)
    ├── nongfu_spring.json            ← 农夫山泉 09633.HK 模板
    └── popmart.json                  ← Pop Mart 09992.HK 模板

核心设计原则:
1. 公司特定逻辑(页眉过滤词、报表标题、BS结构、文本顺序)全部下沉到 JSON 模板
2. 解析引擎对所有公司通用,不包含任何 if company == 'xxx' 分支
3. 新公司接入 = 新增一个 JSON 模板文件,无需修改引擎代码


六阶段流程

阶段一:PDF 文本定位与提取

目标:精准定位三大报表所在页面,提取文本层数据。

# 1. 搜索报表标题关键词定位页码(用英文标题最稳定)
pdfkit.py search_text --input YEAR年报.pdf --find "PROFIT OR LOSS" --engine pymupdf
pdfkit.py search_text --input YEAR年报.pdf --find "FINANCIAL POSITION" --engine pymupdf
pdfkit.py search_text --input YEAR年报.pdf --find "CASH FLOWS" --engine pymupdf

# 2. 排除目录/章节引言页,取最前面的"报表标题页"
#    验证:单页提取后内容首行应为报表中文标题(如"綜合損益表")
# 3. 提取范围:[损益表起始-1, 损益表起始+8](10页,含缓冲,覆盖三大表+权益变动表)
pdfkit.py extract_text --input YEAR年报.pdf --pages "[107,108,109,110,111,112,113,114,115,116]" \
  --format text --output YEAR_financial.txt

注意:pdfkit search_text 返回的 page 字段与 extract_text --pages 接受的索引基准一致
(两者都用同一编号系统,可直接复用)。--pages 接受 0-based 索引数组,需显式列出所有页号。

  • 只提取文字层,非扫描件不需要 OCR
  • 如遇加密 PDF,先 pdfkit.py decrypt 解密
  • 港股年报关键词:PROFIT OR LOSS / FINANCIAL POSITION / CASH FLOWS(用英文最稳)
  • A股年报关键词可能为:利润表 / 资产负债表 / 现金流量表

阶段二:文本行清洗(clean_lines)

目标:移除页眉页脚、保留所有数据行。

规则:
1. 移除 "--- Page N ---" 页面标记 → 替换为 '---PAGE---' 内部标记
2. 移除公司名、年报标题行(从模板 header_filters 加载)
3. 移除核数师报告干扰行(auditor_lines + auditor_signatures)
4. 移除 "Note"/"附註"、"RMB'000"/"人民幣千元" 等纯标记行
5. 保留空行作为条目分隔符
6. 【关键】不删除 1-3 位纯数字行 ← 这是 note 编号和小数值,曾导致大规模数据丢失
7. 仅移除单独出现的页码数字(紧跟 ---PAGE--- 的行)

阶段三:结构化解析(parse_statement_lines)

目标:将文本行组装为 {name_en, name_zh, note, value_current, value_previous} 结构化条目。

文本格式模式(双向兼容)

模板的 text_order 字段决定文本收集顺序:

模式 A: en_first(先英文后中文,如 Pop Mart)
  Revenue              ← 英文科目名(可能跨多行)
  收益                 ← 中文科目名(可能跨多行)
  5                    ← 附注编号
  2,513,471            ← 当年值
  1,683,434            ← 上年值

模式 B: zh_first(先中文后英文,如农夫山泉)
  收益                 ← 中文科目名
  REVENUE              ← 英文科目名
  5                    ← 附注编号
  22,877,297           ← 当年值
  24,021,041           ← 上年值

模式 C: auto(自适应,推荐用于新公司)
  解析器检测当前行 is_pure_chinese,自动选择先中文或先英文

解析器关键规则

  1. 数字行判断:匹配 \(?\d[\d,]*\)? 的模式,同时接受 – / — / -(破折号 = 零值/不适用)
  2. 附注编号识别:仅 1-2 位纯数字或带字母后缀(如 34(a)),也接受逗号分隔多引用(如 16, 34(c)、5,8);3 位以上数字一律当作数值。字母后缀放宽为 [a-z]{1,4}(如 20(vii),小米 1810.HK 实测)——单字母正则 \([a-z]\) 会漏掉多字母附注导致科目名被污染。
  3. 节标题识别:模板 section_header_keywords 集合(小写精确匹配)标记 is_section_header=True
  4. 合计行识别:含 total 或 總 关键词的科目标为 is_total=True
  5. 多行名称合并:英文/中文名跨行时,通过空白行前后的语言特征判断连续性

阶段四:数据核查(强制)

按模板 balance_sheet_validation.type 选择验证策略:

4.1 资产负债表等式验证

类型 A: assets_eq_liab_plus_equity(标准结构,有 Total assets 行)
  验证: Total assets == Total liabilities + Total equity
  适用: A股、美股、Pop Mart 等多数公司

类型 B: net_assets_eq_equity(总资产减流动负债列示,无 Total assets 行)
  验证: 非流动资产 + 流动资产 - 流动负债 - 非流动负债 = 净资产 = 权益总额
  适用: 农夫山泉等部分港股

4.2 损益表连贯性验证

验证项:综合收益总额 == 净利润 + 其他全面收益(近似验证)
说明:因归属拆分可能存在微小舍入差异,允许 1% 以内偏差

4.3 现金流与资产负债表交叉验证

验证项:现金流量表期末现金 vs 资产负债表现金科目
查找策略:按模板 cash_item_aliases 候选列表逐个 fallback 查找
  - 2020年农夫山泉: "Cash and cash equivalents"
  - 2021+年农夫山泉: "Cash and bank balances"(会计政策变更后)
异常处理:
  1. 两者相等 → ✓ 通过
  2. CF表内有"as stated in the statement of financial position"调节项且等于BS现金 → ✓ 经调节后通过
  3. 差额 = BS 中的 "Long-term bank deposits" → ⚠️ 提示长期存款调节项
  4. 其他情况 → ⚠️ 提示差额,建议人工核查 CF 表分析段

4.4 异常波动预警

触发条件:同比变动 > 30%
预警动作:在报表中标注 "⚠️ 变动 >30%"
检查项:排除 IPO 融资、重大并购、会计准则变更等合理原因
行业偏离检测:与行业均值偏离 > 50% 时启动人工复核

4.5 数据缺失处理

单年缺失:该格显示 "-",邻近年份有值时标记 "⚠️ 数据待补"
跨年口径不一致:
  - 同名科目取最早出现年份的命名
  - 新增科目在无数据的年份显示 "-"
  - 科目名变更在备注栏标注 "原名: XXX"
  - 现金等关键科目用 cash_item_aliases 候选列表 fallback 查找

阶段五:单位换算

默认流程:原始数据为 RMB'000(千元)→ 除以 100,000 → 亿元(保留 2 位小数)

def to_yi(val):
    """千元 → 亿元: val / 100000"""
    return val / 100000 if val is not None else None
  • 列标题同步更新为"人民币亿元"
  • 同比百分比和变动金额同步换算

阶段六:HTML 报告生成

输出结构:按年份分组,每年依次呈现三张报表。

表格布局

| 科目名称         | 2020年         | 2019年         |
|-----------------|----------------|----------------|
| 物业厂房设备     | 2.38           | 1.04           |  ← 数据行
|                 | ▲ 130.1%       | -              |  ← 同比%行
|                 | +1.34          | -              |  ← 变动金额行(BS专有)
|                 | 0.6%           | -              |  ← 占比行(蓝,BS置于变动金额下方)

占比指标规范(2026-09-09 港交所项目新增,用户确认)

范围:仅综合损益表与综合资产负债表默认加占比;综合全面收益表、现金流量表默认不加。

分母口径:
- 损益表:各科目当年值 ÷ 当年营业总收入(港交所口径为"收入及其他收益";A股即"营业总收入")。每股盈利(EPS)行不出占比。
- 资产负债表:三段各自独立——资产段科目 ÷ 资产总额、负债段科目 ÷ 负债总额、权益段科目 ÷ 权益总额。
- 不出占比的行:合计行(总资产/总负债/权益总额/负债及权益总额——自身恒为 100%)与信息行(如流动资产净值——非构成项)。

呈现位置与样式:
- 当年列小字区最底部:损益表为 数据→同比→占比;BS 为 数据→同比→变动金额→占比(用户确认:BS 中占比紧邻变动金额下方)。
- 字体字号与同比行完全一致(13px),文字颜色蓝色 #1e6091。
- 格式:一位小数 xx.x%;负占比沿用括号风格 (x.x%)。
- HTML 报告的口径说明区须注明占比分母口径,避免日后回看歧义。

颜色规范(中国A股惯例)

同比变动方向基于绝对值变动判断(使收入增长和成本增长均显示为红色):

  • 变动方向 = abs(curr) > abs(prev) → 增长 → 红色 #e17055 ▲
  • 变动方向 = abs(curr) < abs(prev) → 减少 → 绿色 #00b894 ▼
  • 符号翻转特殊处理:
  • prev > 0, curr < 0(正→负)→ 强制减少 → 绿色 ▼
  • prev < 0, curr > 0(负→正)→ 强制增长 → 红色 ▲
  • 合计行背景:淡蓝色 #e8f4fd
  • 数据值颜色:各科目(含开支类)数据值统一为黑色,不再用蓝色区分开支类(2026-09-09 用户确认取消"蓝开支")。支出仍以括号 ( ) 表示负数。

字号与字体

  • 数据数值:16px,DIN 字体系列
  • 合计行:17px 加粗
  • 同比注释:13px(常规字重,不加粗)
  • 变动金额:12px(常规字重,不加粗)
  • 占比行:13px(与同比完全一致),蓝色 #1e6091(常规字重,不加粗)

> 注:同比、占比、变动金额三类小字不加粗(2026-09-09 用户确认取消加粗,与数据行靠字号差异区分层次)。


异常情况分类与处理策略

类别一:数据格式不一致

异常 触发场景 处理策略 模板字段
文本顺序差异 Pop Mart 先英文后中文;农夫山泉先中文后英文 解析器双向兼容,模板 text_order 字段控制 text_order: en_first/zh_first/auto
报表标题命名差异 港股 BS 可能叫"綜合財務狀況表"或"資產負債表" 模板 statement_titles 配置多个候选关键词 statement_titles.{表}.start_keywords[]
损益表与OCI是否合并 Pop Mart 合并(一张表);农夫山泉分开(两张表) 模板 income_includes_oci 控制;extract_income 的结束关键词设为 BS 起始 income_includes_oci: true/false
页眉页脚差异 不同公司年报页眉含不同公司名、年报标题格式 模板 header_filters 集中配置所有过滤词 header_filters.*

类别二:字段缺失与结构差异

异常 触发场景 处理策略 模板字段
BS 无 Total assets 行 农夫山泉采用"总资产减流动负债"列示 模板 balance_sheet_style: net_assets,验证逻辑切换为净资产等式 balance_sheet_style + balance_sheet_validation.type
节标题关键词差异 不同公司节标题措辞略有不同 模板 section_header_keywords 集合配置 section_header_keywords[]
董事签名干扰 BS 末尾常有董事签名(中英文) 模板 director_signatures 列表,解析时跳过 director_signatures[]
核数师报告末页干扰 损益表前一页是核数师报告末页,含审计师姓名/日期/责任段 模板 auditor_lines + auditor_signatures 双重过滤 header_filters.auditor_lines/signatures

类别三:跨年会计政策变更

异常 触发场景 处理策略 模板字段
现金科目名跨年变更 农夫山泉 2020 用 "Cash and cash equivalents",2021+ 拆分为 "Cash and bank balances" + "Long-term bank deposits" 模板 cash_item_aliases 候选列表,按优先级 fallback 查找 cash_item_aliases[]
CF 期末现金 ≠ BS 现金 因含长期/三月以上定期存款等调节项 CF 表末尾"結餘分析"段做调节;验证逻辑识别 Long-term bank deposits 等调节项 cashflow_reconciliation_keyword
新增/取消科目 业务范围变化导致科目增减 数据缺失处理:无数据年份显示 "-",邻近年份有值时标记"⚠️ 数据待补" (内置逻辑)

类别四:PDF 提取层异常

异常 触发场景 处理策略
扫描件无文字层 旧年报或部分页是扫描图片 pdfkit.py extract_text --ocr_fallback 启用 OCR
文字层乱码(CID 映射损坏) 字体 ToUnicode 缺失,提取出"伪汉字"(如「䌪䪍㟺㔺ⷭ」)而非 \ufffd 替换符;数字通常仍正常 文字层提取全部失效 → 走 OCR 兜底(见「类别八」);页码用 PDF 书签定位
加密 PDF 部分年报有密码保护 pdfkit.py decrypt 先解密
跨页表格断裂 一张表跨 2-3 页,中间有页眉页脚 clean_lines 已处理,保留空行作分隔符
页码索引基准混淆 pdfkit search_text 返回的 page 与 extract_text --pages 索引基准 两者用同一编号系统,可直接复用;但 --pages 接受 0-based 数组,需显式列出所有页号

类别五:解析器边缘情况

异常 触发场景 处理策略
clean_lines 误删 1-3 位数字 股本、note 编号等被当作页码删除 不删除纯数字行,改为解析器上下文判断
破折号 "–" 未被识别为值 含零值科目整行被跳过 is_number_or_dash 接受 –/—/-
3 位数字被当作 note 编号 减值拨回科目数值错位 is_note_line 仅匹配 1-2 位数字;字母后缀放宽为 [a-z]{1,4}(^\d{1,2}(\([a-z]{1,4}\))?$,支持 20(vii)),逗号多引用 ^\d{1,2},\s*\d{1,2}(\([a-z]{1,4}\))?$
带逗号数值被误判为"逗号分隔多附注" 3,873 等数值被当作 note 跳过 逗号分隔 note 要求两段均≤2位:^\d{1,2},\s*\d{1,2}(\([a-z]\))?$
BS/CF 末尾注释行被解析为条目 "The above consolidated balance sheet..."、以上綜合資產負債表、以上綜合現金流量表應與隨附附註 及后续董事签名、页码被误解析 extract 阶段遇到上述注释关键词即 break 停止(v1 与 v2 均已内置;模板 end_keywords 亦建议加入)
跨行中文名被空白行截断 联营公司投资等科目英文名残留 空白行 + 前瞻纯中文检测 → 继续合并
逗号分隔多附注未被识别 现金流量表租赁负债付款被命名为 "16, 34(c)" is_note_line 增加 ^\d{1,2},\s*\d+(\([a-z]\))?$ 匹配
单位换算 ÷10000 数值放大 10 倍 千元 → 亿元 = ÷100000(不是 ÷10000)
'資產' in zh 子串匹配 无形资产等误渲染为节标题 改用 is_section_header 精确标志

类别六:招股书附录一(会计师报告)vs 年报(2026-09-09 蜜雪招股章程实测)

招股书历史财务资料与年报结构差异大,v2 引擎不适用,需独立多栏解析器(参考实现:E:/AIstorage/investment/mxjt/mixue/build_prospectus.py):

  1. 多期间多栏布局:损益/OCI/CF 为 5 列(3 个年度 + 2 个 9M 期间),BS 为 4 列;数值可能一行多个或一行一个,按 token 流收集。行完成判据 = "首位是附注则需 ncols+1 个 token,否则 ncols 个"。
  2. 附注编号带字母:如 15(a)/15(b)/15(c),需并入 token 数字类集合,否则被当作文字行导致空科目。
  3. 无科目名的孤立数值行:PDF 文本层小计行常无标签(如 CF"税前利润经调整后"、P&L"应占利润合计"、BS"母公司拥有人应占权益合计"),需按上下文补名,勿丢弃。
  4. 点线引导符可能只有单个「.」(如「扣除税項 .」),DOTS 正则放宽为 1 个以上 (\s*\.\s*){1,}$。
  5. 科目查找必须全名精确匹配:「流動資產總值」是「非流動資產總值」的子串、「資產淨值」是「流動資產淨值」的子串,子串匹配会取错行。
  6. 独立表头行(非流動資產/權益/以下各方應佔:等)与多行科目名前缀难区分,用精确表头名单先行切分。
  7. 每股收益单位为人民币元(非千元),不能 ÷100000。
  8. 校验仍全部适用且推荐:BS 等式、P&L 利润勾稽、OCI 勾稽、CF 期初+净增+汇兑=期末、CF 期末现金=BS 现金(仅年度列可比,9M 列 BS 无对应时点)。

类别七:港交所式多栏 BS 年报(2026-09-09 香港交易所 00388 六年实测)

港交所(及部分采用同款列示方式的港股公司)年报结构与 v2 引擎假设差异大,需专用解析器。参考实现:E:/AIstorage/investment/gjs/hkex/parse_hkex.py(解析+验证)+ render_hkex.py(HTML)。

  1. 六列 BS:綜合財務狀況表每科目为"流動/非流動/合計 × 当年/上年"6 值,权益段仅"合計"2 值;段标记行「資產/負債/股本權益」切换值数期望。行级附注判定:值 token 数 = 期望值数+1 → 首 token 为附注。
  2. 中文单语 + 百萬元:中文报表在 PDF 独立区段(2020 年报在 p128-134 区段);单位"百萬港元"→ 亿元 = ÷100;EPS 形如 "9.11元" 须保持字符串不换算。
  3. 两列表附注计数规则:值 token 数==3 且首位为 1-2 位纯数字 → 首位是附注(如「收入 5 16,835 13,565」「香港交易所股東 46 11,505 9,391」「就非控股權益行使的出售選擇權所支付款項 39 (51) –」——末例首位 39 实为附注,已用财务活动净流出勾稽验证)。
  4. 停止标志禁忌:2023+ 年报把"(非HKFRS計量項目)"标注移入 CF 表内首行,"非HKFRS"不能用作停止标志;安全标志为「主要業務活動之現金流量」(带右引号」)、「以上綜合」、「綜合財務報表附註」。
  5. 表头年份粘连:y 聚类后表头年份行成单 token("20232022"),用 re.fullmatch(r'(\d{4})+', text) 过滤;「附註」「百萬元」表头行整行过滤。
  6. 科目名逐年微调:其他全面收益╱(虧損)→ 其他全面(虧損)╱收益;折舊及攤銷 → 折舊、攤銷及減值;EBITDA → EBITDA(非HKFRS計量項目)。验证与查找用前缀匹配(startswith('其他全面'))而非全等/子串(防"以公平值計量及列入其他全面收益的財務資產…"误配)。
  7. 无名值行:P&L「(4,439) (3,997)」为營運支出總額(前条目为其他營運支出时补名);CF「現金及等同現金項目分析」段末确认行与期末现金重复 → 丢弃。
  8. CF 与 BS 现金口径差:CF 期末现金是公司自有资金口径,BS「現金及等同現金項目」含结算参与者保证金相关现金(差额约 1,160亿–1,700亿港元),非错误,勾稽说明须解释(附註21 分析段)。
  9. 推荐解析架构:PyMuPDF get_text("words") + y 坐标聚类(容差 4pt)成逻辑行 → 行级 token 状态机;比纯文本流更抗列错位。附注样式 note_like:含数字且无中文且匹配 [\d,()\[\]a-z\-–]+。
  10. 勾稽验证集(六年 66 项全通过):BS 等式(两年)×2、损益(溢利=除税前+税项;EBITDA=收入减支出+营运支出总额;营运溢利=EBITDA+折旧摊销;除税前=营运溢利+区间中间项求和)、全面收益(總額=溢利+其他全面收益)、CF(期初+净变动+汇兑=期末)。

类别八:文字层乱码年报 → OCR 兜底(小米 1810.HK 五年实测,2026-09-09)

触发场景:PDF 有文字层但字体 ToUnicode 映射损坏,中英文提取为"伪汉字"(如「䌪䪍㟺㔺ⷭ」),数字仍正常。search_text 搜不到关键词、extract_text 输出乱码——v2 引擎的"模板 + 文本流"路线完全不可用。

完整流程(参考实现脚本见 scripts/parse_ocr_text.py + scripts/validate_ocr_data.py):

  1. 乱码检测:提取一页看字符——若为 CJK 扩展 A(U+3400-U+4DBF)/私有区(U+E000-U+F8FF) 的伪汉字(非 \ufffd),即为 CID 映射损坏。文字层方案放弃。
  2. 页码定位:乱码时改用 PyMuPDF doc.get_toc() 读 PDF 书签定位三大报表页码(书签是结构化元数据,不受乱码影响)。
  3. OCR 提取:用 pdf-glmocr-hybrid 技能,--pages 指定报表页(避开全 PDF 慢扫)。参数 num_ctx=16384(密表早停根因)+ num_predict=8192 + 简短中文 prompt。
  4. 解析 OCR 输出(v2 引擎不适用,需独立解析器):
    - OCR 输出格式不统一:损益表常为 Markdown 表格(| 收入 | 5 | 457,286,687 | ... |),OCI/BS/CF 为空格分隔文本流(逐行/同行混合)。解析器须兼容两种。
    - 行内解析优先 + 跨行缓冲兜底:先从行尾收 2 个数值 token、剥附注;行内不足双值时 tokens 进跨行缓冲,凑齐双值再 flush(处理 OCI 逐行格式)。
    - 纯数字附注陷阱:附注 15/26 是纯数字,token 流模式下会被误判为数值——必须"行内从尾部收值"优先,杜绝附注混入值列。
    - 节标题做 section 标记:BS 的「保修撥備/定期銀行存款/借款」在流动与非流动段同名,靠 section 隔离,跨年对照用 (section, name) 键,避免同名科目错位对照。
    - OCR 噪声:temperature=0 下偶发整块/行级重复(按"最长实质块 + 条目级整段去重"处理);系统性误读(「權益法入賬」→「法人賬」)全局替换修正。
  5. 验证(191 项全通过):损益逐级加总、OCI 加总、BS 分段加总+总等式、CF 三段加总+现金勾稽、跨年对照(年报 N 的上年列 vs 年报 N-1 的当年列,配科目名映射表处理重命名)。跨年对照是 OCR 质量的终极试金石——两次独立 OCR 结果一致即高置信。
  6. OCR 漏读补漏:单值行(如「因攤薄 —」)可能漏读一值,用段加总勾稽反推差额 + PyMuPDF get_text("words") 数字层核对 PDF 原文补正。

科目名跨年映射(小米实测,同理适用于其他公司):物業及設備→物業、廠房及設備;長期/短期銀行存款→定期銀行存款;貿易應收款項→貿易應收款項及應收票據;保修撥備→撥備;年內利潤↔年度利潤(2023 用「年內」);資本開支→購買物業、廠房及設備、土地使用權及無形資產。


公司模板配置规范

模板文件位于 templates/{company_id}.json,字段定义见 templates/_schema.json。

必填字段

字段 类型 说明
company_id string 公司唯一标识(文件名前缀)
company_name string 公司中文全称
company_name_en string 公司英文全称
header_filters object 页眉页脚过滤词集合
statement_titles object 三大报表起止关键词
balance_sheet_style enum standard / net_assets
text_order enum en_first / zh_first / auto

关键可选字段

字段 默认值 说明
income_includes_oci false 损益表与OCI是否合并
cash_item_aliases ["Cash and cash equivalents"] 现金科目候选列表(fallback 查找)
cashflow_reconciliation_keyword "ANALYSIS OF BALANCES" CF 表调节段标题(遇到停止解析)
balance_sheet_validation.type assets_eq_liab_plus_equity 验证策略
director_signatures [] 董事签名列表(解析时跳过)
extraction_page_offset 1 损益表起始页的前置缓冲页数

新公司接入指南(5 步)

Step 1:复制默认模板

cp templates/_default_hk.json templates/{company_id}.json

Step 2:填充公司基本信息

编辑 {company_id}.json,填入 company_name、company_name_en、stock_code、market。

Step 3:定位三大报表页码

PDFKIT="C:/Users/wangs/.workbuddy/plugins/marketplaces/cb_teams_marketplace/plugins/document-skills/skills/pdfkit-py/scripts/pdfkit.py"
PY="C:/Users/wangs/.workbuddy/binaries/python/envs/default/Scripts/python.exe"

# 搜索三大报表标题(用英文最稳定)
for KW in "PROFIT OR LOSS" "FINANCIAL POSITION" "CASH FLOWS"; do
  "$PY" "$PDFKIT" search_text --input 年报.pdf --find "$KW" --engine pymupdf
done

记录损益表起始页号,验证:单页提取后内容首行应为报表中文标题。

Step 4:实测文本格式与 BS 结构

# 提取损益表起始页,观察科目顺序
"$PY" "$PDFKIT" extract_text --input 年报.pdf --pages "[损益表起始页]" --format text

判断:
- 文本顺序:科目名是先中文还是先英文?→ 设置 text_order
- BS 结构:搜索 "Total assets",找到 → balance_sheet_style: standard;找不到 → net_assets
- 损益表与OCI:搜索 "COMPREHENSIVE INCOME",与损益表同页 → income_includes_oci: true

Step 5:填充模板并测试

将 Step 2-4 的发现填入模板 JSON,然后运行:

"$PY" scripts/generate_report_v2.py \
  --template {company_id} \
  --years 2020,2021,2022,2023,2024,2025 \
  --input-dir /path/to/extracted_txt/ \
  --output /path/to/report.html

检查输出:
- [ ] 三大报表科目数量在预期范围(Income ~20, Balance ~35, Cashflow ~50)
- [ ] 资产负债表等式验证全部通过 ✓
- [ ] 现金流勾稽提示合理(差额 = 长期存款等调节项)
- [ ] 抽查 5 个关键科目(营收/净利润/总资产或净资产/现金)与 PDF 原文一致


执行检查清单

在最终输出前,逐项确认:

  • [ ] 阶段一:所有 PDF 的三大报表均已定位并提取
  • [ ] 阶段二:clean_lines 未误删数据行(抽查 3-5 行数值是否与 PDF 原文一致)
  • [ ] 阶段三:每张表解析后的科目数量在预期范围内(~20 + ~35 + ~50)
  • [ ] 阶段四-1:所有年份资产负债表等式验证通过(按 balance_sheet_validation.type)
  • [ ] 阶段四-3:所有年份 CF 期末现金与 BS 现金勾稽合理(相等或差额可解释)
  • [ ] 阶段四-4:同比 >±30% 的科目已标注
  • [ ] 阶段五:单位标签已从"千元"改为"亿元"
  • [ ] 阶段六:HTML 无外部依赖、响应式正常、打印样式正常
  • [ ] 抽查 5 个关键科目与 PDF 原文一致

依赖

  • pdfkit-py:PDF 文本提取(PyMuPDF 底层)
  • openpyxl:可选的 Excel 输出
  • Python 3.10+

脚本

  • scripts/generate_report.py:v1 单公司脚本(Pop Mart 版,参考实现,含完整 HTML 生成器)
  • scripts/generate_report_v2.py:v2 通用引擎(从模板加载配置,含解析+验证,HTML 生成需复用 v1 函数并传入 template)
  • scripts/parse_a_share.py:A 股独立解析器(参考实现:东鹏饮料 605499.SH 5 年合并报表)
  • scripts/generate_a_share_report.py:A 股 HTML 报告生成器(红涨绿跌/DIN字体/亿元单位)
  • scripts/parse_ocr_text.py:文字层乱码年报的 OCR 文本流解析器(参考实现:小米 1810.HK 五年;行内解析优先+跨行缓冲+节标题 section 标记+条目级去重,见「类别八」)
  • scripts/validate_ocr_data.py:OCR 版数据验证器(参考实现:小米 1810.HK;损益/OCI/BS/CF 全套勾稽 + 跨年对照 + 科目名映射表)
  • templates/_schema.json:模板字段 JSON Schema 规范
  • templates/_default_hk.json:港股默认模板(新公司接入起点)
  • templates/_default_a_share.json:A 股默认模板(新公司接入起点,含 A 股特定字段)
  • templates/nongfu_spring.json:农夫山泉模板(zh_first + net_assets BS + 现金科目 fallback)
  • templates/popmart.json:Pop Mart 模板(en_first + standard BS)
  • A股年报处理指南.md:A 股年报解析详细工作流(vs 港股差异、智能跨行合并、节标题处理、防死循环等)

已知限制与未来扩展

  1. HTML 生成器尚未完全模板化:v2 引擎目前只输出数据摘要,完整 HTML 生成需复用 v1 函数并传入 template。下一步可将 v1 的 generate_html/build_table/build_bs_check/build_cf_check 改造为接受 template 参数。
  2. A股支持已验证(2026-08-19 完成东鹏饮料 5 年合并报表提取):A 股年报结构与港股差异较大,详见 A股年报处理指南.md。当前实现使用独立脚本 scripts/parse_a_share.py,未集成到 v2 通用引擎。下一步可基于 _default_a_share.json 将 A 股字段下沉到 v2 引擎。
  3. 所有者权益变动表结构特殊:A 股该表为多列横向结构(实收资本/其他权益工具/资本公积/...),PDF 提取后表格列结构被打散,当前实现仅在 JSON 保留 raw_lines,不在 HTML 呈现。后续可专门写一个 parse_equity_statement() 处理此结构。
  4. 美股支持待验证:美股 10-K 报表结构与港股差异较大(如无 OCI 单独表、BS 用 "Balance Sheet" 而非 "Statement of Financial Position"),需新增 _default_us.json 模板。
  5. 多币种支持:当前默认 RMB'000 → 亿元,港股部分公司用 HKD'000 或 USD'000,需扩展 currency 字段为对象含汇率换算。A 股单位为"元",换算系数为 ÷100,000,000(已在 _default_a_share.json 的 unit_to_yi_divisor 字段记录)。

常见问题

5 问
答案由本站依据条目字段整理
年报财务数据提取怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_bf2a403c/sy-investment-arextract。安装方式为未标注。装完刷新技能列表或重开客户端。

年报财务数据提取支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

年报财务数据提取权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

年报财务数据提取收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

年报财务数据提取用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。