共计 12547 个字符,预计需要花费 32 分钟才能阅读完成。
需要背景:
为了更好的解放双手,进步记账效率,自己想要制作一个基于 python 的自动化记账程序,用于统计自己每星期、每月、每年,甚至是每日的盈亏记录,目前该程序是处于半自动化状态,前期会逐步更新,争取全套流程纯自动化,不须要过多的人工参加,解脱苦哈哈记账统计的耗时工作
需要总指标:
日账目:连贯罕用的领取通信软件,将本人每破费一笔,就主动归类在一个长期存储地位,而后这个长期存储地位能够用 excel 格局记录存储,并将其下载到指定的电脑桌面地位
星期账目:对一星期的花销和盈收做出统计,并用图的形式展现各种类花销状况和支出状况
月账目:对一个月(即四个星期)的花销和盈收做出统计,并用图的形式展现各种类花销状况和支出状况
年账目:对一年(即 12 个月)的花销和盈收做出统计,并用图的形式展现各种类花销状况和支出状况
唠嗑本次记账程序 2.0 呈现背景:
上次写过一篇记账程序 1.0,我对其中含有的破绽进行填坑。这里有传送门:自动化记账程序 1.0,简短回顾一下,上次的程序只是对一星期的的总收支和总收入收集并统计,并实时计算出残余的余额还有多少。可是这未免过于枯燥,因为这个只能是简略形容,并不能让人更加清晰晓得本人的支出是在哪一块占据的多?本人的收入是在哪一块占据的多?并且纯数字的展现,会不会对数字不敏感的人不敌对呀(比如说自己)
本次记账程序 2.0 的指标:
对上次的记账程序 1.0 做出改良,额定减少对收 / 支品种的展述和对收 / 支品种的数据统计,并叠加对一星期总收入、总支出和残余额的柱状图出现,和对收 / 收入品种的数据统计的饼图出现。
具体内容
后期筹备工作
这次实现记账程序 2.0 的筹备工作,是基于上次的记账程序 1.0,这里有传送门:自动化记账程序 1.0;除此之外,还要额定下载一个新 python 库,名为 xlsxwriter 库,这个库秒杀之前我给你们介绍的 xlwt 库,它不仅能写入数据,还能绘图,也反对 xlsx 格局的文件。如何下载,这里我因为篇幅起因,就只抛出外围代码:pip install xlsxwriter,具体如何操作,能够回顾我上一篇文章,这里有传送门:自动化记账程序 1.0。
编码思路:
在实现自动化记账程序时,容我先捋清一下思路:
1. 思想认识上,这个是基于上一篇文章的思路并进行改进,额定新增对一星期收 / 支类别统计,并以可视化图形出现的,第一次看这篇文章的肯定要回顾上一期我写过的记账程序 1.0 呀【重要事件说三遍~】
2. 对新增局部首先要对本来 excel 模板做出改良
3. 记录单表状况下,对收 / 支品种的名称获取,并将其中波及到每个收 / 支的金额做统计
4. 而后扩大范围,从记录单表到扩充到多表(即从 2021 年 5 月 30 号到 2021 年 6 月 5 号的记账表)
5. 接下来就是对图形的绘制了,这里包含绘制支出、收入和残余利润的柱形图和收 / 支的类别数据的饼图
6. 并将统计到的数据后果应用 xlsxwriter 库写入到 excel 表中,当然,本次不会再应用 xlwt 库,将会对本来程序 1.0 的写入 excel 代码做出扭转
7. 打包成.exe 脚本,这里就不会具体介绍实现过程,只抛出外围代码和后果,不懂的可翻阅我写过的记账程序 1.0【重要事件说四遍~~】
开始编码:
编码思路意识分明后,就欢快编码了:
excel 模板革新
以上这副图是程序 1.0 的 excel 模板
以上这幅图是改进后,程序 2.0 的 excel 模板
这个在接下来程序定位获取数据的时候很重要,如果是小白,能够对照查看
导入第三方库
这里要导入三个 python 库,别离是 xlrd 库、calendar、xlsxwriter
导入库的源码如下【含正文,最好手动敲写】
import xlrd# 从 Excel 文件读取数据和格式化信息的库,反对.xls 以及.xlsx 文件
import calendar# 导入日历库
import xlsxwriter # 用于将数据和格式化信息写入 Excel 文件的库
对收 / 收入品种形容做单表统计
要实现收 / 收入品种形容做单表统计,能够先从如何实现收入品种形容的单表统计开始,思路是:
关上文件 –> 抉择要统计数据的表格 –> 获取数据 –> 用函数来进行封装
对单表的收入品种描述统计的源码如下【含正文,最好手动敲写】:
# 获取最残缺的收入分类字典,其中 end_time 为完结工夫:def get_full_pay_series(end_time):
# 存储残缺的收入品种名称
full_pay_series = {}
# 确定文件门路
excel_url = str(end_time)
# 关上 xlsx 的文件
data = xlrd.open_workbook(excel_url)
#关上第一张表
table = data.sheets()[0]
# 获取第四行的品种数据【从 0 开始】pay_series = table.row_values(3)
# 去除品种列表里的空值:while "" in pay_series:
pay_series.remove("")
# 将残缺的品种遍历,并存储到 full_series 字典中,并设置其默认值是 0
for single_series in pay_series[1:]:
full_pay_series.setdefault(single_series,0)
return full_pay_series
同理,获取单表支出品种的办法也是相似的。
对单表的支出品种描述统计的源码如下【含正文,最好手动敲写】:
# 获取最残缺的支出分类字典,其中 end_time 为完结工夫:def get_full_income_series(end_time):
# 存储残缺的支出品种名称
full_income_series = {}
# 确定文件门路
excel_url = str(end_time)
# 关上 xlsx 的文件
data = xlrd.open_workbook(excel_url)
#关上第一张表
table = data.sheets()[0]
# 获取第八行的品种数据【从 0 开始】income_series = table.row_values(7)
# 去除品种列表里的空值:while "" in income_series:
income_series.remove("")
# 将残缺的品种遍历,并存储到 full_series 字典中,并设置其默认值是 0
for single_series in income_series[1:]:
full_income_series.setdefault(single_series,0)
return full_income_series
对收 / 收入品种金额做单表统计
这个问题和方才讲述如何对收 / 收入品种形容做单表统计的问题有殊途同归收入,解决的形式仍旧是:
关上文件 –> 抉择要统计数据的表格 –> 获取数据 –> 用函数来进行封装
对单表的收入品种金额统计的源码如下【含正文,最好手动敲写】:
# 获取单张表的收入金额
def get_single_pay_series(pay_url):# pay_url 为收入表的门路
# 确定文件门路
excel_url = str(pay_url)
# 关上 xlsx 的文件
data = xlrd.open_workbook(excel_url)
#关上第一张表
table = data.sheets()[0]
# 获取第四行的品种数据【从 0 开始】pay_series = table.row_values(3)
# 去除品种列表里的空值:while "" in pay_series:
pay_series.remove("")
# 获取第六行的品种收入金额数据【从 0 开始】pay_series_val = table.row_values(5)
# 去除品种列表里的空值:while "" in pay_series_val:
pay_series_val.remove("")
# 将收入品种和收入品种金额,用字典存储起来
pay_series_dict = dict(zip(pay_series[1:],pay_series_val[1:]))
return pay_series_dict
对单表的支出品种金额统计的源码如下【含正文,最好手动敲写】:
# 获取单张表的支出金额
def get_single_income_series(income_url):# income_url 为支出表的门路
# 确定文件门路
excel_url = str(income_url)
# 关上 xlsx 的文件
data = xlrd.open_workbook(excel_url)
#关上第一张表
table = data.sheets()[0]
# 获取第八行的品种数据【从 0 开始】income_series = table.row_values(7)
# 去除品种列表里的空值:while "" in income_series:
income_series.remove("")
# 获取第十行的品种收入金额数据【从 0 开始】income_series_val = table.row_values(9)
# 去除品种列表里的空值:while "" in income_series_val:
income_series_val.remove("")
# 将收入品种和收入品种金额,用字典存储起来
income_series_dict = dict(zip(income_series[1:],income_series_val[1:]))
return income_series_dict
获取一星期的表的支出和收入品种数据统计
从单表到对表,获取的思路大略相似,惟一不同是对多个文件进去的解决,因为我仍旧是遵循用工夫来定义每天的记账记录,因而要对工夫做解决,不懂的可翻阅我写过的记账程序 1.0【重要事件说五遍~】,并且要用字典或者列表装载后果,这里我两种都有应用。
获取一星期的表的支出和收入品种数据统计的源码如下【含正文,最好手动敲写】:
# 获取一星期的表的支出和收入品种数据统计
# start 取记账的开始日期,如 2021-5-23
# end 取记账的完结日期,如 2021-5-29
def get_pay_and_income_series(start,end):
# 存储所有收入和支出的品种和值
all_series_and_value = []
# 分隔开始工夫,分成年月日
start_split = str(start).split("-")
# 分隔完结工夫,分成年月日
end_split = str(end).split("-")
# 确定完结文件的门路
end_excel_url = "../ 1 日账单 /{}-{}-{}.xlsx".format(end_split[0],end_split[1],end_split[2])
# 残缺的收入品种名称【以最初的完结文件为主】full_pay_series = get_full_pay_series(end_excel_url)
# 残缺的支出品种名称【以最初的完结文件为主】full_income_series = get_full_income_series(end_excel_url)
# 判断开始和完结的月份是否统一
if int(start_split[1]) == int(end_split[1]):
# 获取指定这个月的开始 到 完结的账单名
for this_day in range(int(start_split[2]),int(end_split[2])+1):#【this_day 指的是月的天数】# 确定文件门路
this_excel_url = "../ 1 日账单 /{}-{}-{}.xlsx".format(start_split[0],start_split[1],this_day)
# 获取单张表的收入品种和金额【索引从 0 开始】pay = get_single_pay_series(this_excel_url)
# 遍历单张表的收入品种名称和金额
for key,value in pay.items():
# 如果收入品种名称在残缺的收入品种名称中
if key in full_pay_series:
# 则取出他的值进行累计
full_pay_series[key] += value
else:
# 否则放弃不变
full_pay_series[key]
# 获取单张表的支出品种和金额【索引从 0 开始】income = get_single_income_series(this_excel_url)
# 遍历单张表的收入品种名称和金额
for key,value in income.items():
# 如果收入品种名称在残缺的收入品种名称中
if key in full_income_series:
# 则取出他的值进行累计
full_income_series[key] += value
else:
# 否则放弃不变
full_income_series[key]
else:
# 获取这月的总天数
this_month_day = calendar.monthlen(int(start_split[0]),int(start_split[1]))
# 前局部:获取指定月的开始 到 这月完结的账单名
for pre_day in range(int(start_split[2]),this_month_day+1):#【pre_day 指的是这个月 / 年的天数】# 确定文件门路
pre_excel_url = "../ 1 日账单 /{}-{}-{}.xlsx".format(start_split[0],start_split[1],pre_day)
# 获取单张表的收入品种和金额【索引从 0 开始】pay = get_single_pay_series(pre_excel_url)
# 遍历单张表的收入品种名称和金额
for key,value in pay.items():
# 如果收入品种名称在残缺的收入品种名称中
if key in full_pay_series:
# 则取出他的值进行累计
full_pay_series[key] += value
else:
# 否则放弃不变
full_pay_series[key]
# 获取单张表的支出品种和金额【索引从 0 开始】income = get_single_income_series(pre_excel_url)
# 遍历单张表的收入品种名称和金额
for key,value in income.items():
# 如果收入品种名称在残缺的收入品种名称中
if key in full_income_series:
# 则取出他的值进行累计
full_income_series[key] += value
else:
# 否则放弃不变
full_income_series[key]
# 后局部:获取新月的开始 到 指定月完结的账单名
for after_day in range(1,int(end_split[2])+1):#【after_day 指的是新月 / 新年的天数】# 确定文件门路
after_excel_url = "../ 1 日账单 /{}-{}-{}.xlsx".format(end_split[0],end_split[1],after_day)
# 获取单张表的收入品种和金额【索引从 0 开始】pay = get_single_pay_series(after_excel_url)
# 遍历单张表的收入品种名称和金额
for key,value in pay.items():
# 如果收入品种名称在残缺的收入品种名称中
if key in full_pay_series:
# 则取出他的值进行累计
full_pay_series[key] += value
else:
# 否则放弃不变
full_pay_series[key]
# 获取单张表的支出品种和金额【索引从 0 开始】income = get_single_income_series(after_excel_url)
# 遍历单张表的收入品种名称和金额
for key,value in income.items():
# 如果收入品种名称在残缺的收入品种名称中
if key in full_income_series:
# 则取出他的值进行累计
full_income_series[key] += value
else:
# 否则放弃不变
full_income_series[key]
# 将一星期收入的品种和金额退出 all_series_and_value 列表中
all_series_and_value.append(full_pay_series)
# 将一星期支出的品种和金额退出 all_series_and_value 列表中
all_series_and_value.append(full_income_series)
return all_series_and_value
注:如果想要检测一下本人写的办法是否可行,能够做一个部分测试,就是调用本人写的函数来查看本人有没有胜利获取本人想要的数据
# 简略部分测试本人有无获取到数据
result2 = get_pay_and_income_series("2021-5-30","2021-6-5")
print(result2)
以上是自己本人测试的代码,仅作为参考,失去的效果图如下:
绘制柱状图,用作对“收入 - 支出 - 利润”的可视化出现
这里是新增局部,绘图次要抓住获取绘图的数据,绘图的系列数据(蕴含绘图的 x / y 地位)、图表的头部题目和 x / y 轴的题目、图表的格调和款式(这个看集体须要,都是润饰和丑化的)。
这部分,自己倡议小白最好尝试先用 xlsxwriter 库绘制一个柱状图,懂其中的应用办法,再依据业务须要写个函数封装起来,不便间接应用。
“收入 - 支出 - 利润”的柱形图绘制的源码如下【含正文,最好手动敲写】:
# 绘制柱状图
'''
参数解说:sheet_name:为工作表名
x_start_cell:为 x 轴的数据开始
x_end_cell:为 x 轴的数据完结
y_start_cell:为 y 轴的数据开始
y_end_cell:为 y 轴的数据完结
out_line_color:为柱状图的外框线【默认是 yellow】bar_title:为设置柱状图的题目
bar_x_axis:为设置 X 轴的名称
bar_y_axis:为设置 Y 轴的名称
tar_set_cell:为图表安放的地位
x_offset:设置 X 轴的偏移量【默认是 25】y_offset:设置 Y 轴的偏移量【默认是 10】'''
def char_bar(sheet_name,x_start_cell,x_end_cell,
y_start_cell,y_end_cell,bar_title,bar_x_axis,
bar_y_axis,tar_set_cell,out_line_color="yellow",x_offset=25,y_offset=10):
# 将其所有输出的参数汇合在同一个列表中,通通转换成字符型数据
origin_data = [sheet_name,x_start_cell,x_end_cell,y_start_cell,y_end_cell,out_line_color,bar_title,bar_x_axis,bar_y_axis,tar_set_cell]
## 将列表里的数据通通转换成字符型数据
str_data = list(map(str,origin_data))
## 创立一个柱状图(column chart)chart = workbook.add_chart({"type":"column"})
## 配置第一个系列数据
chart.add_series({# "name":"={}!${}${}".format(str_data[0],str_data[1][0],str_data[1][1]),# 设置指标头部属性数据
"categories":"={}!${}${}:${}${}".format(str_data[0],str_data[1][0],str_data[1][1],str_data[2][0],str_data[2][1]),# 设置 x 轴的数据
"values":"={}!${}${}:${}${}".format(str_data[0],str_data[3][0],str_data[3][1],str_data[4][0],str_data[4][1]),# 设置 y 轴的数据
"line":{"color":str_data[5]},# 设置柱状图的外框线
})
# 设置图表的题目、X 轴、Y 轴的信息
chart.set_title({"name":str_data[6]})
chart.set_x_axis({"name":str_data[7]})
chart.set_y_axis({"name":str_data[8]})
## 设置图表格调
chart.set_style(1)
# 把图表插入到工作表,以及设置其偏移
worksheet.insert_chart(str_data[9],chart,{"x_offset":x_offset,"y_offset":y_offset})
绘制饼图,用作对 ” 收入的品种和金额 ” 和 ” 支出的品种和金额 ” 的可视化出现
饼图和柱形图绘制的思路是统一的,只不过选用的图类型不一样而已。
“ 收入的品种和金额 ” 和 ” 支出的品种和金额 ” 的饼图绘制的源码如下【含正文,最好手动敲写】:
# 绘制饼图
'''
参数解说:sheet_name:为工作表名
series_start_cell:为品种的数据开始
series_end_cell:为品种的数据完结
value_start_cell:为品种的数据体开始
value_end_cell:为品种的数据体完结
bar_title:为设置饼图的题目
tar_set_cell:为图表安放的地位
x_offset:设置 X 轴的偏移量【默认是 25】y_offset:设置 Y 轴的偏移量【默认是 10】'''
def chart_pie(sheet_name,series_start_cell,series_end_cell,
value_start_cell,value_end_cell,bar_title,tar_set_cell,x_offset=25,y_offset=10):
# 将其所有输出的参数汇合在同一个列表中,通通转换成字符型数据
origin_data = [sheet_name,series_start_cell,series_end_cell,value_start_cell,value_end_cell,bar_title,tar_set_cell]
## 将列表里的数据通通转换成字符型数据
str_data = list(map(str,origin_data))
## 创立一个饼图(pie chart)
chart = workbook.add_chart({"type":"pie"})
## 配置第一个系列数据
chart.add_series({"categories":"={}!${}${}:${}${}".format(str_data[0],str_data[1][0],str_data[1][1],str_data[2][0],str_data[2][1]),# 获取指标头部属性
"values":"={}!${}${}:${}${}".format(str_data[0],str_data[3][0],str_data[3][1],str_data[4][0],str_data[4][1]),# 获取外面的数据体
})
## 设置图表的题目的信息
chart.set_title({"name":str_data[5]})
## 设置图表的格调
chart.set_style(10)
## 把图表插入到工作表,以及设置其偏移
worksheet.insert_chart(str_data[6],chart,{"x_offset":x_offset,"y_offset":y_offset})
数据写入
祝贺你,直到这里,对后期的数据统计和数据绘图就完结了,当初是间接将整顿好的数据写入并绘图了
然而要留神,这里的数据写入是用 xlsxwriter 库编写的,切记不可应用 xlwt 库哦~
数据写入的源码如下【含正文,最好手动敲写】:
# 一星期内容汇总
# start 取记账的开始日期,如 2021-5-23
# end 取记账的完结日期,如 2021-5-29
def write_pay_and_income(start,end):
# 筹备要写入的数据
##“收入 - 支出 - 利润”的表头
headings1 = ["总支出","总收入","残余利润"]
## 获取一星期表的支出和收入的数据
accounts_value = get_pay_and_income(start,end)
##“收入 - 支出 - 利润”的表体
data1 = [accounts_value[0],accounts_value[1],accounts_value[1]-accounts_value[0]]
## "收入的品种和金额" 的表头
headings2 = ["收入品种","收入金额"]
## "收入的品种和金额" 的表体
data2 = [list(get_pay_and_income_series(start,end)[0].keys()),
list(get_pay_and_income_series(start,end)[0].values()),
]
## "支出的品种和金额" 的表头
headings3 = ["支出品种","支出金额"]
## "支出的品种和金额" 的表体
data3 = [list(get_pay_and_income_series(start,end)[1].keys()),
list(get_pay_and_income_series(start,end)[1].values()),
]
# 段落款式设计
## 表头
header_style = {
'bold':True,
'font_name':"微软雅黑",
'border':True,
'align':'center',
'valign':'vcenter',
'bg_color':'yellow'
}
header_style_set = workbook.add_format(header_style)# 款式增加
## 表体
text_style = {
'font_name':"微软雅黑",
'border':True,
'align':'center',
'valign':'vcenter'
}
text_style_set = workbook.add_format(text_style)# 款式增加
# 设置 H 列的宽度为 14
worksheet.set_column("H:H",14)
# 数据写入
## 单数据写入
worksheet.write(0,0,"一星期的收支状况剖析")
worksheet.write(0,4,"一星期的收 / 收入品种剖析")
worksheet.write(2,4,"收入品种",header_style_set)
worksheet.write(3,4,"收入金额",header_style_set)
worksheet.write(5,4,"支出品种",header_style_set)
worksheet.write(6,4,"支出金额",header_style_set)
## 多数据写入
### 写入“收入 - 支出 - 利润”的表头
worksheet.write_row("A3",headings1,header_style_set)
### 写入“收入 - 支出 - 利润”的表体
worksheet.write_row("A4",data1,text_style_set)
### 写入 "收入的品种和金额" 的表头
worksheet.write_row("F3",data2[0],text_style_set)
### 写入 "收入的品种和金额" 的表体
worksheet.write_row("F4",data2[1],text_style_set)
### 写入 "支出的品种和金额" 的表头
worksheet.write_row("F6",data3[0],text_style_set)
### 写入 "支出的品种和金额" 的表体
worksheet.write_row("F7",data3[1],text_style_set)
# 绘图
##“收入 - 支出 - 利润”的柱状图
char_bar(sheet_name = "七天汇总",x_start_cell = "A3",
x_end_cell="C3",y_start_cell = "A4",y_end_cell = "C4",out_line_color = "red",
bar_title = "收支状况图",bar_x_axis = "属性",bar_y_axis = "数值",tar_set_cell="A10")
## "收入的品种和金额" 的饼图
chart_pie(sheet_name = "七天汇总",series_start_cell = "F3",series_end_cell = "L3",
value_start_cell = "F4",value_end_cell = "L4",bar_title = "收入品种剖析",tar_set_cell="I10")
## "支出的品种和金额" 的饼图
chart_pie(sheet_name = "七天汇总",series_start_cell = "F6",series_end_cell = "L6",
value_start_cell = "F7",value_end_cell = "I7",bar_title = "支出品种剖析",tar_set_cell="Q10")
# 敞开文件
workbook.close()
自定义交互
当然以上这些都是用函数封装好了的,如果要应用,必须要调用其中的函数才能够哦~
自定义交互的源码如下【含正文,最好手动敲写】:
start_time = input("开始工夫:")# 设定账单统计开始工夫,这里输出 "2021-5-30"
end_time = input("完结工夫:")# 设定账单统计开始工夫,这里输出 "2021-6-5"
# 确定保留文件的门路
save_url = "./{}到 {} 的汇总表.xlsx".format(start_time,end_time)
# 筹备工作薄
workbook = xlsxwriter.Workbook(save_url)
# 创立 sheet 工作表【表名可写可不写,不写默认是 sheet1】worksheet = workbook.add_worksheet("七天汇总")
write_pay_and_income(start_time,end_time)
生成.exe 程序
到这里,你曾经实现了外围的编码过程,当初正是将你写好的程序做成.exe 程序吧。思路是:将.ipynb 转换成.py 文件将.py 程序生成.exe 文件,不懂的可翻阅我写过的记账程序 1.0【重要事件不知说了几遍了~~】
这里抛出的是将.py 程序生成.exe 的外围代码,如下图
效果图如下:
结语
记账零碎 2.0 就算实现了,就终结了……吗?嘻嘻,留个悬念,看本人能不能憋个大招,让各位看官耳目一新~