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

PythonからOAuthを使ってZaimのAPIを叩きます。 Slackから決まった物をZaimに登録できれば、家計簿の管理がかなり簡略化できます。 まずは、[ここ](https://dev.zaim.net)からZaimの開発者APIをたたくための登録をします。 URLを登録する場所がありますが、なんでもOKなのでhttp://example.comなどを入力しておきます。 その時に発行されるコンシューマIDや認証URLなどを一通り控えておきます。 ### 環境 * Python 2.7.9 ### 必要なモジュールのインストール まずはPythonでOAuth認証するためのモジュールをインストールします。 Pythonでの実装は[ここ](https://remotestance.com/blog/1037/)を参考にしました。 ```bash $ 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を取得します。 ```python # coding: utf-8 import urllib import oauth2 as oauth request_token_url = 'https://api.zaim.net/v2/auth/request' access_token_url = 'https://api.zaim.net/v2/auth/access' authenticate_url = 'https://auth.zaim.net/users/auth' 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も控えておきましょう。 ```python # coding: utf-8 import urllib import oauth2 as oauth import urlparse request_token_url = 'https://api.zaim.net/v2/auth/request' access_token_url = 'https://api.zaim.net/v2/auth/access' authenticate_url = 'https://auth.zaim.net/users/auth' 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で登録します。 ```python # coding: utf-8 from urllib import urlencode import oauth2 as oauth import urlparse request_token_url = 'https://api.zaim.net/v2/auth/request' access_token_url = 'https://api.zaim.net/v2/auth/access' authenticate_url = 'https://auth.zaim.net/users/auth' 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のリファレンスを見ながら投稿できます。 ## 支出を登録するサンプル 支出を登録するコードのサンプルです。 ```python # coding: utf-8 import sys from urllib import urlencode import oauth2 as oauth import urlparse request_token_url = 'https://api.zaim.net/v2/auth/request' access_token_url = 'https://api.zaim.net/v2/auth/access' authenticate_url = 'https://auth.zaim.net/users/auth' 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'))

    返信削除