フォト蔵APIのPython wrapperを作る Vol.2 multipart/form-data
前回からの続きです。
フォト蔵APIのPython wrapperを作る Vol.1 Basic認証 - hachi's blog
multipart/form-data
さあ、認証も通ったのでいよいよ写真のアップしてみましょう。 しかし、写真をアップロードするためには、multipart/form-dataを使う必要があります。 multipart/form-dataとは、テキストデータと画像などのバイナリデータをバウンダリで区切って まとめてサーバに送る方法です。 詳しくは RFC 2388 を読んでください。
残念ながら、Pythonの標準ライブラリだけではこのmultipart/form-dataでデータをPOSTすることができません。 PyPIにはMultipartPostHandlerっていうライブラリもあるのですが、 今回はこれは使わずに自分で実装していきます。
例によって、うだうだ説明するよりソース読んだほうが分かりやすいでしょ。
#!/usr/bin/env python import httplib import mimetypes boundary = '-----photozou.py-----' disposition = 'Content-Disposition: form-data; name="%s"' #アップロードする写真のデータ values = open(file_name, 'rb').read() #写真の情報 data = {} data['album_id'] = album_id data['photo_title'] = photo_title data['description'] = description data['tag'] = tag data['comment'] = comment data['data_type'] = data_type data['year'] = year data['month'] = month data['day'] = day #送信するbodyを作る lines = [] lines.append('--' + boundary) lines.append(disposition % 'photo' + '; filename="%s"' % file_name) lines.append('Content-Type: %s' % mimetypes.guess_type(file_name)[0]) lines.append('') lines.append(values) for k, v in data.iteritems(): lines.append('--' + boundary) lines.append(disposition % k) lines.append('') lines.append(v) lines.append('--' + boundary + '--') lines.append('') data_str = '\r\n'.join(lines) #ヘッダを作る header = {'Authorization' : 'Basic %s' % auth_info} header['Content-Type'] = 'multipart/form-data; boundary=%s' % boundary conn = httplib.HTTPConnection('api.photozou.jp') conn.request('POST', '/rest/photo_add/', data_str, header) res = conn.getresponse() print res.status, res.reason print res.read()
辞書に格納したデータをバウンダリで区切りながらbodyの文字列を作っていきます。 画像ファイルの場合は、ファイル名を書いたり、mimetypeを指定したりしなきゃダメみたいです。 大事なポイントとしては、バウンダリをbodyに追加するときは先頭に'--'を付加するって事。 そして最後のバウンダリは先頭と最後に'--'を付加する必要ありです。 それと改行コードがCRLFって事。
そんなこんなで
写真をアップロードするという最大の山場を越えましたので、 後はぼちぼちと他の機能をラップしていくだけです。 全APIをラップできたら、それ使ったアプリもつくりたいですね。
参考ページ
urllib2のみでmultipart/form-dataを送る - YAMAGUCHI::weblog
Http client to POST using multipart/form-data « Python recipes « ActiveState Code
フォト蔵APIのPython wrapperを作る Vol.1 Basic認証
はじめに
整理してない写真データが増えてきたので、とりあえずバックアップがてらフォト蔵に上げたいとずっと思っていたのですが、 なんたって今まで撮りためた数GBある写真をいまさら手動で上げれるほど暇じゃありません。 幸いにも、フォト蔵にはAPIが公開されているので、 PythonからAPI叩いて自動でアップロードできるようにしようっていうのが今回の目的。 その中で技術的なポイントを幾つかまとめていければと思っています。
環境について
開発環境はこんな感じ。 標準ライブラリだけを使って実装しようと思っているので、 基本的にpython2.7さえあれば、 OSはwindowsでもmacでもlinuxでも動くはずです。
作ったものはBitbucketにあげておきます。
Basic認証
フォト蔵APIはユーザ認証にBasic認証を採用しています。 Basic認証は名前の通り基本的な認証方法ですが、 ネットワークが盗聴されていたら一発でパスワードがバレてしまうというちょっと危ない認証方法でもあります。 しかし、実装が簡単なので未だにいろんなところで使われていたりします。
認証が通らなければ話が進まないので、まずはこのBasic認証部分を実装していきます。 フォト蔵APIにはnopという認証テスト用のAPIがあります。これを使って試していきます。
実際に動くものがあったほうがわかりやすいと思うので、先にコードを載せます。
#!/usr/bin/env python import httplib import base64 auth_info = base64.b64encode('%s:%s' % ('username', 'password')) header = {'Authorization' : 'Basic %s' % auth_info} conn = httplib.HTTPConnection('api.photozou.jp') conn.request('GET', '/rest/nop/', '', header) res = conn.getresponse() print res.status, res.reason print res.read()
実行結果
200 OK <?xml version="1.0" encoding="UTF-8" ?> <rsp stat="ok"> <info> <user_id>1021877</user_id> </info> </rsp>
認証に成功するとこんな感じのXMLが返ってきます。
認証失敗の場合はこんな感じ
401 Unauthorized <rsp stat="fail"> <err code="ERROR_UNKNOWN" msg="Log in failed." /> <err code="AUTH_FAILURE" msg="Authorization Required" /> </rsp>
つまり、 Basic認証ってユーザ名とパスワードを:(コロン)で繋いで、 base64でエンコードした文字列を こんな感じでhttpヘッダーに追加するだけでいいんですね。
Authorization: Basic XXXXXXXXXXXXXXXXXXX
このbase64の文字列がバレたら、パスワードもバレるってこと。 このあたりがあまりよろしくないと言われている所以です。
何はともあれ
認証に成功したので、nopのラッパーも完成です。 簡単ですね。たった5行でhttpでアクセスしてBasic認証までできるんだから。 pythonって素晴らしい。
次は実際に写真をアップするphoto_addのラッパーを作っていきます。
フォト蔵APIのPython wrapperを作る Vol.2 multipart/form-data - hachi's blog
またブログを始めます
主に技術的なアウトプットの場として使っていこうと思っています。 twitterの140文字では伝えきれない、ある程度まとまった情報を残していこう。