Amazon Product Advertising API へのリクエストURIのフォーマットが変更されました。
リクエストURIに署名の付加が必須となり、リクエスト側が署名を生成しなくてはいけません。
ex. http://xml-jp.amznxslt.com/onca/xml?…&Signature=*****
詳細はオフィシャルサイトに載っていますが、要は下記の2つの文字列を HMAC SHA256 という方式で符号化したものが署名です。
・”URIのクエリ(タイムスタンプを含む)”
・”アマゾンから発行される秘密キー”
ところが、これまでリクエストURI生成に使っていたホスティングサーバのPythonはバージョンが古く(早くバージョンアップしてほしい…)、 HMAC SHA256 符号化ができません。
Python 2.4 以前は標準で SHA256 を算出するモジュールが入っていないためです。
※Python 2.5 以降であれば hashlib モジュールが使えます。
仕方がないので、署名付きリクエストURIを生成するスクリプトはPerlで書き、それをPythonから実行し、URIを読み込むことにしました。
以下、PerlのURI生成スクリプト。
AmazonSignedRequestGenerator.pl:
#!/usr/bin/perl
use strict;
use warnings;
use URI::Escape;
use Digest::SHA qw(hmac_sha256_base64);
#ISBNを受け取り、Amazon APIのリクエストURIを返す関数
sub GetSignedURIByISBN{
# Amazon Access Key ID
my $accessKeyID = "Your AWS Access Key ID";
# Amazonから割り振られる秘密キー
my $secretKey = "Your Secret Key";
# リクエスト先のホスト名
my $host = "xml-jp.amznxslt.com";
my $path = "/onca/xml";
# リクエストキーとパラメータを関連付けた連想配列を用意する
my %reqParam = (
"Service" => "AWSECommerceService",
"AWSAccessKeyId" => $accessKeyID,
"Version" => "2007-10-29",
"Operation" => "ItemLookup",
"IdType" => "ISBN",
"SearchIndex" => "Books",
"ItemId" => $_[0], # 引数で受け取ったISBNが入る
"ResponseGroup" => "Medium",
"ContentType" => "text/xml",
"Timestamp" => &GetTimeStamp()
);
# リクエストキーとパラメータを結合したクエリを作成
my @queryList = ();
foreach my $reqKey(sort(keys%reqParam)){ #アルファベット順にソート
push(@queryList, URI::Escape::uri_escape($reqKey, "^A-Za-z0-9\-_.~")."=".
URI::Escape::uri_escape($reqParam{$reqKey}, "^A-Za-z0-9\-_.~"));
}
my $query = join("&", @queryList);
# 署名を作成
my $signature = hmac_sha256_base64("GET\n$host\n$path\n$query", $secretKey);
$signature .= "=" while length($signature) % 4; # 署名の長さが4の倍数になるまで"="を付加
$signature = URI::Escape::uri_escape($signature, "^A-Za-z0-9\-_.~");
# リクエストURIを返す
return "http://$host$path?$query&Signature=$signature";
}
# 呼ばれた時刻のタイムスタンプを返す関数
sub GetTimeStamp {
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = gmtime();
return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
$year+1900, $mon+1, $mday, $hour, $min, $sec);
}
# コマンド引数からISBNを受け取り、リクエストURIを表示
print &GetSignedURIByISBN($ARGV[0]);
PerlのURI生成スクリプト実行例。
引数にISBNを指定すると、その書籍情報XMLのリクエストURIを出力する。
$ perl AmazonSignedRequestGenerator.pl 4091400019 http://xml-jp.amznxslt.com/onca/xml?AWSAccessKeyId="Your AWS Access Key ID"&ContentType=text%2Fxml&IdType=ISBN&ItemId=4091400019&Operation=ItemLookup&ResponseGroup=Medium&SearchIndex=Books&Service=AWSECommerceService&Timestamp=2009-10-02T04%3A34%3A01Z&Version=2007-10-29&Signature=V3SNWy7FwOUQJ%2F9TiNJLK55UMdNEWuw5qmqd%2FRsY6Y4%3D
Perlスクリプトを実行し、取得したURIで書籍情報XMLを取得するPythonスクリプト。
RequestTest.py:
#/usr/bin/python
# -*- coding: utf-8 -*-
import commands, urllib
isbn = '4091400019'
#PerlのURI生成スクリプトを実行して標準入力からURIを取得
requestURI = commands.getoutput('perl ./AmazonSignedRequestGenerator.pl %s' % (isbn))
#書籍情報XMLを取得
bookDataXML = urllib.urlopen(requestURI).read()
#取得したXMLを出力
print bookDataXML
こんな感じで、PythonからPerlを呼び出して書籍情報を取得できます。
RequestTest.pyの8行目でAmazonSignedRequestGenerator.plを呼び出しているところがポイントです。
※これらのソースはサンプルなので、使用する場合は適宜エラー処理を行ってください。
Amazonオフィシャルサイト
Amazon Product Advertising API
Amazon アソシエイト(アフィリエイト) – ヘルプ
参考サイト
[を] Perl による自分用 Amazon Product Advertising API proxy「PAPAXY」

python 2.4でも使える感じの記述を見つけましたが、これは使えないのでしょうか?
http://trac.maruz.net/changeset/118/ATAmazon
コメントありがとうございます。
インストールできる環境であれば、Perlなど使わずにPythonだけで済ませたほうが楽ですね。
hashlib単体でインストールすることも出来るようです。
http://code.krypto.org/python/hashlib/