STONEDSOUL

I wish I could give you meaningful additions

Amazon Product Advertising APIの結果をJSONで受け取るスクリプト

(2009/08/11更新)

AmazonがAPIの認証方法を変えたので、このサイトで使ってるスクリプトも変更しなければいけなくなった。 今までは、Yahoo! Pipesを使って、AmazonのAPIの結果を XMLからJSONに変換していたが、それができなくなるのでGoogle App Engine で動くスクリプトを書いた。

参考にしたのは以下のサイト(ありがとうございます)。

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=”~”を追加(“~”はエンコードしない)
Page 1 of 1

powered by Tumblr