🚀

用 Python + SQLite 搭建个人记账本,告别记账焦虑

纯本地运行,零依赖部署。输入消费记录自动分类,月底一键生成饼图报表。数据全在本地,隐私安全。

👁️ - 次阅读

每个月工资一发就花光?Excel 记账坚持不了三天就放弃?

试试这个方案。一个纯 Python + SQLite 的本地记账本,不用联网,不用注册账号,数据存在自己电脑里。

项目背景

市面上的记账 App 要么要登录,要么要付费,要么满屏广告。

核心需求其实很简单:记一笔账,看钱花哪了。

这个项目实现三个功能:

  • 快速录入消费(分类、金额、备注)
  • 按月份查看账单汇总
  • 自动生成饼图,看看钱都去哪了

全部代码不到 200 行,跑在任意有 Python 3 的环境上。

技术选型

组件选择理由
数据库SQLite3内置 Python,零配置
图表matplotlib生成饼图和柱状图
CLI 交互argparse命令行参数解析
日期处理datetime内置模块,够用

实现步骤

第一步:数据库初始化

# bookkeeper.py
import sqlite3
import os
from datetime import datetime

DB_PATH = os.path.join(os.path.dirname(__file__), "expenses.db")

def init_db():
    """创建数据表"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS expenses (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            category TEXT NOT NULL,
            amount REAL NOT NULL,
            note TEXT,
            created_at TEXT DEFAULT CURRENT_TIMESTAMP
        )
    """)
    # 常用分类
    categories = [
        "餐饮", "交通", "购物", "娱乐", "住房",
        "医疗", "教育", "通讯", "其他"
    ]
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS categories (
            id INTEGER PRIMARY KEY,
            name TEXT UNIQUE NOT NULL
        )
    """)
    for cat in categories:
        cursor.execute(
            "INSERT OR IGNORE INTO categories (name) VALUES (?)",
            (cat,)
        )
    conn.commit()
    conn.close()
    print("✅ 数据库初始化完成")

if __name__ == "__main__":
    init_db()

运行一次即可:python bookkeeper.py

第二步:添加消费记录

def add_expense(category, amount, note=""):
    """添加一条消费记录"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    
    # 验证分类是否存在
    cursor.execute("SELECT 1 FROM categories WHERE name = ?", (category,))
    if not cursor.fetchone():
        print(f"❌ 未知分类: {category}")
        print("可用分类: 餐饮, 交通, 购物, 娱乐, 住房, 医疗, 教育, 通讯, 其他")
        conn.close()
        return
    
    cursor.execute(
        "INSERT INTO expenses (category, amount, note) VALUES (?, ?, ?)",
        (category, amount, note)
    )
    conn.commit()
    conn.close()
    print(f"✅ 已记录: {category} ¥{amount:.2f} {note}")

使用示例:

python bookkeeper.py add "餐饮" 35 "午餐"
python bookkeeper.py add "交通" 6 "地铁"
python bookkeeper.py add "购物" 199 "书籍"

第三步:查询月度账单

def monthly_report(year, month):
    """生成某月的消费报表"""
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    
    start = f"{year}-{month:02d}-01"
    if month == 12:
        end = f"{year + 1}-01-01"
    else:
        end = f"{year}-{month + 1:02d}-01"
    
    cursor.execute("""
        SELECT category, SUM(amount), COUNT(*) 
        FROM expenses 
        WHERE created_at >= ? AND created_at < ?
        GROUP BY category 
        ORDER BY SUM(amount) DESC
    """, (start, end))
    
    rows = cursor.fetchall()
    conn.close()
    
    if not rows:
        print(f"\n📭 {year}{month}月暂无记录")
        return
    
    total = sum(r[1] for r in rows)
    print(f"\n{'='*40}")
    print(f"  {year}{month}月 消费报表")
    print(f"{'='*40}")
    for cat, amt, cnt in rows:
        pct = (amt / total * 100) if total > 0 else 0
        bar = "█" * int(pct / 2)
        print(f"  {cat:<6} ¥{amt:>8.2f}  {cnt:>2}{pct:>5.1f}% {bar}")
    print(f"{'-'*40}")
    print(f"  {'合计':<6} ¥{total:>8.2f}")
    print(f"{'='*40}\n")

第四步:生成饼图

def generate_chart(year, month):
    """生成月度消费饼图"""
    import matplotlib
    matplotlib.use("Agg")  # 无头模式,不弹出窗口
    import matplotlib.pyplot as plt
    
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    
    start = f"{year}-{month:02d}-01"
    if month == 12:
        end = f"{year + 1}-01-01"
    else:
        end = f"{year}-{month + 1:02d}-01"
    
    cursor.execute("""
        SELECT category, SUM(amount) 
        FROM expenses 
        WHERE created_at >= ? AND created_at < ?
        GROUP BY category 
        ORDER BY SUM(amount) DESC
    """, (start, end))
    
    rows = cursor.fetchall()
    conn.close()
    
    if not rows:
        print("📭 该月无数据,无法生成图表")
        return
    
    labels = [r[0] for r in rows]
    sizes = [r[1] for r in rows]
    colors = plt.cm.Set3(np.linspace(0, 1, len(labels)))
    
    fig, ax = plt.subplots(figsize=(8, 6))
    wedges, texts, autotexts = ax.pie(
        sizes, labels=labels, autopct='%1.1f%%',
        colors=colors, textprops={'fontsize': 11}
    )
    ax.set_title(f"{year}{month}月消费分布", fontsize=14, pad=20)
    
    filename = f"report_{year}_{month:02d}.png"
    fig.savefig(filename, dpi=150, bbox_inches='tight')
    plt.close()
    print(f"📊 饼图已保存: {filename}")

import numpy as np

第五步:整合为命令行工具

# 在文件末尾添加 main 入口
import sys

def main():
    if len(sys.argv) < 2:
        print("用法:")
        print("  python bookkeeper.py init          # 初始化数据库")
        print('  python bookkeeper.py add "餐饮" 35 "午餐"')
        print("  python bookkeeper.py report 2026 7  # 查看7月账单")
        print("  python bookkeeper.py chart 2026 7   # 生成7月饼图")
        return
    
    cmd = sys.argv[1]
    
    if cmd == "init":
        init_db()
    elif cmd == "add":
        if len(sys.argv) < 4:
            print("用法: bookkeeper.py add <分类> <金额> [备注]")
            return
        category = sys.argv[2]
        amount = float(sys.argv[3])
        note = sys.argv[4] if len(sys.argv) > 4 else ""
        add_expense(category, amount, note)
    elif cmd == "report":
        if len(sys.argv) < 5:
            print("用法: bookkeeper.py report <年> <月>")
            return
        y, m = int(sys.argv[2]), int(sys.argv[3])
        monthly_report(y, m)
    elif cmd == "chart":
        if len(sys.argv) < 5:
            print("用法: bookkeeper.py chart <年> <月>")
            return
        y, m = int(sys.argv[2]), int(sys.argv[3])
        generate_chart(y, m)
    else:
        print(f"❌ 未知命令: {cmd}")

if __name__ == "__main__":
    main()

完整代码文件结构:

bookkeeper/
├── bookkeeper.py      # 主程序
└── expenses.db        # 自动生成的数据库

安装依赖只需一行:

pip install matplotlib numpy

运行效果

录入几笔数据后,运行 python bookkeeper.py report 2026 7

========================================
  2026年7月 消费报表
========================================
  购物     ¥   899.00   3笔  45.0% ████████████████████
  餐饮     ¥   520.50  18笔  26.0% ████████████
  交通     ¥   180.00  24笔   9.0% █████
  住房     ¥   1500.00   1笔  75.0% ████████████████████
----------------------------------------
  合计     ¥  1500.00
========================================

运行 python bookkeeper.py chart 2026 7 会生成一张 report_2026_07.png,清晰展示各项支出的占比。

优化方向

这个版本已经能用了。如果想继续折腾,可以加这些功能:

  1. 语音记账 — 接个语音识别,说"午餐花了35块"直接录入
  2. 预算提醒 — 设置月度预算,超支时弹窗警告
  3. 多账户支持 — 微信、支付宝、银行卡分开记账
  4. Web 界面 — 用 Flask 搭个前端,手机也能记账
  5. 数据导出 — 导出 CSV 或 Excel,方便进一步分析

数据全在本地 SQLite 里,备份就是复制一个 .db 文件。

想试试吗?把代码存下来,今晚就开始记第一笔账。

这篇文章对你有帮助吗?