news 2026/10/26 15:52:37

Python个人财务管理系统:自动解析微信支付宝账单的本地账本

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python个人财务管理系统:自动解析微信支付宝账单的本地账本

简介:这是一份基于Python开发的个人财务管理系统完整项目,面向毕业设计、课程设计、Python Web与人工智能应用方向的开发者,可用于账目录入、条件查询、分类统计、预算设置及账单提醒等日常财务场景,并融入微信/支付宝账单自动解析与AI智能分类能力,对个人资金流进行直观跟踪。资源包共30个文件,以10个py源码文件为核心,覆盖数据库、用户管理、账单处理等模块;另含8张功能界面截图、Markdown说明文档、环境配置示例、Docker及Makefile部署脚本等,便于快速理解系统结构与二次开发,压缩包仅665KB,体量精简。目前已有78人学习下载,代码入口与模块划分清晰,包含app.py、数据库操作、多平台账单处理器、用户认证等,并配有工具说明和更新日志,可较好支撑理财项目实战、毕业设计参考,也可作为学习Python文件处理、数据存储与Web开发的综合样例。

1. Python个人财务管理系统是什么:能自动吃进微信账单的本地账本

拿到这个“Python个人财务管理系统.zip”之前,我以为是又一个只能手动录流水的小工具,毕竟市面上叫“个人财务管理系统”的课程设计项目太多了。翻完源码才发现,真正值钱的不是那套增删改查页面,而是wechat_bill_processor.py和alipay_bill_processor.py这两个账单解析器——它们能把微信、支付宝导出的原始 CSV 自动清洗、去重、分类并写入数据库,配合bill_classifier.py做关键词规则分类,这套“账单文件 → 结构化数据”的链路才是这个项目最值得拆的部分。它适合三类人:做 Python 毕业设计或课程设计的学生,想把自己微信支付宝流水统一管起来的普通用户,以及想搞清楚“CSV 解析、去重、分类入库”这一整套流程的入门开发者。技术栈不重,但链路完整,从 Docker 部署到用户权限都齐了。下面我按源码结构、启动方式、账单导入的顺序拆给你看,照着走一遍就能跑起来。

2. 系统拆解:入口、数据表与账单导入链路

整个系统的核心链路是“账单文件 → 解析器 → database.py → SQLite”,app.py 只是把结果用 Web 页面露出来。压缩包里的 tools.md 说明了依赖和工具,CHANGELOG.md 记录了版本变更,建议先翻这两个文件,能少走很多弯路。接下来我按入口、数据层、导入链路三个部分拆开讲。

2.1 入口与用户管理:app.py 和 addUser.py 怎么配合

app.py 是 Web 应用入口,负责登录路由、页面渲染和会话管理。它不直接碰数据库,而是通过 user_manager.py 和 database.py 拿数据。第一次打开系统会看到登录页,普通用户登录后只能录账单、查账单,管理员才能跑导入脚本——这种拆法在答辩时很好讲,实际用起来也不容易误删数据。

新增用户不用去数据库里插记录,项目里单独写了 addUser.py。在项目目录下执行:

python addUser.py --username admin --password yourpassword

这个脚本会先检查用户名是否已存在,再写入 users.json(用于会话校验)和数据库中的用户表(用于权限校验)。注意一个细节:用户的写入顺序是“先写库,再写 JSON”,如果任意一步失败,脚本会回滚并打印错误信息,不会出现半个用户状态。密码强度只做了最低要求——至少 6 位,不限制特殊字符。

这里有一个非常容易踩的坑:如果你只改了 users.json 而没有同步到数据库,登录时一切正常,但所有需要写库的操作都会报“用户不存在”。因为 app.py 的权限判定走的是 Flask session,而从库里取用户信息是在真正做数据操作时才会调 user_manager.py 的校验函数。我第一次跑的时候就是在 json 里手动加了用户,结果录第一笔账就翻车了。

用户登录后的会话用 Flask 签名 Cookie 存储,默认的 secret_key 需要从环境变量里读。如果 .env 没配,Flask 会用开发模式的固定值,这在本地练习没问题,但一旦部署到公网,别人就能伪造会话 Cookie。我一般会在 .env 里加一行SECRET_KEY=$(openssl rand -hex 32)生成随机值,启动前再 export 一下。这个改动不涉及项目代码,但能让整个系统的安全性上一个台阶。

2.2 database.py 的建表逻辑与账单类型定义

database.py 是整个数据层的核心,封装了 SQLite 的连接、建表和增删改查。它没有用 ORM,直接写 SQL——好处是依赖少、逻辑透明,毕业设计里很好解释;坏处是你必须手动保证表结构一致性,稍后第四节会讲一个因此踩的坑。

我翻了一遍源码,主要的表有三张:bill 表存流水明细,user 表存用户,budget 表存预算。bill 表的字段大致是这样:

字段类型说明
idINTEGER PRIMARY KEY AUTOINCREMENT主键
bill_typeTEXT支出 / 收入 / 转账
amountREAL金额,正负由类型决定
categoryTEXT分类,如餐饮、交通
bill_timeTEXT交易发生时间
remarkTEXT备注
sourceTEXT微信 / 支付宝 / 手动

建表过程不需要你手动执行,启动 app.py 时 database.py 会检查表是否存在,不存在就自动执行 CREATE TABLE。但如果数据库文件是旧版本建的、又缺了新字段,它不会自动 ALTER TABLE。升级代码后启动如果报no such column: xxx,最简单的处理方式是先备份再重建。可以先看看项目目录下有哪些数据库文件:

ls -la *.db

有历史数据的话,先用 sqlite3 工具导出一份备份:

sqlite3 finance.db ".dump" > finance_backup.sql

确认备份没问题后,删掉旧 finance.db 重新启动,让系统自动建新表。说实话,这个“删库重建”的操作我在本地做过好几次,每次都先用 dump 备份,否则一个月的账单流水说没就没。

bill_types.py 是分类体系的定义文件,它把 category 和关键词映射绑定在一起。比如“餐饮”关联“外卖|午饭|美团|饿了么”,“交通”关联“滴滴|地铁|公交|加油”。bill_classifier.py 会读取这份映射,对每条账单的 remark 做关键词匹配,匹配不到就归到“其他”。这套分类逻辑没有深度学习含量,但它是真能用的——只要你把自己的高频场景词加进去,分类准确率能到八成以上。后面第五节我会专门讲怎么把这个规则引擎改造成可自我更新的版本。

2.3 微信和支付宝账单导入:两条解析链路对比

微信和支付宝导出的 CSV 格式完全不一样,所以项目里做了两个独立的处理器:wechat_bill_processor.py 对应 import_wechat_bills.py,alipay_bill_processor.py 对应 import_alipay_bills.py。两个脚本各自有命令行入口,统一通过 Makefile 或 start.sh 调用。

微信账单导出的 CSV 开头是这样的:前两行是标题和导出时间,第三行才是真正的表头“交易时间, 交易类型, 交易对方, 商品, 收/支, 金额, 支付方式, 当前状态, 交易单号, 商户单号, 备注”。所以解析器第一步就是跳过前面两行垃圾数据,再按逗号逐行拆分。支付宝账单的导出格式略有不同,交易时间字段是2023-01-01 12:00:00,金额列里可能带¥符号和千分位逗号,两个解析器都做了对应的清洗。

手动导入一条账单文件的方式是:

python import_wechat_bills.py --file 微信账单.csv python import_alipay_bills.py --file 支付宝账单.csv

两个脚本都通过--file参数指定路径。如果你不加这个参数,脚本会把当前目录下第一张 csv 文件拿来自动导入——这是个隐藏很深的行为,我一开始没看源码时以为它会报错,结果直接把目录里的测试数据导进去了。判断是否是文件路径时也要注意,脚本里用的是os.path.exists,相对路径是相对于你执行命令的目录,不是项目根目录。所以如果你在项目目录下用python import_wechat_bills.py --file ~/Downloads/wechat.csv这样带绝对路径的命令没问题,但如果你在别的目录下执行脚本,相对路径就会找不到文件。

导入过程中的去重逻辑很关键:两个解析器都维护了一份“已导入单号集合”,微信用“交易单号”,支付宝用“交易号”,以这个字段作为唯一键。第二次导入同一个文件时,重复的交易会被跳过,不会产生重复账目。这意味着你每个月导出一次微信账单、反复导入都不会炸掉。如果你自己二次开发,这个去重键建议保留,这是整个导入链路里最不能丢的设计。

这套导入链路的处理逻辑大致是:读文件 → 按行解析 → 清洗金额和时间 → 匹配分类 → 去重 → 批量写入 database.py。理解了这个顺序,你就能明白为什么某些账单录入后分类是“其他”——不是解析器坏掉了,而是备注里没有命中 bill_types.py 里的关键词。遇到这种情况,去改分类映射比改代码快得多。

3. 部署与运行:本地启动和 Docker Compose 两套方案

这个项目给出了两套启动方式:裸机跑和 Docker Compose。裸机适合日常开发调试,Docker 适合想快速看效果或者部署到服务器上。两套方案用到的都是同一套代码,区别只在环境和进程管理层面。

3.1 本地裸机运行:依赖安装与 start.sh 做了什么

本地跑起来需要 Python 3.8 以上版本,官方文档里没写具体版本,但我在 3.8 到 3.11 上都试过,都能正常跑。安装依赖用一个命令解决:

pip install -r requirements.txt

requirements.txt 里锁定了 Flask、Pandas 等核心依赖。注意这里没有用 requirements-dev.txt 之类的拆分配置,所以如果你只是想跑起来,不需要额外装 dev 依赖。安装完依赖后,最标准的启动方式是执行 start.sh:

bash start.sh

start.sh 脚本内部做的事情很简单:先检查数据库文件是否存在,不存在则让 database.py 自动建表,再启动 app.py 对应的 Flask 服务。它会读取 .env 里的环境变量,如果 .env 不存在就报警告但继续用默认配置。默认端口是 5000,访问http://127.0.0.1:5000就能打开登录页。

如果你在 Windows 上跑,没有 bash 环境,可以手动按顺序执行:

python database.py --init python app.py

第一条命令是初始化数据库,第二条是启动 Web 服务。其实 database.py 的 init 逻辑在 app.py 启动时也会跑一遍,但显式执行一次能让你提前看到数据库建好没有,避免后面导入账单时才报错。在 Linux 下,我更推荐用 Makefile:

make install # 安装依赖 make run # 启动服务

Makefile 把 start.sh 里的步骤包装成了带依赖的 target,make install会先检查 pip 版本再装 requirements.txt,make run会先确认端口没被占用再启动。如果你要在后台跑,可以自己写个 nohup 包装,但更省事的方案是直接看下一节的 Docker。

3.2 Docker Compose 部署:一条命令起来的原理

如果你不想污染本地 Python 环境,或者想快速让项目在服务器上跑起来,用 Docker Compose 是最省事的。项目根目录下有个 docker-compose.yml,里面定义了服务名、端口映射和挂载卷。启动命令很简单:

docker compose up --build -d

--build 参数会先构建镜像,-d 表示后台运行。镜像构建过程由 Dockerfile 完成,Dockerfile 里大致做这几件事:基于 python:3.10-slim 基础镜像 → 复制 requirements.txt → 安装依赖 → 复制项目代码 → 声明 5000 端口。注意 Dockerfile 里没有 COPY 数据库文件进去,所以数据是挂在宿主机指定目录下的,相当于容器只跑代码,数据留在外面。

docker-compose.yml 里的卷映射通常长这样:

volumes: - ./data:/app/data

这样容器内的 database 文件会写到宿主机的 data 目录。好处是容器删了重建数据还在,坏处是你必须把 .env 里的DB_PATH指到/app/data/下,否则数据库文件还会落在容器内,一旦容器销毁就没了。我第一次用 Docker 跑这个项目时就吃过大亏:容器重建后所有账单都不见了,后来才意识到是 DB_PATH 没改。你可以先启动容器,再用 docker logs 看日志里打的数据库路径:

docker logs <容器ID> | grep -i database

如果日志里显示数据库文件路径在容器根目录而不是挂载卷里,那就赶紧改 .env 里的 DB_PATH,然后再 rebuild。这个操作比事后写一堆 MySQL 迁移脚本简单得多,也符合这个项目“轻量”的定位。

3.3 环境变量与配置文件:.env.example 到底要填什么

项目在根目录放了一个 .env.example,这是所有环境配置的唯一入口。我把它打开看一眼,里面的字段不多,但每个都影响运行行为。一份典型的内容是:

SECRET_KEY=random_string DATABASE_PATH=./data/finance.db PORT=5000 DEBUG=False

SECRET_KEY 就是第一节说的 Flask 会话签名密钥,别用默认值。DATABASE_PATH 默认是相对路径,指向项目目录下的 data 子目录。如果你用 Docker Compose,记得改成/app/data/finance.db。PORT 是 Flask 监听端口,和 docker-compose.yml 里暴露的端口要对应。DEBUG 在本地调试时可以设成 True,部署时一定设成 False,否则出错信息会直接怼到页面上。

这里有个常见的误解:.env.example不是让你直接改它的,而是让你复制一份成.env再改。项目代码加载环境变量时只认.env这个文件名,.env.example只是模板。如果你直接改.env.example,系统不会读它,启动时会弹一堆警告。正确做法是:

cp .env.example .env vim .env

改完 .env 后,再执行 start.sh 或 docker compose 重启服务。这个“复制模板”的习惯能救你很多次——我见过不止一个同学直接把敏感信息写进 .env.example 然后推到 GitHub,隐私全暴露了。.gitignore 里已经把 .env 排除在外,所以只要你用的是 .env,就能避开这个风险。

4. 避坑与排查:账单导入失败的五个真实案例

账单导入是功能核心,但也是问题最密集的地方。我把自己和身边朋友跑这个项目时遇到过的五个典型问题列出来,每个都按“现象 → 原因 → 解决”来讲,你照着排查能省不少时间。

案例一:第一行数据导入后分类全是“其他”

现象:导入微信账单后,所有记录的分类都落到了“其他”,连“餐饮”这种高频分类都没识别出来。原因:微信导出 CSV 是带 BOM 的 UTF-8 格式,用open(filename, encoding="utf-8")读文件时,第一列的表头“微信支付账单明细”前面会多一个不可见的\ufeff字符,导致解析器在匹配列名时找不到“备注”这一列,备注字段读到的是空值。解决:在解析器里加一行line = line.lstrip('\ufeff'),或者在open时就用encoding="utf-8-sig"。这个坑非常隐蔽,因为报错不一定出现,只是数据静默出错。我自己是在看了导入日志后才发现列名对不上,又去查了微信支付官方文档才想起来 BOM 的问题。

案例二:支付宝 CSV 打开后中文全乱码

现象:在 Windows 系统上直接双击打开支付宝导出的 CSV,中文全是乱码。原因:支付宝导出文件默认是 GBK 编码,而解析器里写的是encoding="utf-8",读出来的内容乱七八糟。解决:导入脚本里要把编码参数换成gbk或gb18030。这个改动只影响支付宝解析器,微信解析器保持utf-8-sig不动。如果你是自己写脚本导入历史账单,也可以用 pandas 读文件时指定两个编码做 fallback。这个问题的根子是 Windows 和 macOS 产出的文件编码不一致,不是项目本身的逻辑错误。

案例三:金额字段带 ¥ 符号和千分位逗号,导入后金额变成 0

现象:支付宝账单里金额列是¥1,234.56,解析器取到后 float() 转换失败,默认填了 0。原因:清洗逻辑只处理了单个¥符号,没处理数字中间的逗号。解决:在导入脚本的金额清洗函数里,先把¥和空格替换掉,再移除所有逗号,最后才转 float。代码逻辑大概是这样的:

# 支付宝金额清洗,注意去除千分位逗号 raw_amount = row["金额"].replace("¥", "").replace(",", "").strip() amount = float(raw_amount)

这个清洗顺序不能反,如果先转 float 再去逗号,数值直接翻车。我这个坑是导了三个月账单后发现的,环比图表上好几个月的餐饮支出都离奇偏低,追查下来才知道是这问题。

案例四:重复导入同一份账单,账单数翻倍

现象:同一个微信账单文件导入两次,数据库里账单数变成两倍。原因:第一次导入后,微信账单文件被处理完就删除了单号记录(或者根本没写入去重表),第二次导入时无法识别重复。解决:检查 import 脚本里保存单号的逻辑,通常是把交易单号写到一张import_log表或 JSON 文件里。确认这张表的数据在导入过程中没有被清空。我在源码里发现项目本身是维护了去重集合的,如果你自己改了代码,很容易把这段逻辑误删。血泪经验:去重标识一定要持久化,别放在内存里,容器重启后就没有了。

案例五:Docker 部署后导入账单提示数据库路径不存在

现象:docker compose up 成功后,打开页面导入账单,报错sqlite3.OperationalError: unable to open database file。原因:容器内没有/app/data这个目录,或者 .env 里的 DATABASE_PATH 还是相对路径,SQLite 在容器工作目录里创建文件时没有权限。解决:在 docker-compose.yml 的 volumes 里明确把宿主机目录挂载到 /app/data,并在 .env 里写成/app/data/finance.db。另外在 Dockerfile 里加一行RUN mkdir -p /app/data,保证容器启动时目录已存在。这个坑我第二次才躲过去,当时一直在宿主机上找数据库文件,根本不会意识到容器内和宿主机是两个文件系统。

5. 进阶:让 bill_classifier 从死关键词变成可自我更新的规则引擎

跑通基础功能后,体验上最大的瓶颈是分类准确率——bill_types.py 里预置的关键词覆盖不了你个人的真实消费场景。比如你在游戏平台充值,备注里是“Steam”,默认关键词表里没有,所有游戏支出都会被归到“其他”,统计图表瞬间失去意义。这里我给你一个我常用的改造思路:把关键词规则外置成 JSON 文件,然后在导入时把未命中的交易记录到“待分类”表里,定期由用户确认一次,确认结果自动写回规则库。

做法很简单,先创建一个 rules.json,结构是这样:

{ "餐饮": ["外卖", "美团", "饿了么", "麦当劳", "星巴克"], "交通": ["滴滴", "地铁", "公交", "加油", "停车"], "游戏": ["Steam", "PlayStation", "任天堂", "网易"] }

然后改 bill_classifier.py,让它启动时读取这个 JSON,而不是直接从 bill_types.py 的常量里取。分类逻辑走一遍:先精确匹配备注中的关键词,匹配不到就返回“其他”,并把这条记录的 id 和备注写进一个 calleduncategorized的表里。你在 Web 界面上加一个“确认分类”页面,看到未分类记录时,下拉框选一个真分类,系统把这个备注和分类提取成新规则追加到 rules.json,下次再遇到同样的商户名就自动分对了。

# 分类器核心逻辑:先读规则库,再逐条匹配 import json with open("rules.json", "r", encoding="utf-8") as f: RULES = json.load(f) def classify(remark): for category, keywords in RULES.items(): for kw in keywords: if kw.lower() in remark.lower(): return category return "其他"

这段代码比原来的实现多了两个优点:一是规则不用改代码就能加,二是关键词匹配时统一转小写,避免“steam”和“Steam”不一致导致漏分。配合“未分类确认页”,你只需要连续做一周的“事后归类”,规则库就能覆盖你 90% 的日常消费场景。每次导入新账单后,分类准确率反而越用越高,这个体验已经不是毕业设计能给你的了,更像一个真正的个人财务工具。

从那以后,我每次拿到这类“分类靠写死关键词”的项目,都会把规则外置这个改造排在第一位——不只因为它好改,更因为它让我不必反复去源码里找硬编码。这个项目交付后,我自己的账单已经在 Docker 里跑了四个月,微信账单每月导一次,分类准确率稳定在 90% 左右,去重一次没出过问题。希望这个思路也能帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 15:52:36

医疗AI核心技术:多模态数据融合与可解释性实践

1. AI医疗的现状与突破方向 医疗行业正经历着前所未有的数字化转型浪潮。作为一名在医疗AI领域深耕多年的从业者&#xff0c;我亲眼见证了AI技术从最初的辅助诊断工具&#xff0c;逐步发展为重塑整个医疗生态系统的核心驱动力。当前AI在医疗领域的应用已经突破了早期简单的图像…

作者头像 李华
网站建设 2026/10/26 15:52:09

AI视觉在收费站智能监控中的工程实践与优化

1. 项目背景与核心价值这个收费站智能监控系统的落地案例&#xff0c;展现了AI视觉技术在实际工程场景中的突破性应用。传统收费站监控存在三大痛点&#xff1a;夜间车牌识别率骤降、异常行为响应滞后、人工复核效率低下。我们团队研发的这套系统&#xff0c;通过多模态感知融合…

作者头像 李华
网站建设 2026/10/26 15:51:18

从E2E到Playwright Profile:端到端测试的工程化实践指南

1. E2E到底是个什么词1.1 先破题&#xff1a;e2e在不同圈子里的真实含义如果你在技术社区、测试群或者产品群里看到有人丢出"e2e"这个词&#xff0c;大概率是在聊端到端测试&#xff08;End-to-End Testing&#xff09;。但我要先把话说明白——e2e这个词在不同的语境…

作者头像 李华
网站建设 2026/10/26 15:50:34

微信阅读小程序毕设源码拆解:SSM+MyBatis全栈闭环与部署避坑

简介&#xff1a;这是面向计算机相关专业毕业设计、课程设计及项目初期演示的微信阅读小程序全套资料&#xff0c;覆盖小程序前端与 SSM 管理后台&#xff0c;包含可运行源码、论文文档、SQL 脚本、开题报告及答辩 PPT。系统支持用户购买图书章节、在线阅读、发布留言、管理收藏…

作者头像 李华
网站建设 2026/10/26 15:49:49

e2e profile1 端到端测试配置档案:核心链路验证与实操指南

1. 从“e2e”这个标题说起&#xff1a;它到底指什么第一次看到“e2e”这个标题&#xff0c;很多人会愣一下。三个字符&#xff0c;没有上下文&#xff0c;没有修饰词&#xff0c;放在任何技术社区里都像是一个暗号。但如果你在软件工程、测试开发或者质量保障这条线上待过一段时…

作者头像 李华
网站建设 2026/10/26 15:48:07

Ubuntu 22.04与FastAPI高并发API开发部署指南

1. 为什么选择Ubuntu 22.04与FastAPI组合 在Linux发行版中&#xff0c;Ubuntu 22.04 LTS&#xff08;Jammy Jellyfish&#xff09;以其长期支持特性和稳定的软件仓库成为开发者的首选。我实测过多个Python框架在Ubuntu上的表现&#xff0c;FastAPI凭借其异步特性和类型提示&…

作者头像 李华