アマゾンのAPIを使って得た本の情報をGASのSpreadsheetに保存してみる

amazonのProduct Advertising APIを使って、本のISBNコードから名前と価格を取得し、Spreadsheetに保存してみる。

### リクエストの作成手順
***
1. アカウントを作成して、アクセスキー、シークレットキー、アソシエイトタグを取得
2. パラメータ収集
3. アクセスキー、タイムスタンプを付加
4. パラメータ名でソート
5. パラメータをURLエンコードし、文字列作成
6. 「GET」「ecs.amazonaws.jp」「/onca/xml」の文字列追加
7. 署名を作成
8. 署名をリクエストに追加

### アクセスキー、シークレットキー、アソシエイトタグを取得
***
アクセスキー、シークレットキー、アソシエイトタグを取得。
[アソシエイトタグ作成](https://affiliate.amazon.co.jp/)
[Product Advertising APIヘルプ](https://affiliate.amazon.co.jp/gp/advertising/api/detail/main.html)
[Product Advertising API アカウント作成 ヘルプ](https://affiliate.amazon.co.jp/gp/associates/help/t125?ie=UTF8&pf_rd_i=assoc-api-detail-1-v2&pf_rd_m=AN1VRQENFRJN5&pf_rd_p=&pf_rd_r=&pf_rd_s=assoc-center-1&pf_rd_t=501&ref_=amb_link_62041789_1)

>最近取得方法が変わった。。?
***

### パラメータ収集
以下8つのパラメータを収集。

Service:"AWSECommerceService"
Version:["APIのバージョンはこちらを参照"](http://aws.amazon.com/releasenotes/Product%20Advertising%20API)
AssociateTag:"[自分のアソシエイトタグ(必須)]"
SearchIndex:"Books"
Operation:"ItemLookup"
IdType:"ISBN"
ItemId:"[ISBNコードは10桁もしくは13桁の数値部分のみ]"
ResponseGroup:["ResponseGroupはこちらを参照"](https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?CHAP_ResponseGroupsList.html)

※AssociateTagは"PutYourAssociateTagHere"を入れても通る。

***
### アクセスキー、タイムスタンプを付加
上記8つに以下2つのパラメータを付加

アクセスキーは1で取得したコード
`AWSAccessKeyId:"[アクセスキー]"`

タイムスタンプは国際標準化機構 (ISO) 形式の日付の文字列を使う。

`Timestamp:YYYY-MM-DDTHH:mm:ss.sssZ`

DateオブジェクトのtoISOStringメソッドで取得。
`Timestamp:new Date().toISOString()`
***
### パラメータ名でソート
上記10個のパラメータを取得したら自然順序付け・昇順で並び替える。

※アルファベット順ではないらしい。大文字->小文字の昇順
Array.sort関数をそのまま使う。
***

### パラメータをURLエンコードし、文字列作成

上記で出来たパラメータをencodeURIComponentでエンコードし、key=valueを&で挟み文字列作成。

***

### 「GET」「ecs.amazonaws.jp」「/onca/xml」の文字列追加

上記でできた文字列の先頭に
`GET
ecs.amazonaws.jp
/onca/xml`

の3列を追加。（改行含む）

***
### 署名を作成

署名を作成するには、上記で作成した文字列とシークレットキーを使う。
HMAC-SHA256ハッシュアルゴリズムの計算し、計算結果をbase64エンコード。

* Utilities.computeHmacSha256Signature
* Utilities.base64Encode
* 「シークレットキー」

を使って署名を作成。

`Utilities.base64Encode(Utilities.computeHmacSha256Signature(s, "[自分のシークレットキー]"));`

***
#### fetchする。

ここまでで署名が出来ればあとはURIにその署名を追加しfetch
`[リクエスト文字列] = "[URI]" + parameter.join("&") + "&Signature=" + encodeURIComponent("[署名]");`
`UrlFetchApp.fetch("[リクエスト文字列]")`

リクエストが通ればXMLが戻ってくる。
***
#### XMLを解析しSpreadsheetに保存

戻ってきたXMLをXMLServiceで解析し、Spreadsheetに保存。
`XMLService.parse`

***

ちなみにアマゾンに署名作成ツールが用意されているらしい。。
>署名作成ツールは[これ](http://associates-amazon.s3.amazonaws.com/signed-requests/helper/index.html)

以下コード

```js:amazon.gs
function getAmazonBookInfo(isbn){
  var u = "http://ecs.amazonaws.jp/onca/xml?";
  var o = {
    Service:"AWSECommerceService",
    Version:"2011-08-01",
    AssociateTag:"[自分のアソシエイトタグ]",
    Operation:"ItemLookup",
    SearchIndex:"Books",
    ItemId:isbn,
    Timestamp:new Date().toISOString(),
    AWSAccessKeyId:"[自分のアクセスキーID]",
    IdType:"ISBN",
    ResponseGroup:"ItemAttributes"
  };
  
  var a = Object.keys(o).sort();
  a = a.map(function(key){
    return key +"="+encodeURIComponent(o[key]);
  });
  
  var s = "GET" + "\n" + "ecs.amazonaws.jp" + "\n" + "/onca/xml" + "\n" + a.join("&");
  
  var x = Utilities.base64Encode(Utilities.computeHmacSha256Signature(s, "[自分のシークレットキー]"));
  var z = u + a.join("&") + "&Signature=" + encodeURIComponent(x);
  var r = UrlFetchApp.fetch(z);
  
  return XmlService.parse(r.getContentText());
}
```

あとはXMLServiceクラスでXMLを走査。

```js:getBookInfo.gs
function getBookInfo(isbn){
  var o = {};
  var x = getAmazonBookInfo(isbn);
  var a = x.getDescendants();
  for(var i=0;i<a.length;i++){
    if(a[i].getType() == XmlService.ContentTypes.ELEMENT){
      switch(a[i].asElement().getName()){
        case "Title" :
          o.title = a[i].asElement().getText();
          break;
        case "FormattedPrice" :
          o.price = a[i].asElement().getText();
          break;
      }
    }
  }
  var sheet = SpreadsheetApp.openById("[spreadsheetのid]").getSheetByName("[sheet名]");
  sheet.getRange(sheet.getLastRow()+1,1,1,2).setValues([[o.title,o.price]]);
}
```
>※ScriptDbが廃止されるそうなのでSpreadsheet保存に変更。

返ってくるXMLについての詳細は[ココ](https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/CHAP_response_elements.html)

まとめてみると意外とすっきりしたコードが作れる。

トリガーで定期的に取得すれば価格の日毎チェックとかが簡単にできるかも。