如何写收支记账记录脚本

wen 实用脚本 30

本文目录导读:

如何写收支记账记录脚本

  1. 方案一:简易版本(控制台应用)
  2. 方案二:更多功能的版本
  3. 方案三:带GUI界面的版本(使用tkinter)
  4. 使用建议

我来帮你写一个收支记账记录脚本,提供三种不同复杂度的方案,从简单到功能完整。

简易版本(控制台应用)

# simple_accounting.py
import json
from datetime import datetime
import os
class SimpleAccounting:
    def __init__(self, filename="records.json"):
        self.filename = filename
        self.records = self.load_records()
    def load_records(self):
        if os.path.exists(self.filename):
            with open(self.filename, 'r', encoding='utf-8') as f:
                return json.load(f)
        return []
    def save_records(self):
        with open(self.filename, 'w', encoding='utf-8') as f:
            json.dump(self.records, f, ensure_ascii=False, indent=2)
    def add_record(self, type_, amount, category, note=""):
        record = {
            "id": len(self.records) + 1,
            "type": type_,  # "收入" or "支出"
            "amount": float(amount),
            "category": category,
            "note": note,
            "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        self.records.append(record)
        self.save_records()
        print(f"✅ 记录成功:{type_} ¥{amount} - {category}")
    def show_summary(self):
        total_income = sum(r["amount"] for r in self.records if r["type"] == "收入")
        total_expense = sum(r["amount"] for r in self.records if r["type"] == "支出")
        balance = total_income - total_expense
        print(f"\n📊 收支汇总")
        print(f"{'─' * 30}")
        print(f"💰 总收入:¥{total_income:.2f}")
        print(f"💸 总支出:¥{total_expense:.2f}")
        print(f"💎 余额:  ¥{balance:.2f}")
        print(f"📝 总记录:{len(self.records)} 条")
    def show_records(self, limit=10):
        print(f"\n📋 最近记录(最新{limit}条)")
        print(f"{'─' * 60}")
        for record in self.records[-limit:]:
            print(f"{record['date'][:10]} | {record['type']:^4} | ¥{record['amount']:>8.2f} | {record['category']:^8} | {record['note']}")
    def search(self, keyword):
        results = [r for r in self.records if keyword in str(r)]
        print(f"\n🔍 搜索:'{keyword}' - 找到 {len(results)} 条结果")
        for r in results:
            print(f"{r['date'][:10]} | {r['type']:^4} | ¥{r['amount']:>8.2f} | {r['category']:^8} | {r['note']}")
def main():
    app = SimpleAccounting()
    while True:
        print(f"\n{'=' * 40}")
        print("📒 简易记账本")
        print(f"{'=' * 40}")
        print("1. 添加收入")
        print("2. 添加支出")
        print("3. 查看汇总")
        print("4. 查看记录")
        print("5. 搜索记录")
        print("6. 退出")
        choice = input("\n请选择操作 (1-6): ").strip()
        if choice == "1" or choice == "2":
            try:
                amount = input("金额: ")
                category = input("类别 (工资/兼职/奖金/其他): ")
                note = input("备注 (可选): ")
                app.add_record("收入" if choice == "1" else "支出", amount, category, note)
            except ValueError:
                print("❌ 金额输入错误!")
        elif choice == "3":
            app.show_summary()
        elif choice == "4":
            app.show_records()
        elif choice == "5":
            keyword = input("输入搜索关键词: ")
            app.search(keyword)
        elif choice == "6":
            print("👋 再见!")
            break
        input("\n按回车键继续...")
if __name__ == "__main__":
    main()

更多功能的版本

# advanced_accounting.py
import json
import csv
from datetime import datetime, date
import os
from collections import defaultdict
class AccountingSystem:
    def __init__(self, filename="accounting_data.json"):
        self.filename = filename
        self.data = self.load_data()
    def load_data(self):
        """加载数据"""
        if os.path.exists(self.filename):
            with open(self.filename, 'r', encoding='utf-8') as f:
                return json.load(f)
        return {
            "records": [],
            "categories": {
                "收入": ["工资", "奖金", "兼职", "投资", "红包", "其他"],
                "支出": ["餐饮", "交通", "购物", "娱乐", "住房", "医疗", "教育", "其他"]
            }
        }
    def save_data(self):
        """保存数据"""
        with open(self.filename, 'w', encoding='utf-8') as f:
            json.dump(self.data, f, ensure_ascii=False, indent=2)
    def add_record(self, type_, amount, category, note="", date_str=None):
        """添加记录"""
        if date_str is None:
            date_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        record = {
            "id": len(self.data["records"]) + 1,
            "type": type_,
            "amount": float(amount),
            "category": category,
            "note": note,
            "date": date_str,
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        self.data["records"].append(record)
        self.save_data()
        return record
    def get_statistics(self, start_date=None, end_date=None):
        """获取统计信息"""
        records = self.data["records"]
        # 如果指定日期范围,过滤记录
        if start_date and end_date:
            records = [r for r in records if start_date <= r["date"][:10] <= end_date]
        # 计算各类统计
        total_income = sum(r["amount"] for r in records if r["type"] == "收入")
        total_expense = sum(r["amount"] for r in records if r["type"] == "支出")
        # 按类别统计
        income_by_category = defaultdict(float)
        expense_by_category = defaultdict(float)
        for r in records:
            if r["type"] == "收入":
                income_by_category[r["category"]] += r["amount"]
            else:
                expense_by_category[r["category"]] += r["amount"]
        # 按月统计
        monthly_stats = defaultdict(lambda: {"收入": 0, "支出": 0})
        for r in records:
            month = r["date"][:7]
            monthly_stats[month][r["type"]] += r["amount"]
        return {
            "total_records": len(records),
            "total_income": total_income,
            "total_expense": total_expense,
            "balance": total_income - total_expense,
            "income_by_category": dict(income_by_category),
            "expense_by_category": dict(expense_by_category),
            "monthly_stats": dict(monthly_stats)
        }
    def export_to_csv(self, filename="accounting_export.csv"):
        """导出为CSV"""
        with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
            writer = csv.writer(f)
            writer.writerow(["ID", "类型", "金额", "类别", "备注", "日期"])
            for r in self.data["records"]:
                writer.writerow([r["id"], r["type"], r["amount"], r["category"], r["note"], r["date"]])
        print(f"✅ 已导出到 {filename}")
    def show_detailed_report(self):
        """显示详细报表"""
        stats = self.get_statistics()
        print(f"\n{'=' * 50}")
        print("📊 详细财务报表")
        print(f"{'=' * 50}")
        print(f"📍 统计周期:全部")
        print(f"📝 总记录数:{stats['total_records']}")
        print(f"💰 总收入:¥{stats['total_income']:.2f}")
        print(f"💸 总支出:¥{stats['total_expense']:.2f}")
        print(f"💎 结余:¥{stats['balance']:.2f}")
        print(f"\n📈 收入分类明细:")
        print(f"{'─' * 40}")
        for cat, amount in sorted(stats['income_by_category'].items(), key=lambda x: x[1], reverse=True):
            percentage = (amount / stats['total_income'] * 100) if stats['total_income'] > 0 else 0
            print(f"  {cat:^8}: ¥{amount:>8.2f} ({percentage:.1f}%)")
        print(f"\n📉 支出分类明细:")
        print(f"{'─' * 40}")
        for cat, amount in sorted(stats['expense_by_category'].items(), key=lambda x: x[1], reverse=True):
            percentage = (amount / stats['total_expense'] * 100) if stats['total_expense'] > 0 else 0
            print(f"  {cat:^8}: ¥{amount:>8.2f} ({percentage:.1f}%)")
        print(f"\n📅 月度收支趋势:")
        print(f"{'─' * 40}")
        for month in sorted(stats['monthly_stats'].keys()):
            m_stats = stats['monthly_stats'][month]
            balance = m_stats['收入'] - m_stats['支出']
            print(f"  {month}: 收入¥{m_stats['收入']:>8.2f} | 支出¥{m_stats['支出']:>8.2f} | 结余¥{balance:>8.2f}")
def main():
    app = AccountingSystem()
    while True:
        print(f"\n{'=' * 50}")
        print("📒 智能记账系统")
        print(f"{'=' * 50}")
        print("1. 📝 添加收入记录")
        print("2. 📝 添加支出记录")
        print("3. 📊 查看财务报表")
        print("4. 📋 查看最近记录")
        print("5. 🔍 搜索记录")
        print("6. 📤 导出CSV")
        print("7. ⚙️ 管理类别")
        print("8. 🗑️ 删除记录")
        print("0. 🚪 退出")
        choice = input("\n请选择操作 (0-8): ").strip()
        if choice == "1":
            try:
                amount = float(input("💰 金额: "))
                print("类别:")
                for i, cat in enumerate(app.data["categories"]["收入"], 1):
                    print(f"  {i}. {cat}")
                cat_choice = int(input("选择类别编号: ")) - 1
                category = app.data["categories"]["收入"][cat_choice]
                note = input("📝 备注 (可选): ")
                app.add_record("收入", amount, category, note)
                print("✅ 收入记录成功!")
            except (ValueError, IndexError) as e:
                print(f"❌ 输入错误:{e}")
        elif choice == "2":
            try:
                amount = float(input("💰 金额: "))
                print("类别:")
                for i, cat in enumerate(app.data["categories"]["支出"], 1):
                    print(f"  {i}. {cat}")
                cat_choice = int(input("选择类别编号: ")) - 1
                category = app.data["categories"]["支出"][cat_choice]
                note = input("📝 备注 (可选): ")
                app.add_record("支出", amount, category, note)
                print("✅ 支出记录成功!")
            except (ValueError, IndexError) as e:
                print(f"❌ 输入错误:{e}")
        elif choice == "3":
            app.show_detailed_report()
        elif choice == "4":
            limit = input("显示多少条?(默认10): ")
            limit = int(limit) if limit.strip() else 10
            for r in app.data["records"][-limit:]:
                print(f"{r['date'][:10]} | {r['type']:^4} | ¥{r['amount']:>8.2f} | {r['category']:^8} | {r['note']}")
        elif choice == "5":
            keyword = input("🔍 搜索关键词: ")
            results = [r for r in app.data["records"] if keyword in str(r)]
            print(f"找到 {len(results)} 条结果:")
            for r in results:
                print(f"{r['date'][:10]} | {r['type']:^4} | ¥{r['amount']:>8.2f} | {r['category']:^8} | {r['note']}")
        elif choice == "6":
            app.export_to_csv()
        elif choice == "7":
            print("类别管理功能开发中...")
        elif choice == "8":
            try:
                id_to_delete = int(input("输入要删除的记录ID: "))
                app.data["records"] = [r for r in app.data["records"] if r["id"] != id_to_delete]
                app.save_data()
                print(f"✅ 已删除记录 #{id_to_delete}")
            except ValueError:
                print("❌ 无效的ID")
        elif choice == "0":
            print("👋 感谢使用,再见!")
            break
        input("\n按回车键继续...")
if __name__ == "__main__":
    main()

带GUI界面的版本(使用tkinter)

如果你想要图形界面,这里是一个简单的GUI版本:

# gui_accounting.py
import tkinter as tk
from tkinter import ttk, messagebox
from datetime import datetime
import json
import os
class AccountingApp:
    def __init__(self, root):
        self.root = root
        self.root.title("简易记账本")
        self.root.geometry("800x600")
        self.filename = "records.json"
        self.records = self.load_records()
        self.setup_ui()
    def load_records(self):
        if os.path.exists(self.filename):
            with open(self.filename, 'r', encoding='utf-8') as f:
                return json.load(f)
        return []
    def save_records(self):
        with open(self.filename, 'w', encoding='utf-8') as f:
            json.dump(self.records, f, ensure_ascii=False, indent=2)
    def setup_ui(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        # 输入区域
        input_frame = ttk.LabelFrame(main_frame, text="添加记录", padding="10")
        input_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        # 金额输入
        ttk.Label(input_frame, text="金额:").grid(row=0, column=0, sticky=tk.W)
        self.amount_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.amount_var, width=15).grid(row=0, column=1, padx=5)
        # 类型选择
        ttk.Label(input_frame, text="类型:").grid(row=0, column=2, sticky=tk.W)
        self.type_var = tk.StringVar(value="支出")
        ttk.Combobox(input_frame, textvariable=self.type_var, values=["收入", "支出"], width=10, state="readonly").grid(row=0, column=3, padx=5)
        # 类别选择
        ttk.Label(input_frame, text="类别:").grid(row=0, column=4, sticky=tk.W)
        self.category_var = tk.StringVar()
        category_combo = ttk.Combobox(input_frame, textvariable=self.category_var, width=15, state="readonly")
        category_combo.grid(row=0, column=5, padx=5)
        # 根据类型更新类别
        def update_categories(*args):
            if self.type_var.get() == "收入":
                category_combo['values'] = ["工资", "奖金", "兼职", "投资", "红包", "其他"]
            else:
                category_combo['values'] = ["餐饮", "交通", "购物", "娱乐", "住房", "医疗", "教育", "其他"]
            self.category_var.set("")
        self.type_var.trace('w', update_categories)
        # 备注输入
        ttk.Label(input_frame, text="备注:").grid(row=0, column=6, sticky=tk.W)
        self.note_var = tk.StringVar()
        ttk.Entry(input_frame, textvariable=self.note_var, width=20).grid(row=0, column=7, padx=5)
        # 添加按钮
        ttk.Button(input_frame, text="添加记录", command=self.add_record).grid(row=0, column=8, padx=5)
        # 统计信息区域
        stats_frame = ttk.LabelFrame(main_frame, text="统计信息", padding="10")
        stats_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        self.stats_labels = {}
        stats_info = [("总收入", "total_income"), ("总支出", "total_expense"), ("结余", "balance")]
        for i, (label, key) in enumerate(stats_info):
            ttk.Label(stats_frame, text=f"{label}:").grid(row=0, column=i*2, padx=10)
            self.stats_labels[key] = ttk.Label(stats_frame, text="¥0.00", font=("Arial", 10, "bold"))
            self.stats_labels[key].grid(row=0, column=i*2+1, padx=5)
        # 记录列表
        list_frame = ttk.LabelFrame(main_frame, text="收支记录", padding="10")
        list_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
        # 创建表格
        columns = ("日期", "类型", "金额", "类别", "备注")
        self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=15)
        for col in columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)
        self.tree.column("日期", width=120)
        self.tree.column("金额", width=100)
        self.tree.pack(fill=tk.BOTH, expand=True)
        # 滚动条
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.tree.configure(yscrollcommand=scrollbar.set)
        # 操作按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=3, column=0, columnspan=2, pady=10)
        ttk.Button(button_frame, text="删除选中", command=self.delete_record).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="刷新列表", command=self.refresh_display).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="导出数据", command=self.export_data).pack(side=tk.LEFT, padx=5)
        # 初始化显示
        self.refresh_display()
        # 配置grid权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(2, weight=1)
    def add_record(self):
        try:
            amount = float(self.amount_var.get())
            type_ = self.type_var.get()
            category = self.category_var.get()
            note = self.note_var.get()
            if amount <= 0:
                messagebox.showerror("错误", "金额必须大于0")
                return
            if not category:
                messagebox.showerror("错误", "请选择类别")
                return
            record = {
                "id": len(self.records) + 1,
                "type": type_,
                "amount": amount,
                "category": category,
                "note": note,
                "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
            self.records.append(record)
            self.save_records()
            self.refresh_display()
            # 清空输入
            self.amount_var.set("")
            self.category_var.set("")
            self.note_var.set("")
            messagebox.showinfo("成功", f"{type_} ¥{amount:.2f} 记录成功!")
        except ValueError:
            messagebox.showerror("错误", "请输入有效的金额")
    def refresh_display(self):
        # 清空表格
        for item in self.tree.get_children():
            self.tree.delete(item)
        # 计算统计
        total_income = sum(r["amount"] for r in self.records if r["type"] == "收入")
        total_expense = sum(r["amount"] for r in self.records if r["type"] == "支出")
        balance = total_income - total_expense
        # 更新统计信息
        self.stats_labels["total_income"].config(text=f"¥{total_income:.2f}")
        self.stats_labels["total_expense"].config(text=f"¥{total_expense:.2f}")
        self.stats_labels["balance"].config(text=f"¥{balance:.2f}")
        # 添加记录到表格
        for record in reversed(self.records[-100:]):  # 显示最近100条
            self.tree.insert("", "end", values=(
                record["date"][:16],
                record["type"],
                f"¥{record['amount']:.2f}",
                record["category"],
                record["note"]
            ))
    def delete_record(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("警告", "请选择要删除的记录")
            return
        if messagebox.askyesno("确认", "确定删除选中的记录吗?"):
            # 获取选中的记录索引
            for item in selected:
                values = self.tree.item(item)["values"]
                # 查找匹配的记录并删除
                for record in self.records[:]:
                    if (record["date"][:16] == values[0] and
                        record["type"] == values[1] and
                        f"¥{record['amount']:.2f}" == values[2]):
                        self.records.remove(record)
                        break
            self.save_records()
            self.refresh_display()
            messagebox.showinfo("成功", "记录已删除")
    def export_data(self):
        if not self.records:
            messagebox.showwarning("警告", "没有可导出的数据")
            return
        filename = f"accounting_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(self.records, f, ensure_ascii=False, indent=2)
        messagebox.showinfo("成功", f"数据已导出到 {filename}")
if __name__ == "__main__":
    root = tk.Tk()
    app = AccountingApp(root)
    root.mainloop()

使用建议

  1. 选择哪个版本?

    • 如果只是简单用用,方案一就够
    • 想要更多功能,用方案二
    • 想要图形界面,用方案三
  2. 数据存储

    • 所有方案都使用JSON文件存储
    • 可以手动编辑JSON文件
    • 建议定期备份数据文件
  3. 扩展功能

    • 可以添加数据库支持(SQLite)
    • 可以添加图表显示
    • 可以添加预算管理功能
    • 可以添加报表导出功能
  4. 运行方式

    • 保存为.py文件后直接运行
    • 方案三需要安装tkinter(Python自带)

需要我帮你进一步定制某个版本,或者添加特定功能吗?

抱歉,评论功能暂时关闭!