记账截图识别与收支分析
Overview
把手机记账 App 的长截图(滚动截图)识别为结构化收支记录,输出月度 CSV 和可交互的收支分析 HTML 工作台。适用于「每月/每几个月导出一次截图 → 沉淀为数据 → 可视化分析」的记账流程。
关键原则:识别截图时必须逐段读取原尺寸图,禁止用压缩拼图——压缩后文字模糊会导致描述/金额大量识别错误(历史上因此产生过"电竞车""阈守关金"这类完全虚构的条目)。准确率优先于速度。
Workflow 决策树
- 用户提供了记账截图(一张或多张长截图)→ 走「截图识别」流程(Step 1-5)
- 用户已有 CSV 交易数据 → 跳过截图识别,直接走 Step 3(归类)+ Step 5(HTML)
- 用户只想分析已有数据 → 直接生成/更新 HTML 工作台(Step 5)
- 用户基于收支数据进一步问 资产配比 / 房贷还贷策略 / 降薪现金流压测 → 走「财务规划测算」流程(Step 6)
Step 1: 切分长截图
把每张原截图按 2700px 高度 切成 part,不缩放、不做不必要的二次有损编码:
python scripts/split_screenshots.py <截图目录> <输出目录> [--chunk 2700] [--step 2400] [--only 12,13]
- 输入:一个目录,里面是 1 张或多张
*.jpg/*.jpeg/*.png长截图(如 1440×25000 左右的滚动截图) - 输出:每个文件一个子目录
{原文件名前缀}/p00.jpg, p01.jpg, ...,每张约 2700px 高 - 规则:每个原文件单独一个子目录,避免不同文件切出的 part 互相覆盖
--step(默认 2400)控制滑动步进,比--chunk小即产生重叠,留 300px 左右重叠可防止条目正好被切在边界上导致信息残缺;重叠引入的重复条目在后续按唯一键去重--only 12,13只切指定文件(补切个别图,不必全量重来);--list先看将处理哪些文件、各切几片- 若截图是纵向滚动截图(宽度 ~1440,高度 20000+),直接切;若宽图则需先旋转
切分环节的四个坑(2026-09-11 量化验证后修复,勿回退)
这四条在切图时都会静默降低识别质量或丢数据,脚本已处理,改动前请先读懂:
- 别丢掉色度:Pillow 存 JPEG 时,即使
quality=95,默认仍是 4:2:0(色度只有 1/4 分辨率)。彩色小字、彩色图标、缩略图边缘会糊。脚本已固定subsampling=0(4:4:4)。实测同一张切片:彩色内容 48.11dB → 50.25dB,黑白文字内容 55.55dB → 56.38dB;代价约 +20% 体积。若需更接近无损可传--quality 100(约 73dB,体积 +40%)。- 附带结论:
crop之后不能用quality='keep'(Pillow 报 original image is not a JPEG,因为裁出的新图丢了 quantization 属性),不要再尝试。
- 附带结论:
- PNG 源仍存 PNG:iOS/部分安卓的截图是 PNG。把 PNG 改存 JPEG 等于凭空多一次有损编码(实测从"逐位相同"退化为 48dB)。脚本
--format auto(默认)会跟随源格式。 - 按数字自然排序:
sorted()得到的是1,10,11,2,27,3,时间线直接错乱。脚本按数字段排序(1 < 2 < 10)。注意:哈希文件名(如35edea778c.jpg)本身无序,排序只保证可复现,真实顺序要靠图片内的日期字段。 - 尾部碎片不能一律丢:只有"已被上一片完全覆盖"的尾片才是冗余可丢的。旧逻辑一律丢弃 <300px 的尾片,在
--step == --chunk(无重叠)时会静默丢掉最后那段记录(实测尾记录直接消失)。脚本按"是否被覆盖"判断,并在切完后做覆盖校验:确认[0, 原图高)被完全覆盖,有缺口则报错并以退出码 2 结束。
Step 2: 逐段识别(核心步骤,务必严格)
用 Read 工具逐张读取每 part 原尺寸图(不要拼网格、不要缩放),识别每笔交易:
- 每笔交易记录 5 个字段:日期(YYYY-MM-DD)、星期、类型(收入/支出)、描述、金额(收入正/支出负)
- 描述保留截图原文,不臆测、不"翻译"、不补全(如截图写"久锦"就记"久锦")
- 金额以截图为准:负数=支出,正数=收入
- 注意月份汇总行(如"1月 收入 X 支出 Y")可用来交叉校验当月合计,识别完核对一次
- 不要跳读:每 part 从上到下读全,避免漏掉日期标题下的多笔
- 一个 part 读完再读下一个,不要同时加载多个 part(会丢失上下文)
- 识别结果按 日期倒序或正序整理均可,最终按日期排序写入数据文件
截图里可能出现的干扰项
- 日期标题行:如"01月04日 星期日 支出 405.2"——这是当天的汇总,不是交易本身,不要记为交易
- 月份汇总行:顶部"1月 收入 X 支出 Y",仅用于核对
- 理财/转账流水:频繁出现,金额忽正忽负,全部照记;分析时可按分类聚合净额
- 疑似录错的符号:某笔描述像支出但金额为正(或反之)——照截图记录,并在交付时提醒用户核对
大批量截图(10 张以上)的并行识别(重要,2026-09-11 实战总结)
一次要处理十几到几十张长截图时,不要用单只子代理串行读完:单只读 ~28 张 1440×2700 大图要 40+ 分钟,会在完成前被会话中断,最终报告丢失、进度白费。正确做法:
- 先把全部长截图统一切分成原始尺寸切片(2700px 高、步进 2400px 留 300px 重叠),先切好再由子代理读,保证每只拿到的切片口径一致。
- 用多只子代理并行,每只只负责 2 张原图(约 14 个切片),单只约 10 分钟可完成。
- 让子代理每读完一张原图就覆盖式写入一次 TSV,不要等全部读完才写——被中断时进度仍在。
- 子代理 prompt 里要写明该原图的预期条数(如"每张原图应恰好 20 条"),让它自检漏读。
- 相邻切片重叠必然产生重复条目,最后按业务唯一键(如 日期+描述+金额)统一去重。
- 子代理报
429 频率限制时,给 Agent 传model: "lite"即可继续(实测有效),不必等到额度重置。
交叉校验技巧:若数据里存在两组应一一对应的字段(如"评价文字"与"星级"),写脚本自动比对,能高效抓出识别错误——比肉眼复查全量数据快得多。
Step 3: 归类
使用 references/categories.md 中的分类规则给每笔交易归类:
- 内置规则:按描述关键词匹配(如"打车/地铁"→交通,"高铁/机票"→出差,"外卖/火锅"→餐饮)
- 归类逻辑在数据生成脚本中实现,
build_csv.py和build_html.py都复用同一套get_category() - 新描述自动落入"其它",属正常;积累一定数量后把高频新描述补进 categories.md 再重跑
- 收入类注意:工资/绩效/补贴/退税等都归"工资";出差报销归"出差";红包归"红包"
Step 4: 生成 CSV
python scripts/build_csv.py <数据目录> <输出CSV目录>
- 每月一个 CSV:
YYYYMM.csv,UTF-8 BOM 编码(Excel 直接打开不乱码) - 字段:
日期,星期,类型,分类,描述,金额 - 额外生成
账户总览.csv(可选,账户/负债信息)
Step 5: 生成 HTML 分析工作台
python scripts/build_html.py <数据目录> <输出HTML路径> [--template assets/workspace_template.html]
生成单文件可交互 HTML,内嵌全部交易数据 + Chart.js(CDN),功能:
- 概览卡片:真实收入/支出/净结余/储蓄率(不含理财流水,理财单算净额)
- 年月筛选 + 类型筛选(全部/收入/支出)+ 关键词搜索
- 月度趋势图(收入/支出柱状)、支出分类饼图、分类排行(支出/收入)
- 支出分类月度堆叠趋势、收入结构(工资/出差/红包 + 理财净额折线)
- 月度环比卡片(自动取最近两月,当前月不完整时用日均口径)
- 明细表(可编辑/删除/新增,localStorage 持久化)
- 金额排序:点击「金额」表头按金额升/降序(▲▼ 指示),点击「日期」表头按日期排序
- 按月折叠:视图切换「平铺 / 按月折叠」,折叠视图下点击月份分组头可展开/收起该月,分组头显示该月笔数/收入/支出小计
- 账户总览表
- 导出/导入 CSV(原生解析,兼容 GBK 与斜杠日期)、JSON 备份/恢复
- "本月要处理"置顶区:本月预算进度 + 大额支出提醒 + 理财净额 + 疑似记错提醒
模板使用 中国惯例配色:收入红、支出绿。
Step 6: 财务规划测算(资产配比 / 还贷策略 / 现金流压测)
当用户基于已有收支数据问「钱怎么配」「房贷要不要提前还、怎么还」「降薪/绩效停发扛不扛得住」时,用 scripts/planning_calculator.py 测算,方法论文档见 references/financial_planning.md。
输入参数来源:从工作区数据提取——账户总览(现金/股票/公积金/贷款余额)、月度收支分析(月均支出/工资类收入/绩效占比)、用户口述(贷款利率/月缴存/女友公积金)。
按问题选子命令:
| 场景 | 命令 | 关键参数 |
|---|---|---|
| 等额本金还款计划 | loan | --principal --years --rate [--paid-months] |
| 提前还本:减月供 vs 缩年限 | prepay | --principal --years --rate --paid-months --prepay [--monthly-gf] |
| 四笔钱资产分层 | allocate | --cash --monthly-expense --emergency-months [--baby-fund --stock --loan-rate] |
| 降薪/停发情景压测 | cashflow | --scenarios '{"情景名":{"wage":..,"perf":..,"expense":..,"mortgage":..}}' |
# 示例:提前还 15 万,两方式对比(月缴存 2500 用于算公积金覆盖后自付)
python scripts/planning_calculator.py prepay --principal 800000 --years 30 \
--rate 0.026 --paid-months 12 --prepay 150000 --monthly-gf 2500
分析要点(详见 references/financial_planning.md):
- 等额本金下「缩短年限」省息永远优于「减月供」,代价是月供更高 → 用公积金月缴存判断自付是否扛得住
- 资产配比用「四笔钱」:应急金(月支出×N月,降薪风险期 N 取 10-12)→ 生育/大额计划金 → 还贷池(贷款利率 > 存款利率时超额现金优先还贷)→ 权益仓(闲钱、设上限、现金流脆弱期 0-10%)
- 政策类(配偶公积金/期限变更次数/冲还贷与提前还本互斥)各地不同,须现场查证并在报告中标注"待核实"
- 产出:测算结果建议整理为单文件 HTML 报告(Hero 结论区 + 方案对比表 +
.insight高亮结论 + 分阶段行动清单),与收支工作台统一浅色风格
交付
- CSV 文件(每月的
YYYYMM.csv+账户总览.csv) 收支分析.html单文件工作台- 用 present_files 展示 HTML 预览
- 简要报告:各月收入/支出/净结余、异常记录提醒(疑似录错、漏截图需用户补充)
常见问题
- 截图太多/太长:先切分,再逐 part 识别,不要试图一次看完一整张超长截图
- 识别有误怎么办:用户指出具体哪笔,直接在数据文件中修改对应行,重新生成 CSV+HTML 即可
- 分类不全:把新描述追加到
references/categories.md的对应分类关键词列表,重新生成 - HTML 里图表不显示:Chart.js 走 CDN,需联网;如需完全离线可后续替换为内联 SVG(不推荐初版做)
Resources
scripts/
split_screenshots.py— 所有截图类任务的切图唯一实现(记账、豆瓣、微信等通用):按 2700px/步进 2400 切分,自然排序、JPEG 4:4:4、PNG 保无损、尾部碎片不丢、切完做覆盖校验。其他工作区如需切图直接调用本脚本,不要另写一份实现(避免行为漂移,2026-09-11 已把电影工作区的split_douban.py改成调用本脚本的薄封装)build_csv.py— 交易数据 → 月度 CSV + 账户总览 CSV(含分类逻辑)build_html.py— 交易数据 → 单文件 HTML 分析工作台(含分类逻辑)planning_calculator.py— 财务规划测算(loan 还款计划 / prepay 提前还本对比 / allocate 四笔钱分层 / cashflow 情景压测),纯标准库、参数全命令行、无个人数据
references/
categories.md— 分类规则表(描述关键词 → 分类),通用不涉个人financial_planning.md— 财务规划方法论(四笔钱框架、等额本金公式、提前还本两方式对比、公积金政策通用要点、情景压测方法、HTML 报告输出规范),通用不涉个人
assets/
workspace_template.html— HTML 工作台模板(含 Chart.js 与全部交互逻辑,__EMBEDDED_DATA__/__DB_IDS__/__DATA_VERSION__占位符)
微信扫一扫