Community研究與資料分析github.com

AdhishaInd/financial-statement-extraction

從公司財務報告PDF(含年報、季報及掃描件)中提取損益表、資產負債表與現金流量表數據,存入關聯式資料庫,並透過算術檢查確保僅載入可信的數字。

financial-statement-extraction 是什麼?

此技能專為從公司財務報告PDF中提取結構化財務數據而設計,支援資產負債表、損益表與現金流量表。其核心機制是自動解析器先處理大部分報告,然後透過算術檢查(如資產=負債+權益)驗證每欄數據的正確性,只有通過檢查的欄位才會載入資料庫。未通過的報告會進入分診流程,明確指出失敗原因,再由子代理以批次方式從頁面圖片中讀取。整個流程確保資料庫中的每個數字都可追溯、可審計,且支援增量發布與階段性審計。此技能已於可倫坡證券交易所兩年(2,707份報告、720,000個數字)的資料中驗證,99.4%的報告完全載入。它支援多種平台(如Claude Code、Cursor、Codex),並能處理掃描件與不同版型的報告。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/AdhishaInd/agent-skills/tree/HEAD/skills/financial-statement-extraction

Installed? Explore more 研究與資料分析 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

財務報表提取

將報告PDF轉換為經過檢查的事實:financial_fact(document, period, label, scope, value, unit, audit status)。 已在可倫坡證券交易所兩年的申報文件(2,707份報告、720,000個數字,99.4%完全載入)上建立並驗證。 使其快速的方法:自動解析器處理大多數報告,算術檢查決定哪些可信, 分流步驟明確說明每個剩餘報表失敗的原因,然後僅從頁面圖片中, 以批次方式由子代理讀取這些報表。每次變更僅透過階段載入與審計才能送達已發布的資料庫。

一切所依賴的唯一規則

一個數字僅在其欄位通過算術檢查時才載入(資產 = 權益 + 負債;稅前利潤 - 稅 = 利潤;母公司擁有人 + 非控制權益 = 利潤;現金流量表各節總和等於淨變動;期初 + 變動 = 期末)。不會為了讓檢查通過而調整任何數字。檢查僅允許列印捨入(最後一位列印數字的少量單位:兩項用2,三項用3,五項用5),因此總計與其組成部分相差1-2個單位時可通過,更多則為讀取或列印錯誤。這就是為何解析器、OCR引擎、視覺轉錄和人類都可以餵養同一個資料庫:決定權在檢查,而非來源。當檢查失敗時,要嘛讀取錯誤(重新讀取),要嘛列印錯誤(記錄原因,排除在外)。

實際中有以下重要推論:

  • 標籤完全保持原樣列印,僅透過精確別名(label_alias)映射到標準項目,絕不使用模糊匹配。拼印錯誤的標籤會使報表無法載入,而非默默地錯誤。
  • 沒有標籤的列印總計可能會獲得一個括號標籤([Total assets]),因為其位置定義了它。
  • "UNCHECKED"(無法檢查)不是"FAIL"。它通常表示檢查器尚不認識某種版面 - 只需修正檢查器一次,所有具有該版面的報告都會載入(參見 references/checks.md)。

檔案位置

  • scripts/pipeline/ - 管線:parse_report.py(PDF -> JSON 表格)、segment.py、columns.py、 tokens.py、checks.py、ocr_words.py(OCR 作為偽文字圖層)、load_facts.py(JSON -> DB,僅通過欄位)、 vision_tables.py(圖片轉錄 -> JSON 表格)、extract_all.py、normalize.py。 地圖、資料形狀及如何適應其他市場:references/pipeline.md。
  • scripts/triage.py、scripts/make_batches.py、scripts/render.py、scripts/stage_publish.py - 各步驟的輔助工具。
  • assets/schema.sql(資料庫)、assets/dictionary.sql(252 個標準項目 + 471 個精確標籤別名)、 assets/worker_brief.md(給轉錄工作者的簡報)、assets/examples/(轉錄檔案)。
  • 專案目錄:資料庫、PDF 和輸出所在的位置。使用者在 CLAUDE.md / AGENTS.md 中命名它(例如 "Financials project: ~/stocks/cse_financials");如果沒有則詢問。佈局:db/<name>.db、 reports/<SYMBOL>/<doc>.pdf、解析器輸出 extracted_final/、發布來源 extracted_final_v/、 轉錄 reviewed/vision/、筆記 docs/。如果專案有自己的 pipeline/,則將其視為當前程式碼(此技能的副本可能較舊)。

始終以 -I(隔離模式)和 CSE_OCR=0 執行 Python,除非需要 OCR(CSE_ 前綴是歷史遺留)。 報告的 PDF:select local_path from report_document where document_id=?(相對於專案目錄),然後執行 python -I scripts/render.py <pdf> <pages> <out_dir> --text 以傾印文字圖層並渲染頁面。

工作流程

1. 範圍界定與下載

選擇期間範圍;從報告標題中獲取期間結束日(交易所申報日期不可靠)。填入 report_document 行(每個報告一列:公司、類別 ANNUAL/INTERIM、標題、期間結束、來源 URL),然後 以並行與可恢復方式下載。交易所特定部分(API、URL、特性)屬於配套技能 - 可倫坡用 cse-financials。將每個年份區塊作為這些步驟的單獨一次執行。在新的市場或新的 年份之前,請閱讀 references/traps.md:它列出了耗費最多時間的資料陷阱。

2. 使用同一個解析器版本解析所有報告

python -I scripts/pipeline/extract_all.py <db> <out_dir> --workers N 搭配 CSE_OCR=0(約 9 分鐘處理 2,700 份報告),然後針對掃描件進行單獨的 OCR 處理(如果可用則使用 GPU;參見陷阱)。解析器變更後,重新解析所有 報告並逐份比較 - 部分重新解析會使資料庫無法重現。

3. 載入並讀取狀態

load_facts.py(透過 stage_publish.py,步驟 6)為每個報告提供 EXTRACTED(損益表和資產負債表已載入)、PARTIAL 或 FAILED。預計單獨從解析器大約有 80% 為 EXTRACTED。

4. 在查看任何頁面之前,先對剩餘報告進行分流

python -I scripts/triage.py <db> <extracted_dir> triage.json --pdf-hints
python -I scripts/make_batches.py triage.json batches/ --target=12

分流會給出每個缺失報表的原因(not_found、UNCHECKED、FAIL、no_columns、no_months、 unit_unproven、pass_refused...)以及查看位置。閱讀計數:一個原因導致的大群集(例如 100 個 UNCHECKED)通常意味著檢查器缺口或載入器規則 - 修復程式碼勝過轉錄數百頁。同時檢查 FAILED 報告是否真的是報表:通知、股東名冊和更正公告很常見,只需要記錄原因。

5. 以批次方式從圖片中轉錄

每個工作者獲得一個批次檔案和 assets/worker_brief.md(填入路徑)。它找到報表 頁面,讀取它(先讀文字圖層,再讀圖片以確認佈局和任何可疑內容),寫入 reviewed/vision/<doc>.txt,執行 vision_tables.py 處理其文件,直到每個欄位 PASS,然後寫入 bNN.result.json。工作者需要一個能夠讀取圖片的模型。 格式和規則:references/vision-format.md。工作者並行運行、使用限制、恢復與審查結果:references/orchestration.md。 如果沒有子代理,則使用相同的簡報一個接一個地處理批次。

在批次運行期間,每當結果摘要到達時就讀取它:

  • 重複出現的"UNCHECKED because the checker does not recognise X" -> 擴展 checks.py(references/checks.md), 用 vision_tables.py 重新測試受影響的檔案,將規則附加到簡報中,以便後續批次知道。已寫入的表格 然後在無需重新轉錄的情況下通過。
  • 判斷性呼叫(審計狀態、重述欄位、奇數期間長度、提供的標籤)-> 檢查它們是否遵循 簡報;集中修正(例如對 COLS 行使用 sed),而不是重新執行工作者。

6. 階段、審計、發布

python -I scripts/stage_publish.py --project <dir>            # 僅階段 + 審計
python -I scripts/stage_publish.py --project <dir> --publish  # 閱讀審計後

如果審計顯示報告離開 EXTRACTED 狀態、報告變空、完整性/外鍵錯誤、新的單位離群值,或是在沒有轉錄檔案的報告中事實遺失/變更,則拒絕發布(這意味著程式碼變更觸及了沒有人重新讀取的資料)。 在視覺報告之外的增益是正常的(解決衝突會釋放另一個報告的欄位),但需要檢查每一項。分階段發布(先完成批次),以便工作中斷時能保存;然後如果專案有測試,則執行其測試。

7. 結束每個報表

目標是:每個缺失的報表要嘛已載入,要嘛有陳述的原因。建立每個報表的結果表 (已載入 / 未載入 + 來自 MISSING 行和結果檔案的原因)。對於每個未載入的報表,檢查 相同的數字是否已從另一份報告(下一年度的比較數字、對應的中期報告)載入 - 通常 是的,這會將"缺口"轉變為"已涵蓋"。將結果記錄在專案文件中。

Token 與時間經濟

  • 先分流;從不發送工作者去"找出問題"而沒有原因和頁面提示。
  • 先文字圖層再圖片:乾淨的文字圖層可以免費確認數字;圖片用於確定佈局。渲染 1500 px;裁切 (render.py --clip)而不是渲染更大的整頁。帶有垃圾文字圖層("9,O4349L")的掃描件需要圖片。
  • 按公司分批:一個佈局,多個季度。每個批次約 10 份報告或約 12 個成本單位,一次約 6 個工作者。
  • 即使檢查仍為 UNCHECKED,工作者也要寫入完整表格,加上一列 MISSING 行:如果稍後擴展 檢查器,表格無需再次讀取即可載入。
  • 在程式碼(檢查器、載入器)中一次性、集中修復系統性問題;重新執行 vision_tables.py(幾秒鐘)而不是重新讀取頁面。
  • 協調器不查看頁面圖片,除非為了解決爭議;它讀取摘要、運行檢查和審計。
  • 將工作者摘要保持在 3-6 行;詳細資訊屬於檔案註解。

完成的定義

每個報告:EXTRACTED,或 PARTIAL/FAILED 並為每個缺失報表提供一個命名列印證據的原因 (例如 "printed total 3,115,995,977 vs equity + liabilities 3,115,995,968"),或"covered by report N"。僅透過 stage_publish.py 發布,並附有備份、審計乾淨(或所有標誌已解釋)、測試通過,以及在專案文件中加上結果表與帶日期的註釋。

相關技能