わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

PA-API v5で商品検索

 先月から,このAPIのバージョン4.0は3月9日までですよ,早く移行してくださいよというメールが,たびたびやって来ました.古いAPIと思われるものを,これまで,活用していました.

 バージョン5.0 (v5)について,SDKほかを見たところ,Ruby版はありません.JavaJavaScriptの実装を読んだものの,これをRubyに書き換えるのは面倒です.
 そこでJavaScript (Node.js)で動かすこととし,自分用に大幅に書き換えました.ファイル名をpaapi5search.jsとしまして,コードはGistに置いています.
 nodeコマンドで動かしますが,いくつか準備が必要です.ファイルのはじめのほうに書いたように,依存するパッケージが2つありまして,npm installでインストールしておきます.
 次に,このAPIを使うには「Access Key」「Secret Key」「Partner Tag」が必要なのですが,jsファイルに直書きするのは何かと危険ですので,ruby-aaws*1と同じ,~/.amazonrcから読み出すことにしました.ただし移行ガイドにあるとおり「新しい認証情報を取得する」必要もあります.「Partner Tag」は,~/.amazonrcでは「associate=」のあとに指定する文字列となります.
 昨日付の記事で取り上げた書籍のISBNを,入力に与えたときの,実行コマンドと結果は以下のとおりです.

$ node paapi5search.js 9784393376034
<ASIN> 439337603X
<ISBN> 9784393376034
<DetailPageURL> https://www.amazon.co.jp/dp/439337603X?tag=(略)
<SimpleURL> https://www.amazon.co.jp/dp/439337603X
<Title> これからの大学
<Author> 松村圭一郎
<Manufacturer> 春秋社
<Publication Date> 2019-12-20T00:00:01Z
<Buying Price> ¥2,090
松村圭一郎: これからの大学, 春秋社 (2019). [isbn:9784393376034]

 最後は書誌情報です.端末でこの行をトリプルクリックしてコピーし,テキストエディタに貼り付けることを意図しています.
 いくつかコマンドラインオプションをとります.-tオプションで検索語を指定できますが,このオプションがない場合,コマンドライン解析をして残った最初の引数が検索語となります.-mオプションには数値を指定し,項目数の上限を指定します(デフォルトは1),出力のオプションとして,-jをつけると,問い合わせ結果のJSON形式を出力し,-Sをつけると,上記の結果(要約)を出力しません.デバッグオプションは-dです.
 JSONだけの出力は,次のようにします.

$ node paapi5search.js -t 9784393376034 -j -S
{
 "SearchResult": {
  "TotalResultCount": 1,
  "SearchURL": (略),
  "Items": [
   {
    "ASIN": "439337603X",
    "DetailPageURL": (略),
    "ItemInfo": {
     "ByLineInfo": {
      "Brand": {
       "DisplayValue": "春秋社",
       "Label": "Brand",
       "Locale": "ja_JP"
      },
      "Contributors": [
       {
        "Locale": "ja_JP",
        "Name": "松村 圭一郎",
        "Role": "著"
       }
      ],
      "Manufacturer": {
       "DisplayValue": "春秋社",
       "Label": "Manufacturer",
       "Locale": "ja_JP"
      }
     },
     "Classifications": {
      "Binding": {
       "DisplayValue": "単行本",
       "Label": "Binding",
       "Locale": "ja_JP"
      },
      "ProductGroup": {
       "DisplayValue": "Book",
       "Label": "ProductGroup",
       "Locale": "ja_JP"
      }
     },
     "ContentInfo": {
      "Languages": {
       "DisplayValues": [
        {
         "DisplayValue": "日本語",
         "Type": "発行済み"
        }
       ],
       "Label": "Language",
       "Locale": "ja_JP"
      },
      "PagesCount": {
       "DisplayValue": 240,
       "Label": "NumberOfPages",
       "Locale": "en_US"
      },
      "PublicationDate": {
       "DisplayValue": "2019-12-20T00:00:01Z",
       "Label": "PublicationDate",
       "Locale": "en_US"
      }
     },
     "ExternalIds": {
      "EANs": {
       "DisplayValues": [
        "9784393376034"
       ],
       "Label": "EAN",
       "Locale": "en_US"
      },
      "ISBNs": {
       "DisplayValues": [
        "439337603X"
       ],
       "Label": "ISBN",
       "Locale": "en_US"
      }
     },
     "Title": {
      "DisplayValue": "これからの大学",
      "Label": "Title",
      "Locale": "ja_JP"
     }
    },
    "Offers": {
     "Listings": [
      {
       "Id": (略),
       "Price": {
        "Amount": 2090,
        "Currency": "JPY",
        "DisplayAmount": "¥2,090"
       },
       "ViolatesMAP": false
      }
     ]
    }
   }
  ]
 }
}

 上記の結果は,プログラム内では変数siRespに代入されます(それを「JSON.stringify(siResp, null, 1)」により文字列にして,出力しています).
 このときsiResp["SearchResult"]["Items"][0]["ItemInfo"]["Title"]["DisplayValue"]またはsiResp.SearchResult.Items[0].ItemInfo.Title.DisplayValueがタイトル(評価値は"これからの大学")となるのですが,このアクセスを簡潔に記述できるよう,oという名前の関数を自作しました.具体的にはo(siResp, "SearchResult.Items.0.ItemInfo.Title.DisplayValue")と書きます*2.どこかで「切れる」場合には(例えばo(siResp, "SearchResult.Items.0.Title.DisplayValue")については),undefinedを返します.また途中の「0」について(0に限らず数字列の場合には),まずsiResp["SearchResult"]["Items"]["0"]を調べ,この結果がundefinedになるときには,siResp["SearchResult"]["Items"][0]に切り替えて配列のアクセスを行います.


 上記でリンクしたもの以外で,コーディングにおいて何度か参照したページです.

*1:https://rubygems.org/gems/ruby-aawsによると最新版が0.7.0で,10年以上も前とのこと.しかしRuby 2.8.0devで,問題なく検索できるのでした....

*2:実際にはsiResp["SearchResult"]["Items"][0]を変数itemに代入し,printItemSummary内のo(item, 'ItemInfo.Title.DisplayValue')で獲得しています.