背景
随手记是金蝶出品的一款记账软件,其实还是不错的,不过我从来没有充过会员,一直也长期用着用了有快三年了,已经有快4000条流水了,每天坚持记账也养成了挺好的习惯。不过近期正好在尝试其他的记账APP,所以发现了竟然还有语音记账和自动记账等功能(自动记账利用的是安卓的无障碍功能识别界面内容来触发),试用了一下还挺好用的。因此我就计划迁移出随手记了,迁移到我试用了还不错的一木记账
App来使用。
但是在迁移的过程中却发现随手记APP的Excel导出是需要会员的,我就导出一下就不用你了竟然收我14块钱一个月的费用,实在太不划算了。
账本的设置-高级功能-备份与同步-导出数据到Excel(CSV)竟然是锁住的,免费版用户导出不了,得充值14块钱一个月才行。
于是到处找解决的方案,最后发现,在设置-高级功能-备份与同步-本地备份与恢复,可以进行免费的导出。导出的文件是kdf后缀的文件,不是常见的文件类型,只有随手记app自己可以导入和解析恢复,那么我们要怎么取到里面的账单内容呢?
一顿好找,最后在吾爱破解找到一个大佬的kdf的解析的文章,其实kdf的本质是一个zip的压缩包里面呢包含了一个sqlite数据库,还有一些其他文件,这个sqlite数据库就是我们需要的账单了。但这个sqlite数据库的文件头是被魔改的,需要改回来才能用。
不过可惜,这位吾爱大佬的文章中给的代码是他自己用的,缺少了非常多的关键信息,因此直接执行是无法执行的,同时我要导入一木记账的代码是并没有的,因此努力修改了一下原始的代码思路,目前已经可以直接使用啦!
将随手记kdf解密并生成可阅读的sqlite数据库
首先我们需要从随手记里面“免费”导出kdf账单文件。
在设置-高级功能-备份与同步-本地备份与恢复中导出即可,然后把该文件传输到电脑的某个上,并修改文件名为record.kdf
方便我们后续的处理。
接下来,运行我们的第一个脚本:
import zipfile
import os
def unzip_kbf(input_files=None):
zf = zipfile.ZipFile(input_files)
zf.extractall(path='./')
def ssj_kbf_sqlite_convert(input_file, output_file):
"""
convert ssj data, after kbf unzip to sqlite,convert it to normal sqlite database file
:param input_file: the mymoney.sqlite file path
:param output_file: the convert mymoney.sqlite file path
:return:
"""
sqlite_header = (0x53, 0x51, 0x4C, 0x69,
0x74, 0x65, 0x20, 0x66,
0x6F, 0x72, 0x6D, 0x61,
0x74, 0x20, 0x33, 0x0)
if os.path.exists(output_file):
os.remove(output_file)
with open(input_file, mode='rb') as f:
with open(output_file, mode='wb') as fw:
data_buffer = f.read()
write_buffer = bytearray(data_buffer)
index = 0
while index < len(sqlite_header):
write_buffer[index] = sqlite_header[index]
index = index + 1
fw.write(write_buffer)
print("convert done")
# 执行kbf文件解密
unzip_kbf("record.kbf")
ssj_kbf_sqlite_convert("mymoney.sqlite", "record_decrypt.sqlite")
此时该文件夹即可生成一个已经解密的record_decrypt.sqlite
文件。
这个文件就是可以直接读取数据的数据了,我们使用一些数据库读取的工具就可以查看里面的内容了,比如navicat等等。其中的t_transaction表就是我们交易的账单了。
当然还有其他的一些表还需要进行联立,我们只需要使用sql的知识把我们需要的字段弄出来即可。
生成导入到一木记账的Excel模板
首先一木记账的模板可以在一木记账APP里面导出来,大概长这样:
于是我也给你提供了我测试好可以导入的获取的代码,使用代码之前你需要安装一下三方的库:
pip install pandas xlwt
接下来是代码:
import sqlite3
import pandas as pd
import xlwt
# 连接到SQLite数据库,如果数据库文件不存在,会自动在当前目录创建一个
# 数据库文件名为example.db
conn = sqlite3.connect('record_decrypt.sqlite')
# 创建一个游标对象,用于执行SQL语句
cursor = conn.cursor()
sql = '''SELECT strftime('%Y-%m-%d %H:%M', a.tradeTime / 1000 + 8 * 3600, 'unixepoch') as 日期,
case
when a.type = 1 then '收入'
when a.type = 0 then '支出'
end as 收支类型,
case
when a.type = 1 then (select case
when (select b.currencyType from t_account b where b.accountPOID = a.sellerAccountPOID) = 'CNY' then a.buyerMoney
else (select round(a.buyerMoney * d.rate, 2) from
(select b.currencyType from t_account b where b.accountPOID = a.sellerAccountPOID) c,
t_exchange d where c.currencyType = d.sell)
end)
when a.type = 0 then (select case
when (select b.currencyType from t_account b where b.accountPOID = a.buyerAccountPOID) = 'CNY' then a.buyerMoney
else (select round(a.buyerMoney * d.rate, 2) from
(select b.currencyType from t_account b where b.accountPOID = a.buyerAccountPOID) c,
t_exchange d where c.currencyType = d.sell)
end)
end as 金额,
case
when a.type = 1 then (select d.name from (select b.parentCategoryPOID from t_category b
where b.categoryPOID = a.buyerCategoryPOID) c, t_category d
where c.parentCategoryPOID = d.categoryPOID)
when a.type = 0 then (select d.name from (select b.parentCategoryPOID from t_category b
where b.categoryPOID = a.sellerCategoryPOID) c, t_category d
where c.parentCategoryPOID = d.categoryPOID)
end as 类别,
case
when a.type = 1 then (select b.name from t_category b where b.categoryPOID = a.buyerCategoryPOID)
when a.type = 0 then (select b.name from t_category b where b.categoryPOID = a.sellerCategoryPOID)
end as 子类,
'日常账本' as 所属账本,
case
when a.type = 1 then (select b.name from t_account b where b.accountPOID = a.sellerAccountPOID)
when a.type = 0 then (select b.name from t_account b where b.accountPOID = a.buyerAccountPOID)
end as 收支账户,
a.memo as 备注,
(select c.name
from t_transaction_projectcategory_map b, t_tag c
where b.transactionPOID = a.transactionPOID
and b.projectCategoryPOID = c.tagPOID
and b.type = 2) as 标签,
'' as 地址
FROM t_transaction a
order by a.tradetime desc;'''
# 运行一个查询语句
select_sql = sql
# 使用游标执行查询
cursor.execute(select_sql)
# 获取所有查询结果
results = cursor.fetchall()
# 打印结果
for row in results:
print(row)
# 将结果转换为DataFrame
columns = [column[0] for column in cursor.description] # 获取列名
df = pd.DataFrame(results, columns=columns)
# 关闭游标和连接
cursor.close()
conn.close()
# 使用xlwt库将DataFrame写入Excel文件
excel_filename = '一木记账导入.xls'
# 创建一个Excel工作簿
wb = xlwt.Workbook()
# 添加一个工作表
ws = wb.add_sheet('Sheet 1')
# 将DataFrame数据写入Excel工作表
for col_num, col_data in enumerate(df.columns):
ws.write(0, col_num, col_data) # 写入列名
for row_num, row_data in enumerate(df.values):
for col_num, col_data in enumerate(row_data):
ws.write(row_num + 1, col_num, col_data) # 写入单元格数据
# 保存Excel文件
wb.save(excel_filename)
print(f'数据已成功写入到 {excel_filename}')
完成后生成的文件效果如下:
接下来就很简单了,使用导出好的这个xls文件,在一木记账中打开或者点导入即可成功导入啦!
希望能对大家有所帮助,谢谢!