Amazon Product Advertising APIの結果をJSONで受け取るスクリプト
(2009/08/11更新)
AmazonがAPIの認証方法を変えたので、このサイトで使ってるスクリプトも変更しなければいけなくなった。 今までは、Yahoo! Pipesを使って、AmazonのAPIの結果を XMLからJSONに変換していたが、それができなくなるのでGoogle App Engine で動くスクリプトを書いた。
参考にしたのは以下のサイト(ありがとうございます)。
- Amazon Product Advertising APIの署名認証をPythonでやってみる
- pyAAWS for Product Advertising API
- Amazon アソシエイト Web サービス改め Product Advertising API の電子署名について調べてみました
- AmazonのProduct Advertising API認証プロキシ(REST版・GAE用)ソース
XMLからJSONへの変換は次のライブラリ(XSLT)を使った(感謝)。
以下がサンプルと手順。
app.yaml
前の(テキスト)エントリーで書いた app.yamlを修正。次の箇所を変更し、
- url: /(.*\.(xml|xsl|xslt))
static_files: assets/xml/\1
upload: assets/xml/(.*\.(xml|xsl|xslt))
以下を足した。
- url: /onca/json
script: aws_pa.py
xml2json-xslt
xml2json.xsltは、siblings with the same name are not collected into an array if other elements exist at the same level (のコメント11)に添付されているものを使った。 ダウンロードページにあるやつでは、AmazonのXMLを上手く変換できなかったため。
それを上の設定に合わせて asset/xml ディレクトリに入れた。
aws_pa.py
Pythonのコードは以下の通り。
import cgi, urllib, urllib2, hmac, hashlib, base64, re
from datetime import datetime
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class AWSProductAdvertising(webapp.RequestHandler):
def __init__(self):
self.secret_key = "INPUT_YOUR_SECRET_KEY_HERE"
self.aws_pa_domain = "xml-jp.amznxslt.com"
self.aws_pa_path = "/onca/xml"
self.params = {
"Service": "AWSECommerceService",
"AssociateTag": "INPUT_YOUR_ASSOCIATE_TAG_HERE",
"AWSAccessKeyId": "INPUT_YOUR_AWS_ACCESS_KEY_HERE",
"Version": "2009-03-31",
"Timestamp": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
"Style": "http://YOUR_APP_NAME.appspot.com/xml2json.xslt",
"ContentType": "text/javascript"
}
def send_request(self):
# create query string
query_strings = []
for key, value in sorted(self.params.items()):
query_strings.append(key + "=" + urllib.quote(value.encode('utf-8'), safe="~"))
query_string = "&".join(query_strings)
# create signature
message = "\n".join( ['GET', self.aws_pa_domain, self.aws_pa_path, query_string] )
digest = hmac.new(self.secret_key, message, hashlib.sha256).digest()
signature = urllib.quote( base64.b64encode(digest) )
aws_pa_url = "http://%(domain)s%(path)s?%(query)s&Signature=%(signature)s" % {
"domain": self.aws_pa_domain,
"path": self.aws_pa_path,
"query": query_string,
"signature": signature
}
return urllib2.urlopen(aws_pa_url).read().decode('utf-8')
def get(self):
for argument in self.request.arguments():
if not re.search("^_", argument):
self.params[argument] = self.request.get(argument)
result_json = self.send_request()
callback = self.request.get('_callback')
if callback:
result_json = callback + "(" + result_json + ")"
self.response.headers['Content-Type'] = 'text/javascript'
self.response.out.write(result_json)
application = webapp.WSGIApplication( [('/onca/json', AWSProductAdvertising)], debug=True )
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
使い方
下のようなURLをリクエストすると、結果がJSONで返ってくる。
http://YOUR_APP_NAME.appspot.com/onca/json?Operation=ItemLookup&ItemId=0679722769&ResponseGroup=ItemAttributes
また、”_callback” というパラメータを使って、コールバック関数を指定できる。
http://YOUR_APP_NAME.appspot.com/onca/json?Operation=ItemLookup&ItemId=0679722769&ResponseGroup=ItemAttributes&_callback=cbfunc
上のコードはご自由にお使いいただて結構です(連絡も不要)。ただし、このコード、およびその使用によって起こった いかなる結果についても、私は責任を負いません。
(こういうのは堅苦しくて好きじゃないんだけど、一応。)
追記(2009/06/29): 日本語で検索できなかったのを修正した。
query_strings.append(key + "=" + urllib.quote(value))
の部分を以下のように変更
query_strings.append(key + "=" + urllib.quote(value.encode('utf-8')))
追記(2009/08/11): いろいろ間違ってたので修正
- SignatureがSigunatureになってたのを修正
- XSLTを使うには、リクエストをxml-jp.amznxslt.comに送る必要がある(日本以外は XSLT Service URLs を参照)
- パラメータにContentTypeを追加
- ”/” をエンコードするために、urllib.quote()にsafe=”~”を追加(“~”はエンコードしない)