.png)
这半年多以来,我一直用 n8n 配合 Google Apps Script(GAS)来实现 Zaim 的自动记账,运行得很稳定。但 GAS 终究是一个外部平台,每次想到流程里嵌着一个不完全受自己控制的环节,总觉得不够踏实。这次把 Activepieces 部署到了自己的甲骨文云上,打算用它的 Code 模块替掉 GAS 这一段。试下来 Activepieces 在处理 Zaim 这类没有官方连接器的服务时,确实比 n8n 顺手——至少我在这边跑通了,n8n 那边一直没有成功。
不过这篇先不写完整的自动化流程,重点放在最容易卡住人的前置步骤:获取 Zaim 的 Access Token 和 Access Token Secret。这一步搞定之后,后面接Activepieces时,就可以反复用这套凭证了。
为什么需要先在本地用 Python 跑一遍认证
Zaim 的 API 用的是 OAuth 1.0a,不是现在更常见的 OAuth 2.0。区别在于:每次请求都要用四个凭证(Consumer Key、Consumer Secret、Access Token、Access Token Secret)现场计算一个加密签名,附在请求头里发出去,服务器验证签名通过才认你的身份。
前两个凭证(Consumer Key / Secret)注册应用的时候就拿到了,是固定的。但后两个(Access Token / Secret)需要走一次完整的授权流程才能生成:跳转到 Zaim 的网页、登录、点击允许、拿到一个验证码(PIN),再用这个 PIN 换回最终的 Token。这个过程没法跳过,因为它本质上是 Zaim 在确认”这个应用确实是我本人授权的”。
好消息是,这个流程只需要做一次。拿到 Access Token 和 Access Token Secret 之后,它们就可以一直复用,不需要每次调用 API 都重新走一遍网页授权。
第一步:在 Zaim 开发者中心注册应用
登录 Zaim 后访问 https://dev.zaim.net/,点击”新しいアプリケーションを追加”(添加新应用),按要求填写:
| 字段 | 填写建议 |
|---|---|
| アプリケーション名(应用名) | 随意,例如 MyLocalScript |
| 组织名 | 随意 |
| 应用网站 | 随意,填 https://localhost 也可以 |
| アクセス権限(访问权限) | 按需要勾选”读取”和”写入”,记账需要写入权限 |
| 是否公开 | 选择”不公开” |
提交后会拿到 Consumer ID(即 Consumer Key)和 Consumer Secret,先保存好,后面要用。
第二步:安装依赖库
这里不依赖任何 Zaim 专用的第三方封装库,只用通用的 OAuth 库 requests-oauthlib 直接对接 Zaim 的官方端点。好处是依赖少、行为透明,搬到 Activepieces 的 Code 模块里也只需要声明这一个 Requirement:
pip install requests requests-oauthlib第三步:跑脚本,走一遍网页授权
Zaim 的 OAuth 1.0a 流程涉及三个固定端点:
| 用途 | 端点 |
|---|---|
| 获取临时 Request Token | https://api.zaim.net/v2/auth/request |
| 跳转网页授权 | https://auth.zaim.net/users/auth |
| 换取最终 Access Token | https://api.zaim.net/v2/auth/access |
注意授权页面的域名是 auth.zaim.net,和前后两个 api.zaim.net 不是同一个子域,这个地方很容易写错。新建一个文件,比如 get_token.py:
from requests_oauthlib import OAuth1Session
CONSUMER_KEY = "你的Consumer ID"
CONSUMER_SECRET = "你的Consumer Secret"
REQUEST_TOKEN_URL = "https://api.zaim.net/v2/auth/request"
AUTHORIZE_URL = "https://auth.zaim.net/users/auth"
ACCESS_TOKEN_URL = "https://api.zaim.net/v2/auth/access"
oauth = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET, callback_uri="oob")
# 第一步:获取临时Request Token
fetch_response = oauth.fetch_request_token(REQUEST_TOKEN_URL)
resource_owner_key = fetch_response.get("oauth_token")
resource_owner_secret = fetch_response.get("oauth_token_secret")
print("请在浏览器打开下面的链接完成授权:")
print(f"{AUTHORIZE_URL}?oauth_token={resource_owner_key}")
verifier = input("请输入页面上显示的PIN码:")
# 第二步:用PIN码换取最终的Access Token
oauth = OAuth1Session(
CONSUMER_KEY,
client_secret=CONSUMER_SECRET,
resource_owner_key=resource_owner_key,
resource_owner_secret=resource_owner_secret,
verifier=verifier
)
oauth_tokens = oauth.fetch_access_token(ACCESS_TOKEN_URL)
print("access token:", oauth_tokens.get("oauth_token"))
print("access token secret:", oauth_tokens.get("oauth_token_secret"))执行后,终端会打印出一个授权链接,复制到浏览器打开,登录 Zaim 并点击允许授权,页面会显示一个 PIN 码。把这个 PIN 码粘贴回终端的输入提示后按回车,最终会打印出 Access Token 和 Access Token Secret。
这两个 Token 和密码同等重要,不要直接写进会上传到 Git 仓库的代码文件里,更不要分享给他人。
验证一下能不能用
拿到四个凭证后,可以直接调用 Zaim 的家计簿数据接口测试连通性:
from requests_oauthlib import OAuth1Session
CONSUMER_KEY = "你的Consumer ID"
CONSUMER_SECRET = "你的Consumer Secret"
ACCESS_TOKEN = "刚拿到的access token"
ACCESS_TOKEN_SECRET = "刚拿到的access token secret"
oauth = OAuth1Session(
CONSUMER_KEY,
client_secret=CONSUMER_SECRET,
resource_owner_key=ACCESS_TOKEN,
resource_owner_secret=ACCESS_TOKEN_SECRET
)
response = oauth.get("https://api.zaim.net/v2/home/money", params={"mapping": 1, "limit": 5})
print(response.status_code)
print(response.json())能正常返回状态码 200 和 JSON 数据,说明这四个凭证可以直接拿去给任何能发 HTTP 请求的自动化平台用了。这里要提一句:Zaim API 只能读到手动输入的记录,信用卡或银行账户自动同步进来的数据是取不到的,但这正好符合”通过 Activepieces 主动写入一条记账”的场景,不影响后续使用。
为什么这四个凭证能让 Activepieces 绕开 OAuth 授权界面
Activepieces 目前没有 Zaim 的官方连接器,所以那种”点一下按钮就跳转授权”的标准流程在这里用不上。但这不是问题——因为前面这一套手动流程,本质上就是把”点按钮授权”这件事提前做完了。拿到的四个凭证,相当于一张已经盖过章的通行证,之后无论在哪个平台、哪种语言的脚本里,直接带着这张通行证去请求数据即可,不需要再走一次浏览器登录授权的画面。
小结
Zaim 走的是 OAuth 1.0a,注定要先在本地(或任何能跑 Python 和打开浏览器的环境)完整走一遍授权流程,才能换来可以长期复用的 Access Token 和 Access Token Secret。这一步看起来麻烦,但只需要做一次。之后想换自动化平台、想从 GAS 迁移到 Activepieces 甚至自己写脚本,靠的都是同一套凭证,不用每次都重新折腾。



