背景随手记是金蝶出品的一款记账软件,其实还是不错的,不过我从来没有充过会员,一直也长期用着用了有快三年了,已经有快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文件,在一木记账中打开或者点导入即可成功导入啦!

希望能对大家有所帮助,谢谢!