我が家の家計簿システムについて

この記事はカレーのち ぴょこりんクラスタ Advent Calendar 2018のために書いたものです。 ちなみにこのAdvent Calendarが何なのかについては、主催者による紹介記事をみてください。

サマリ

  • 我が家の家計簿(支出しか記録してないけど)システムについて紹介する
  • 家計簿システムの機能
    • 月ごとの累計支出額計算
    • 月ごとの各自の負担分の計算
    • 支出状況の可視化

はじめに

お金を貯めたい、でも貯まってる感がない。ボーナスでなんとなく貯まることもあれば、 財形で別口座に逃がしているという謎の安心を感じることもある。 そう、俺たちは雰囲気で家計をやりくりしている。

例えば、こんなことはないだろうか。

  • 今月は飲み会多かったけど飲み会だし大したことない
  • 今月は自分へのご褒美だから出費は多少増えているけど費用対効果は高いのでOK
  • 今月はボーナス出たからだいたいプラマイゼロかプラスになっているはず
  • 毎日コーヒーを買うくらいの自由はあるし、まあそんなに高くないから大丈夫でしょ

こんな感じの理屈で自分を納得させたことは数え切れないほどあるはずだ。 これらの共通点は定量性のなさだ。定量的に把握できないから、雰囲気でやりくりすることになってしまう。

お金を使うことは問題ではない。いくら使っているかわからないのが問題である。 いくら使っているのかわからないと、毎月赤字なのか黒字なのかわからない。だから、お金が貯まらない。 そんな状況を脱出するためには、まず自分が何に対して使っているのか知らなければならない。

収支を知るための道具の1つに、家計簿がある。 今回は、家計簿への支出の記録・集計・可視化のために何をやっているかをまとめる。

家計簿システムの要件と実現方式

以下の表にまとめる。

# 分類 要件 実現方式 理由など
1 記録 家族が各自支出を入力できる Zaimの共通アカウントを用意して、それぞれのスマホからZaimアプリで入力する 使ったことがあったから
2 記録 過去データの取得 自作の取得ツール ZaimにはRead onlyだけどAPIがあるから。手動は絶対に続かない。
3 記録 過去データの保存 SQLiteの利用 慣れてるPythonから特別なライブラリ不要で使えて、あとで加工も簡単にできそうだから。何より新しくデータベースをインストールして依存関係を増やすのが嫌だから。
4 集計 各自の支出分と負担分を算出する 自作の計算ツール Zaimの共通アカウントにはそういう機能がないため
5 可視化 集計結果の表化 Google Spreadsheet + 自作のアップロードツール どこからでもブラウザがあれば見られるから。あと、最悪Zaim乗り換えても、Google Spreadsheetは乗り換えないから。
6 可視化 集計結果のグラフ化 Redash SQLiteをデータソースとして選択できて、それなりに開発がされてそうだったから。あと、ブラウザから結果を見るのはもちろん、SQLクエリも書けるから。

我が家の家計簿システムの概要

我が家の家計簿システムの概要は以下の図のとおり。

f:id:nbisco:20181208224442p:plain
家計簿システムの概要

使い方は以下のとおり。

  • 記録・集計
    1. 各自がZaimのアプリから逐次支出を記録
    2. 毎日1回、Zaimのサーバからデータを取得して、SQLite3に反映
    3. 毎月最終日には、その月分の支出をまとめてGoogle Spreadsheetにアップロード
  • 可視化された結果の確認
    1. 月の初日に、各自の支出額、負担額を確認
    2. 週1回くらい*1に今月の支出状況の確認

家計簿システムのソースコード

github.com

Google Sheets APIのサンプルを流用して作ってるので、Apache License。 個人情報っぽいところは全部落とした・・・はず・・・。 正直申し訳ないのは、githubに上げたにも関わらず他人が使えるような状態じゃないところで、 ある意味技術ポエムと言うべきものになっている*2

道具の紹介

ここでは使ってるもの、作ったものについて紹介する。

Zaim

Zaimとは、有名な家計簿アプリの1つ。 我が家では、家族用アカウントを作って、それぞれのスマホから入力するようにしている。 見た目はわかりやすいし、入力にも困らないので、他*3を試すことなく使い続けている。

だいたいにおいて困らないZaimだけど、いくつかいまいちな点がある。例えば以下。

  • APIがRead Onlyなところ。定期的な固定出費(例えば家賃とか)を自動入力したい。 1/19に再確認したら普通にWriteできるAPIがあった。何かと誤解していたのかな?
  • 誰が入力したかわからないところ。そのせいでカテゴリをかなり細かく分けざるを得なかった。
  • カテゴリの追加が面倒。

Google Spreadsheet

もはや説明はいらない。本当に便利でありがたいですね。 家計簿以外に何かを集計したり、作業リスト代わりにしたりと、我が家では大活躍。

SQLite

SQLデータベースエンジンの実装の1つ。データベースエンジンと言っても、単にライブラリPythonさえあれば使えるので、今回のような小規模利用で依存関係増やしたくない場合にちょうどいいと思う。

Redash

データ可視化ツールの1つ。きれいなグラフを作ってくれるし、Dockerイメージも配布されているので導入も簡単。 案外、SQLiteがデータソースに選べる可視化ツールはあまりなくて、選択肢は実質これくらいだったような気がする。

自作ツール

ファイルとやってくれること

以下のとおり。

  • get_zaim_auth_key.py: ユーザが直接実行する
    • ZaimのAPIキーを取得してくれるが、完全自動じゃない(いまいち)
  • db_build.sh: ユーザが直接実行する
    • 現在あるデータベース(固定でzaim.db)を消す
    • SQLiteファイルを作成する(実際に処理をするのはdbgen.py)
    • Zaimから過去データを吸い上げてSQLiteファイルに格納する(実際に処理するのはzaimapi.py)
  • dbgen.py: ユーザが直接実行しない
    • SQLiteファイルを作成する
  • gspread.py: ユーザが直接実行しない
    • Google Sheets APIを叩いて、Zaimから取ってきたデータをアップロードする
  • zaimapi.py: ユーザが直接実行しない
    • Zaim APIを使ってデータを取得する
    • 取得したデータをSQLiteに格納する
  • zaim.py: ユーザが直接実行することもある
    • Zaim APIを使ってデータを取得し、SQLiteを更新する(実際に処理するのはzaimapi.py)
    • 各自の負担分を計算する
    • (指示されたときだけ)Google Sheets APIを使って、データをアップロードする(実際に処理するのはgspread.py)
  • kakeibo.sh: ユーザが直接実行する
    • zaim.pyをキックして出力をログファイルに残す(ずっと残り続けるのでいまいち)
    • 最終日かどうかを判定して、Google Sheets APIを叩くかどうか決める
  • packages.txt
    • pipで使っているパッケージ群

使い方の流れ

以下、全てcloneしたディレクトリ直下にいることを前提とする。 カテゴリ作成と認証が面倒だけど、最初1回だけなので耐える。

Zaimでのカテゴリ作成

負担分を明確にするには、誰が何のために払ったかを明確にする必要がある。 Zaimのいまいちなところは誰が払ったかわからないところなので、そのための情報を カテゴリにいれる。つまり、入力者分だけカテゴリを作らなきゃいけないので重労働が発生する。 さらに、個人出費も記録できるようにするため、さらにその倍カテゴリを作らなければならない。これは苦役である。

githubソースコード上は、alphaさんとbetaさんの2人で記録するという体にしてある。

ZaimのOAuth認証~DB作成まで

一部蛮族的操作が必要なのはすまない気持ちでいっぱいだが、初回1回だけなので耐える。

  1. Zaimの開発者アカウントを作成する(単にログインすればよい)
  2. ここを参考にZaimアプリケーションを登録し、Consumer IDとConsumer Secretを入手する
  3. 入手したConsumer KeyとConsumer Secretを、.credentials/zaim_secret.jsonに以下のように記入する gist.github.com
  4. get_zaim_auth_key.pyを実行すると、認証用URLが表示される。ブラウザでアクセスする。
  5. ログイン後、get_zaim_auth_key.py内のcallback_urlで設定したURLへリダイレクトされるが、リダイレクト先をちゃんと作ってないとアクセスに失敗する。 失敗しても慌てず、ブラウザのURLを見て、oauth_tokenとoauth_verifierをメモする。
  6. .credentials/zaim_secret.jsonを更新する gist.github.com
  7. db_build.shを実行し、SQLiteファイル(zaim.dbという名前で作成する)を作成する。このスクリプトは指定日(YYYY-MM-DDで指定)から今日までの全部のデータを取得するので、 自分が取得したい日を引数で指定する。

Google Spreadsheetの認証~Zaimからデータ取得~Google Spreadsheetへのアップロードまで

  1. これとかこのあたりを読んで、 sheet IDとか、client_secret.jsonを入手しておく。入手したら、gspread.pyのSPREADSHEET_IDとCLIENT_SECRET_FILEを変更する。
  2. ./zaim.py --spreadsheet --noauth_local_webserverを実行すると、Zaimからデータ入手したあと、SQLiteを更新する。
  3. --spreadsheetオプションを付けているので、SQLite更新後、Google Spreadsheetにアップロードしようとするが、初回はOAuthのトークンがないので、 トークン取得処理が走る。ここのサンプルコード実行時みたいに、認証URLが出るので、指示に従う。
  4. 認証がうまくいくと、"YYYY-MM"という名前のシートができていて、以下が入力されているはず。
    • それぞれが支払った金額
    • それぞれが分担する金額
    • 清算金額
    • Zaimで入力したデータ

Redashを用いた可視化

こんな感じのものが日々更新されていく。以下の画像は雰囲気だけの例。

f:id:nbisco:20181209091906p:plain
redashでの表示例

  1. Redashコンテナを起動する。自力で入れてもよいが、依存関係解決がけっこう大変だと思うので、コンテナがおすすめ。
  2. データソースにzaim.dbを指定する。
  3. 自分の好きなようにSQLで集計する。

日々の動作

kakeibo.shを実行する。cronとかに登録しておくと楽でよい。 入力漏れとかでシートを作り直すときは、ブラウザでシートを消してから実行する必要がある(これもいまいちだけどたまになので残っている)。

これを作って変わったこと

  • プラス
    • 自分たちのやりくりの実力がわかるようになった
    • いくら使うかだいたいわかるので、先々の計画が立てやすくなった
    • 何を減らすべきかを雰囲気でなく数字で考えられるようになった
  • マイナス
    • "あっ、こんなになんで使っちゃったんだろう(悲しみ)"みたいな気持ちになってしまうことがある。強い心が必要。

おわりに

支出が追いかけられるようになり、自分たちが雰囲気に流されることは減ったが、 それでも使うときは使っちゃうし、記録できてもダメなときはダメという感じである。 ただ、先々の計画が立てやすくなったのは本当によかった。

*1:最近は気が向いたときになってしまっている・・・

*2:自分の書いた記事に技術ポエムじゃないものが果たしてあっただろうか

*3:例えばマネーフォワードとか