[Python] ZaimのAPIをPythonから使う (OAuth2)

PythonからOAuthを使ってZaimのAPIを叩きます。
Slackから決まった物をZaimに登録できれば、家計簿の管理がかなり簡略化できます。
まずは、ここからZaimの開発者APIをたたくための登録をします。
URLを登録する場所がありますが、なんでもOKなのでhttp://example.comなどを入力しておきます。
その時に発行されるコンシューマIDや認証URLなどを一通り控えておきます。

環境

  • Python 2.7.9

必要なモジュールのインストール

まずはPythonでOAuth認証するためのモジュールをインストールします。 Pythonでの実装はここを参考にしました。

1
2
$ sudo pip install oauth2
$ sudo pip install urllib

APIを実行するまでの流れ

APIを実行するには下記の手順を踏む必要があります。
(1度行えば、次回からは不要になります。)

  1. OAuth Token, OAuth Token Secretを取得する
  2. 上記を使って、ブラウザで認証を行い、OAuth Verifierを取得する
  3. Access Token, Access Token Secretを取得する
  4. 1から3までの情報を使ってAPIを使用する

認証用のRequest, Tokenを取得する

まずは、OAuth認証するためには、一回ブラウザで認証をする必要があります。
OAuth Token, OAuth Token Secretを取得します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# coding: utf-8
 
import urllib
import oauth2 as oauth
 
callback_url = 'https://www.zaim.net/'
consumer_key = 'consumerkeyxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
consumer_secret = 'consumenrsecretxxxxxxxxxxxxxxxxxxxxxxxxx'
 
def get_request_token():
    consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
    client = oauth.Client(consumer)
 
    # get the request_token
    resp, content = client.request('%s?&oauth_callback=%s' % (request_token_url, callback_url))
    request_token = dict(parse_qsl(content))
    print 'OAuth Token Secret: %s' % request_token['oauth_token_secret']
    print 'OAuth Token : %s' % request_token['oauth_token']
    return request_token['oauth_token']
 
def parse_qsl(url):
    param = {}
    for i in url.split('&'):
        _p = i.split('=')
        param.update({_p[0]: _p[1]})
    return param
 
def get_access_token(oauth_token, oauth_verifier):
    customer = oauth.Consumer(key=consumer_key, secret=consumenr_secret)
    token = oauth.Token(oauth_token, oauth_verifier)
 
    client = oauth.Client(consumer, token)
    resp, content = client.request(access_token_url, "POST", body="oauth_verifier={0}".format(oauth_verifier))
    return content
 
# main
## request tokenを取得
request_token = get_request_token()
 
## request_tokenを認証URLにつけて認証URLを生成する
authorize_url = '%s?oauth_token=%s' % (authenticate_url, request_token)
print 'Authorize url: %s' % authorize_url

ブラウザを使ってOAuth Verifierを取得する

上記で作成したURLを使ってブラウザでアクセスします。
認証を行ったら、そのページ内の"oauth_verifier"を控えておきます。
(HTMLのソースを表示でソースないに表示されます)
これが後々の通信に必要になります。

Access Token, Access Token Secretの取得

下記のコードで取得します。
これで取得したAccess Token, Access Token Secretも控えておきましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# coding: utf-8
 
import urllib
import oauth2 as oauth
import urlparse
 
callback_url = 'https://www.zaim.net/'
consumer_key = 'consumer key'
consumer_secret = 'consumer secret'
request_token = 'reequest token'
request_token_secret = 'request token secret'
oauth_verifier = 'oauth verifier'
 
def main():
    consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
    token = oauth.Token(request_token, request_token_secret)
    token.set_verifier(oauth_verifier)
    client = oauth.Client(consumer, token)
    resp, content = client.request(access_token_url, 'POST')
    access_token = dict(urlparse.parse_qsl(content))
    print 'Access Token: %s' % access_token['oauth_token']
    print 'Access Token Secret: %s' % access_token['oauth_token_secret']
 
if __name__ == '__main__':
    main()

ここまでで、APIにアクセスするための情報が全て集まりました。

通信サンプル

ここまでの情報を使って通信するサンプルになります。
ユーザー情報を引っ張ってきます。
結果はcontentにJSON形式で入ります。
リクエストパラメーターがある場合はparamsにkey:valueで登録します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# coding: utf-8
 
from urllib import urlencode
import oauth2 as oauth
import urlparse
 
callback_url = 'https://www.zaim.net/'
consumer_key = 'consumer key'
consumer_secret = 'consumer secret'
request_token = 'request token'
request_token_secret = 'request token secret'
oauth_verifier = 'oauth verifier'
access_token = 'access token'
access_token_secret = 'access token secret'
base_hostname = 'https://api.zaim.net'
 
def main():
    url = base_hostname + '/v2/home/user/verify'
    token = oauth.Token(key=access_token, secret=access_token_secret)
    consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
    params = {}
    #
    # paramsがある場合は params = {'key':'valye'} で登録する
    #
    client = oauth.Client(consumer, token)
    resp, content = client.request(url, method='GET', body=urlencode(params))
    print resp
    print content
 
if __name__ == '__main__':
    main()

あとはAPIのリファレンスを見ながら投稿できます。

支出を登録するサンプル

支出を登録するコードのサンプルです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# coding: utf-8
 
import sys
from urllib import urlencode
import oauth2 as oauth
import urlparse
 
callback_url = 'https://www.zaim.net/'
consumer_key = 'consumer key'
consumer_secret = 'consumer secret'
request_token = 'request token'
request_token_secret = 'request token secret'
oauth_verifier = 'oauth verifier'
access_token = 'access token'
access_token_secret = 'access token token secret'
base_hostname = 'https://api.zaim.net'
 
#
# ZaimのAPIでアクセスする
#
def access_zaim_api(api, method, params):
    url = base_hostname + api
    token = oauth.Token(key=access_token, secret=access_token_secret)
    consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
    client = oauth.Client(consumer, token)
    resp, content = client.request(url, method=method, body=urlencode(params))
    # print resp
    # print content
    return resp
 
def input_payment_data(category_id, genre_id, amount, date, from_account_id, comment, name, place):
    params = {
            'mapping' : 1,
            'category_id' : category_id,
            'genre_id' : genre_id,
            'amount' : amount,
            'date' : date,
            'from_account_id' : from_account_id,
            'comment' : comment,
            'name' : name,
            'place' : place
            }
 
    return access_zaim_api('/v2/home/money/payment', 'POST', params)
 
if __name__ == '__main__':
    # 保育料の設定
    input_payment_data(109, 11111111, 1111, '2017-12-22', 1111111, '保育料', '', '')

amountに金額を設定します。
genre_idなどは、取得するAPIがあるので、そちらで取得してどのIDで登録するか事前に調べておきます。
取得したJSONの文字列はUnicodeでエンコードされているので、jqコマンドを使って読めるようにして調べると良いです。

1 件のコメント :

  1. resp, content = client.request(url, method='GET', body=urlencode(params))でエンコードのエラーがでたので、変えました。TypeError: Unicode-objects must be encoded before hashing

    resp, content = client.request(url, method='GET', body=urlencode(params).encode('UTF-8'))

    返信削除