引言
在中国,对每个人每月的财务进行统计存在困难。虽然绝大多数人都已经只使用移动支付,所有的消费记录都已经被记录,但是消费记录被保存于腾讯与阿里两家公司中,双方之间信息并不互通。尤其在双方各自的APP上不能使用对方的支付方式,这导致不能只选择一家公司方式进行支付。同时每家公司也没有提供便捷的自动化的导出数据记录的方法,这也许是出于数据安全的考虑。上述原因都对个人财务数据管理造成障碍。
个人财务管理的好处是显而易见的。通过对自己的财务进行统计和分析,可以更好地掌握自己的消费情况,为理性消费提供依据。同时,对于有存款和投资需求的人来说,也可以更好地规划自己的资金流向,更好地实现财富管理。
在这里,我们将使用 Python 将数据导入到 Notion 的数据库中,对数据进行同一管理。Notion 是一种功能强大且易于使用的跨平台软件,可以用来构建个人财务管理系统。使用 Notion 构建个人财务管理系统具有以下优点:
- 可以将多个数据源整合在一个地方,方便进行管理和分析。
- 可以使用 Notion 的多种功能,如表格、图表和日历,更直观地展示数据。
- Notion 的数据记录和导入功能非常方便,可以自动化地导入数据,减少手动输入数据的时间和错误。
正文
1. 获取财务数据
1.1 获取支付宝财务账单
首先登录支付宝 知托付! (alipay.com),扫码登录,下载你所需要导入的数据。
点击交易记录
选择交易时间,点击下载excel格式,最后你会获得一个压缩包,解压缩后是一个csv格式的表格。
1.2 获取微信账单
微信的账单获取要麻烦一些,打开手机版的微信,点击服务,点击钱包,点击右上方的账单,点击常见问题,点击下载账单,填写发送的邮箱,在邮箱里面下载压缩包,压缩包密码会在微信的通知中显示。
2. 获取notion的API秘钥
2.1 获取秘钥
点击网站My integrations | Notion Developers,登录你的notion账号。
点击New integration按钮,进去网页后填写name,点击Submit
2.2 关联页面
进入你需要输入的数据库的页面,使你的页面与API进行关联。
2.3 创建你的数据库
这是我的table模板样式,如果你希望使用我的代码,最好模板样式和我一样。
3 代码编写
3.1 导入python库
import pandas as pd
import requests
Pandas库是一个免费、开源的第三方Python库,是Python数据分析必不可少的工具之一,它为Python数据分析提供了高性能,且易于使用的数据结构,即Series和DataFrame。Requests库是Python的第三方库,是目前公认的爬取网页最好的库之一,特点有简单,代码简洁,甚至一行代码就能爬取到网页。**1** 它使用 Python 语言编写,并且采用了 Apache2 Licensed(一种开源协议)的 HTTP 库。
3.2 删除干扰数据
由于要使用pandas库对csv文件进行解析,所以要删除一些csv文件携带的多余信息。
3.3 测试秘钥
NOTION_KEY = 'secret_XU1b766517dacf018ddc1c0da0fbb869a6'
headers = {'Authorization': f"Bearer {NOTION_KEY}",
'Content-Type': 'application/json',
'Notion-Version': '2022-06-28'}
其中NOTION_KEY的值为2.1步中你获取的秘钥,
search_params = {"filter": {"value": "page", "property": "object"}}
search_response = requests.post(
f'https://api.notion.com/v1/search',
json=search_params, headers=headers)
print(search_response.json())
如果访问成功,通过这串代码可以获得一下结果
{
"object": "list",
"results": [
{
"object": "page",
"id": "4465d9f6-11fd-4fe6-9f29-f263da0d9c12",
"created_time": "2023-03-29T14:10:00.000Z",
"last_edited_time": "2023-03-30T12:22:00.000Z",
"created_by": {
"object": "user",
"id": "c20f3b73-0a58-4b27-8fae-9589dd1de767"
},
"last_edited_by": {
"object": "user",
"id": "c20f3b73-0a58-4b27-8fae-9589dd1de767"
},
"cover": "None",
"icon": "None",
"parent": {
"type": "workspace",
"workspace": true
},
"archived": false,
"properties": {
"title": {
"id": "title",
"type": "title",
"title": [
{
"type": "text",
"text": {
"content": "账单",
"link": "None"
},
"annotations": {
"bold": false,
"italic": false,
"strikethrough": false,
"underline": false,
"code": false,
"color": "default"
},
"plain_text": "账单",
"href": "None"
}
]
}
},
"url": "https://www.notion.so/4465d9f611fd4fe69f29f263da0d9c12"
}
],
"next_cursor": "None",
"has_more": false,
"type": "page_or_database",
"page_or_database": {}
}
3.4 格式化账单
由于支付宝与微信的账单数据格式不统一,都且包含了大量无用的数据,同时有部分数据为退款,或者没有进行交易,所以使用代码对数据进行清洗重构。
def alipay_method(path):
alipay = pd.read_csv(path,encoding='gbk')
alipay = alipay.iloc[:,[8,7,9,2,10,11,]]
alipay.columns = ['name','company','money','time','status','method',]
alipay['time'] = pd.to_datetime(alipay['time'])
alipay = alipay.replace(' ', '', regex=True)
alipay = alipay.loc[alipay['method'].isin(['交易成功','等待确认收货'])]
alipay = alipay.loc[alipay['status'].isin(['支出','收入'])]
alipay['method'] = '支付宝'
alipay['time'] = alipay['time'].dt.strftime('%Y-%m-%dT%H:%M:%S')
return alipay
def weixing_method(path):
weixing = pd.read_csv('微信支付账单(20221229-20230329).csv')
weixing = weixing.iloc[:,[3,2,5,0,4,7,]]
weixing.columns = ['name','company','money','time','status','method',]
weixing['time'] = pd.to_datetime(weixing['time'])
weixing = weixing.replace(' ', '', regex=True)
weixing = weixing.loc[weixing['status'].isin(['支出','收入'])]
weixing['money'] = weixing['money'].replace('¥', '', regex=True)
weixing['money'] = weixing['money'].replace(',', '', regex=True).astype('float')
weixing['method'] = '微信'
weixing['time'] = weixing['time'].dt.strftime('%Y-%m-%dT%H:%M:%S')
return weixing
清洗完后的数据示例,
3.4 导入数据进入notion
def get_json(name,company,money,time,status,method,database_id = 46beab1a-3cf5-4276-b998-1d8afecf62bf):
if method == '支付宝':
color = 'blue'
else :
color = 'green'
if status == '收入':
color1 = 'green'
else:
color1 ='red'
pay_json = {
"parent": {"type": "database_id","database_id": datebase_id},
"properties": {
"交易额度": {"type": "number","number": money},
"交易时间": {"type": "date","date": {"start": time + ".000+08:00"}},
"支入支出": {"type": "status","status": {"name": status,"color": color1}},
"交易对方": {"type": "rich_text","rich_text": [{"type": "text","text": {"content": company,},}]},
"交易方式": {"type": "status","status": {"name": method,"color": color}},
"商品名称": {"type": "title","title": [{"type": "text","text": {"content": name},}]}
}
}
return pay_json
def send_data(pay):
error = []
for i in pay.index:
name = pay['name'][i]
company = pay['company'][i]
money = pay['money'][i]
time = pay['time'][i]
status = pay['status'][i]
method = pay['method'][i]
pay_json = get_json(name,company,money,time,status,method,)
try:
create_response = requests.post("https://api.notion.com/v1/pages", json=pay_json, headers=headers)
if create_response.status_code != 200:
error.append(i)
except:
error.append(i)
return error
其中database_id值为你要导入的数据库的id值,可以在3.3步返回的结果中找到。
3.5 运行程序
if '__name__' == '__main__':
alipay = alipay_method('alipay_record_20230329_2046_1.csv')
weixing = weixing_method('微信支付账单(20221229-20230329).csv')
pay = pd.concat([weixing,alipay]).reset_index(drop=True)
pay.to('pay.csv')
error = send_data(pay)
print(error)
最后运行程序,打印的结果为因为各种原因导入失败的行索引,这个索引要在pay中寻找。
3.6 运行结果
结尾
所有代码欢迎参考,在你使用时可能会出现各种各样的bug,这很正常。如果缺乏python基础,这个方法对你来说可能比较困难,你可以尝试一些低代码方案,例如 Zapier。