Amazon API -Perlで署名付URI生成 PythonでXMLを取得-

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」

2 Comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*