Amazon AWS 検索プログラム

Amazon は EC ソリューションのための Amazon AWS (Amazon Web Service) を公開している。アプリケーションプログラムから,AWS の API (Application Programming Interface) を用いて,Amazon で販売されている商品の検索を行い,結果を取得し,サイトの目的に応じた加工を行うことが出来る。

Amazon AWS API を用いて Amazon アフィリエイトリンクを作成するツールはたくさんある。私もちょっと勉強のために Perl 言語で,Amazon 検索コンソールプログラムを書いてみた。

Amazon AWS はたしか SOAP Web Service インタフェースではじまったかと記憶するが,いまでは SOAP のほか RESTful インタフェースでも要求を受け付けるようになっている。ここでは REST リクエストを発行することにする。

Product Advertising API 開発者ガイド (API Version 2010-09-01) に Amazon AWS 開発者向けの文書が掲載されている。ここにある「REST リクエストの構造」に合致するように検索要求を組立てて,Perl LWP::UserAgent (Library of World Wide Web for Perl User Agent) モジュールでアマゾンにアクセスする。

Amazon AWS リクエストの組立てにおいて厄介なのは,署名認証リクエストの生成だろうと思う。Amazon AWS サービスを受けるためには,Amazon アソシエイト・プログラムに参加して,アカウント以外にも,Access Key ID,Secret Access Key を取得しておかなければならない。そして,これらを含む情報に,タイムスタンプと,RFC2104 準拠 HMAC-SHA256 ハッシュアルゴリズム計算で得られた署名を付加することで,リクエストを生成しなければならない。Product Advertising API 開発者ガイド (API Version 2010-09-01) にその詳細な手順が記述されている。

この署名認証リクエスト生成を簡単にやってくれる Perl モジュール URI::Amazon::APA が CPAN にあり,今回はこれを利用させてもらった(ちなみにこのモジュールは日本人プログラマによるコントリビューションである)。URI::Amazon::APA では,query_form メソッドで Amazon AWS のオペレーションを配列形式で設定し,その後 sign メソッドによって署名認証リクエストに仕立て上げることが出来る。

引数に検索キーワードを与えると,これをもとにアマゾンを検索し,結果を XML で標準出力に書くプログラム例 amazonaws.pl を以下に掲げる。Amazon AWS のレスポンスも XML なのだが,すべてベタ書きの改行のないテキストなので,ある程度見やすい姿に整形して出力するために XML::Simple モジュールを通している。Access Key ID ($public_key 変数),Secret Access Key ($private_key 変数), AssociateTag といったアカウントに関わる部分は実在のものとは無関係のでっちあげに変えてあるので,利用者のアカウントに応じて変更しなければならない。

#!/usr/bin/perl -w
# -*- coding: utf-8; mode: cperl; -*-
# amazonaws.pl - Amazon AWS 検索結果を出力する
# 2015(c) isao yasuda.
# $Id: amazonaws.pl 142 2015-03-10 11:31:57Z isao $
#
# usage: amazonaws.pl '検索キーワード'
#
 
use strict;
use utf8;
use URI::Amazon::APA;
use LWP::UserAgent;
use XML::Simple;
 
binmode(STDOUT, ":utf8");
 
# Amazon AWS リクエストを生成する
my $u = URI::Amazon::APA->new('http://ecs.amazonaws.jp/onca/xml');
$u->query_form(
               Service       => 'AWSECommerceService',
               Operation     => 'ItemSearch',
               Keywords      => shift || '本阿弥書店 俳壇',
               SearchIndex   => 'Books',
               ResponseGroup => 'ItemAttributes',
               AssociateTag  => 'MyAffId',
              );
# 署名
my $public_key  = 'AWSACCESSKEYID';
my $private_key = 'mYsecReT/aCceSS+k3y';
$u->sign(
         key    => $public_key,
         secret => $private_key,
        );
 
# LWP で取って来る
my $ua = LWP::UserAgent->new;
my $r  = $ua->get($u);
 
# XML 出力
my $xs = XML::Simple->new;
if ($r->is_success) {
    print XMLout($xs->XMLin($r->content),
                 XMLDecl => '<?xml version="1.0" encoding="UTF-8"?>');
} else {
    print STDERR $r->status_line, $r->as_string;
}

Amazon AWS のオペレーション(検索 SearchIndex 等の処理要求)やレスポンス様式(ResponseGroup)の詳細については,Product Advertising API 開発者ガイド (API Version 2010-09-01) を参照いただきたい。

amazonaws.pl は XML の取得・表示だけのしろものである。実務的なプログラムにするには,XML を解析して必要な情報を抽出し HTML に整形するなどして Web コンテンツに埋め込むようなコードにするべきだろう。書籍のカバー画像も商品リンクを魅力的にするには必要だろう(商品画像リンク情報は ResponseGroup パラメータに Images を追加することで得られる)。

このプログラムを以下のように端末から発行すると,「本阿弥書店 歌壇」でアマゾンを検索し,その結果を 10 件表示する。ファイル res.xml にリダイレクトしている。

$ amazonaws.pl '本阿弥書店 歌壇' > res.xml

Amazon AWS 回答は以下のようなものである。<Item> タグに商品の明細情報が記述されており,これが 10 件分収容されている(以下では,途中,... で省略してある)。末尾にリクエスト条件の内容もある。

<?xml version="1.0" encoding="UTF-8"?>
<opt xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
  <Items MoreSearchResultsUrl="http://www.amazon.co.jp/gp/redirect.html?camp=20
25&creative=5143&location=http%3A%2F%2Fwww.amazon.co.jp%2Fgp%2Fsearch%3
Fkeywords%3D%25E6%259C%25AC%25E9%2598%25BF%25E5%25BC%25A5%25E6%259B%25B8%25E5%2
5BA%2597%2B%25E6%25AD%258C%25E5%25A3%2587%26url%3Dsearch-alias%253Dbooks-single
-index&linkCode=xm2&tag=MyAffId&SubscriptionId=AWSACCESSKEYID" Tota
lPages="12" TotalResults="118">
    <Item ASIN="B00TIVC2X0" DetailPageURL="http://www.amazon.co.jp/%E6%AD%8C%E5
%A3%87-2015%E5%B9%B4-05-%E6%9C%88%E5%8F%B7-%E9%9B%91%E8%AA%8C/dp/B00TIVC2X0%3FS
ubscriptionId%3DAWSACCESSKEYID%26tag%3DMyAffId%26linkCode%3Dxm2%26camp%3D2025%2
6creative%3D165953%26creativeASIN%3DB00TIVC2X0">
      <ItemAttributes Binding="雑誌" EAN="4910123570556" Label="本阿弥書店" Manuf
acturer="本阿弥書店" ProductGroup="Book" ProductTypeName="ABIS_BOOK" Publication
Date="2015-04-14" Publisher="本阿弥書店" ReleaseDate="2015-04-14" Studio="本阿弥書
店" Title="歌壇 2015年 05 月号 [雑誌]">
        <EANList EANListElement="4910123570556" />
        <Languages name="Language" Name="日本語" Type="Published" />
        <ListPrice Amount="800" CurrencyCode="JPY" FormattedPrice="¥ 800" />
      </ItemAttributes>
      <ItemLinks>
        <ItemLink Description="Add To Wishlist" URL="http://www.amazon.co.jp/gp
/registry/wishlist/add-item.html%3Fasin.0%3DB00TIVC2X0%26SubscriptionId%3DAWSAC
CESSKEYID%26tag%3DMyAffId%26linkCode%3Dxm2%26camp%3D2025%26creative%3D5143%26cr
eativeASIN%3DB00TIVC2X0" />
        <ItemLink Description="Tell A Friend" URL="http://www.amazon.co.jp/gp/p
dp/taf/B00TIVC2X0%3FSubscriptionId%3DAWSACCESSKEYID%26tag%3DMyAffId%26linkCode%
3Dxm2%26camp%3D2025%26creative%3D5143%26creativeASIN%3DB00TIVC2X0" />
        <ItemLink Description="All Customer Reviews" URL="http://www.amazon.co.
jp/review/product/B00TIVC2X0%3FSubscriptionId%3DAWSACCESSKEYID%26tag%3DMyAffId%
26linkCode%3Dxm2%26camp%3D2025%26creative%3D5143%26creativeASIN%3DB00TIVC2X0" /
>
        <ItemLink Description="All Offers" URL="http://www.amazon.co.jp/gp/offe
r-listing/B00TIVC2X0%3FSubscriptionId%3DAWSACCESSKEYID%26tag%3DMyAffId%26linkCo
de%3Dxm2%26camp%3D2025%26creative%3D5143%26creativeASIN%3DB00TIVC2X0" />
      </ItemLinks>
    </Item>
    <Item ASIN="B00STR3OEU" DetailPageURL="http://www.amazon.co.jp/%E6%AD%8C%E5
%A3%87-2015%E5%B9%B4-04-%E6%9C%88%E5%8F%B7-%E9%9B%91%E8%AA%8C/dp/B00STR3OEU%3FS
ubscriptionId%3DAWSACCESSKEYID%26tag%3DMyAffId%26linkCode%3Dxm2%26camp%3D2025%2
6creative%3D165953%26creativeASIN%3DB00STR3OEU">
      <ItemAttributes Binding="雑誌" EAN="4910123570457" Edition="月刊" 
Label="本阿弥書店" Manufacturer="本阿弥書店" ProductGroup="Book" ProductTypeName=
"ABIS_BOOK" PublicationDate="2015-03-14" Publisher="本阿弥書店" ReleaseDate=
"2015-03-14" Studio="本阿弥書店" Title="歌壇 2015年 04 月号 [雑誌]">
        <EANList EANListElement="4910123570457" />
        <Languages name="Language" Name="日本語" Type="Published" />
        <ListPrice Amount="800" CurrencyCode="JPY" FormattedPrice="¥ 800" />
      </ItemAttributes>
      <ItemLinks>
    ...
    </Item>
    ...
    <Request IsValid="True">
    <ItemSearchRequest Keywords="本阿弥書店 歌壇" ResponseGroup="ItemAttributes" 
SearchIndex="Books" />
    </Request>
  </Items>
  <OperationRequest RequestId="856d77d5-d1e1-4663-abec-43ddb776f0d9" 
RequestProcessingTime="0.2997021110000000">
    <Arguments>
      <Argument Name="SearchIndex" Value="Books" />
      <Argument Name="AssociateTag" Value="MyAffId" />
      <Argument Name="Service" Value="AWSECommerceService" />
      <Argument Name="Keywords" Value="本阿弥書店 歌壇" />
      <Argument Name="AWSAccessKeyId" Value="AWSACCESSKEYID" />
      <Argument Name="Signature" Value="s0i1g2n3a4t5u6r7e=" />
      <Argument Name="Version" Value="2010-09-01" />
      <Argument Name="Timestamp" Value="2015-03-10T10:47:15Z" />
      <Argument Name="ResponseGroup" Value="ItemAttributes" />
      <Argument Name="Operation" Value="ItemSearch" />
    </Arguments>
    <HTTPHeaders name="Header" Name="UserAgent" Value="libwww-perl/6.05" />
  </OperationRequest>
</opt>