LoginSignup
1
0

More than 3 years have passed since last update.

Java で Amazon Product Advertising API 5.0 (PA-API v5) をコールする

Last updated at Posted at 2020-09-25

概要

  • Java で Amazon Product Advertising API 5.0 (PA-API v5) をコールする
  • AWS が提供している公式の SDK を使わず API を直接コールする
  • AWS 署名バージョン 4 (AWS Signature Version 4) の処理を Java 標準ライブラリのみで実装する
  • 今回の実行環境: macOS Catalina + Java 15 (AdoptOpenJDK 15) + Jackson Databind 2.11.1 + Gradle 6.6.1

サンプルコード

ファイル一覧

├── build.gradle
└── src
    └── main
        └── java
            ├── AwsSignature4.java
            ├── JsonUtil.java
            ├── MyApp.java
            └── PaApi5Wrapper.java

build.gradle

Gradle の設定ファイル。
JSON 操作ライブラリは Java の標準ライブラリにないため Jackson を使用する。

plugins {
  id 'java'
  id 'application'
}

repositories {
  mavenCentral()
}

dependencies {
  // Jackson を使う
  implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1'
}

application {
  mainClassName = 'MyApp'
}

sourceCompatibility = JavaVersion.VERSION_15

src/main/java/MyApp.java

import java.util.HashMap;
import java.util.Map;

/**
 * PA-API v5 をコールするサンプルクラス。
 */
public class MyApp {

  public static void main(String[] args) throws Exception {
    // PA-API v5 をコールする
    searchItems();
    getItems();
  }

  private static final String ACCESS_KEY = "<YOUR-ACCESS-KEY-HERE>"; // 取得したアクセスキー
  private static final String SECRET_KEY = "<YOUR-SECRET-KEY-HERE>"; // 取得したシークレットキー
  private static final String TRACKING_ID = "<YOUR-PARTNER-TAG-HERE>"; // トラッキングID (例: XXXXX-22)

  // キーワードから商品を検索
  public static void searchItems() throws Exception {

    String keywords = "シェイクスピア";

    // リクエスト情報
    Map<String, Object> req = new HashMap<>() {
      {
        put("ItemCount", 3); // 検索結果の数
        put("PartnerTag", TRACKING_ID); // ストアID or トラッキングID
        put("PartnerType", "Associates"); // パートナータイプ
        put("Keywords", keywords); // 検索キーワード
        put("SearchIndex", "All"); // 検索カテゴリー (All, AmazonVideo, Books, Hobbies, Music などを指定可能)
        put("Resources", new String[]{ // レスポンスに含む値のタイプ
          "ItemInfo.Title",
          "ItemInfo.ByLineInfo",
          "ItemInfo.ProductInfo",
          "Images.Primary.Large",
          "Images.Primary.Medium",
          "Images.Primary.Small"
        });
      }
    };

    // リクエスト情報を JSON 文字列にする
    String reqJson = new JsonUtil().objectToJson(req);
    System.out.println("===== キーワードから商品を検索: リクエスト =====");
    System.out.println(reqJson);

    // PA-API v5 をコールして結果を JSON 文字列で受け取る
    PaApi5Wrapper api = new PaApi5Wrapper(ACCESS_KEY, SECRET_KEY);
    String resJson = api.searchItems(reqJson);
    System.out.println("===== キーワードから商品を検索: レスポンス =====");
    System.out.println(new JsonUtil().prettyPrint(resJson));
  }

  // ASIN から商品情報を取得
  public static void getItems() throws Exception {

    String[] asinList = new String[]{"4391641585", "B010EB1HR4", "B0125SPF90", "B07V52KSGT"};

    // リクエスト情報
    Map<String, Object> req = new HashMap<>() {
      {
        put("PartnerTag", TRACKING_ID); // ストアID or トラッキングID
        put("PartnerType", "Associates"); // パートナータイプ
        put("ItemIds", asinList); // ASINのリスト
        put("Resources", new String[]{ // レスポンスに含む値のタイプ
          "ItemInfo.Title",
          "ItemInfo.ByLineInfo"
        });
      }
    };

    // リクエスト情報を JSON 文字列にする
    String reqJson = new JsonUtil().objectToJson(req);
    System.out.println("===== ASIN から商品情報を取得: リクエスト =====");
    System.out.println(reqJson);

    // PA-API v5 をコールして結果を JSON 文字列で受け取る
    PaApi5Wrapper api = new PaApi5Wrapper(ACCESS_KEY, SECRET_KEY);
    String resJson = api.getItems(reqJson);
    System.out.println("===== ASIN から商品情報を取得: レスポンス =====");
    System.out.println(new JsonUtil().prettyPrint(resJson));
  }
}

src/main/java/PaApi5Wrapper.java

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.Map;

/**
 * PA-API v5 ラッパークラス。
 */
public class PaApi5Wrapper {

  private static final String HOST = "webservices.amazon.co.jp"; // Amazon.co.jp の Web API ホスト
  private static final String REGION = "us-west-2"; // Amazon.co.jp では us-west-2 を指定

  private final String accessKey;
  private final String secretKey;

  /**
   * コンストラクタ。
   * @param accessKey アクセスキー
   * @param secretKey シークレットキー
   */
  public PaApi5Wrapper(String accessKey, String secretKey) {
    this.accessKey = accessKey;
    this.secretKey = secretKey;
  }

  /**
   * キーワードから商品を検索する。
   * @param reqJson リクエスト情報 JSON
   * @return レスポンス情報 JSON
   * @throws InterruptedException
   * @throws IOException
   * @throws NoSuchAlgorithmException
   * @throws InvalidKeyException
   * @throws URISyntaxException
   */
  public String searchItems(String reqJson) throws InterruptedException, IOException, NoSuchAlgorithmException, InvalidKeyException, URISyntaxException {
    String path = "/paapi5/searchitems";
    String target = "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.SearchItems";
    return callApi(reqJson, path, target);
  }

  /**
   * ASIN から商品情報を取得する。
   * @param reqJson リクエスト情報 JSON
   * @return レスポンス情報 JSON
   * @throws InterruptedException
   * @throws IOException
   * @throws NoSuchAlgorithmException
   * @throws InvalidKeyException
   * @throws URISyntaxException
   */
  public String getItems(String reqJson) throws InterruptedException, IOException, NoSuchAlgorithmException, InvalidKeyException, URISyntaxException {
    String path = "/paapi5/getitems";
    String target = "com.amazon.paapi5.v1.ProductAdvertisingAPIv1.GetItems";
    return callApi(reqJson, path, target);
  }

  /**
   * PA-API v5 をコールする。
   * @param reqJson リクエスト情報 JSON
   * @param path API エントリポイントのパス
   * @param target リクエストの送信先サービスおよびデータのオペレーション
   * @return レスポンス情報 JSON
   * @throws URISyntaxException
   * @throws InvalidKeyException
   * @throws NoSuchAlgorithmException
   * @throws IOException
   * @throws InterruptedException
   */
  public String callApi(String reqJson, String path, String target) throws URISyntaxException, InvalidKeyException, NoSuchAlgorithmException, IOException, InterruptedException {

    // Java 11 から正式導入された HTTP Client API を使う

    // HTTP リクエスト情報を構築
    HttpRequest.Builder reqBuilder = HttpRequest.newBuilder()
      .uri(new URI("https://" + HOST + path)) // API コール用の URL
      .POST(HttpRequest.BodyPublishers.ofString(reqJson)) // API コールのパラメータをセット
      .timeout(Duration.ofSeconds(10));

    // 署名情報を付加したヘッダ情報を取得
    AwsSignature4 awsv4Auth = new AwsSignature4(accessKey, secretKey, path, REGION, HOST, target);
    Map<String, String> signedHeaders = awsv4Auth.getHeaders(reqJson);

    // リクエスト情報にヘッダをセット
    signedHeaders.remove("host"); // Host ヘッダは付加しない (jdk.httpclient.allowRestrictedHeaders)
    for (Map.Entry<String, String> entrySet : signedHeaders.entrySet()) {
      reqBuilder.header(entrySet.getKey(), entrySet.getValue());
    }

    // HTTP リクエスト情報を生成
    HttpRequest req = reqBuilder.build();

    // API をコールして結果を取得
    HttpClient client = HttpClient.newBuilder()
      .version(HttpClient.Version.HTTP_1_1)
      .connectTimeout(Duration.ofSeconds(10))
      .build();
    HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());

    // ステータスコードで成功・失敗を判断
    if (res.statusCode() == 200) {
      return res.body();
    } else {
      throw new RuntimeException(res.body());
    }
  }
}

src/main/java/AwsSignature4.java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;

/**
 * AWS 署名バージョン 4 (AWS Signature Version 4)
 */
public class AwsSignature4 {

  private static final String SERVICE = "ProductAdvertisingAPI"; // PA-API
  private static final String HMAC_ALGORITHM = "AWS4-HMAC-SHA256";
  private static final String AWS_4_REQUEST = "aws4_request";

  private final String awsAccessKey;
  private final String awsSecretKey;
  private final String path;
  private final String region;
  private final String host;
  private final String target;

  /**
   * コンストラクタ。
   * @param awsAccessKey アクセスキー
   * @param awsSecretKey シークレットキー
   * @param path API エントリポイントのパス
   * @param region リージョン
   * @param host API エントリポイントのパス
   * @param target リクエストの送信先サービスおよびデータのオペレーション
   */
  public AwsSignature4(
    String awsAccessKey, String awsSecretKey,
    String path, String region,
    String host, String target) {
    this.awsAccessKey = awsAccessKey;
    this.awsSecretKey = awsSecretKey;
    this.path = path;
    this.region = region;
    this.host = host;
    this.target = target;
  }

  /**
   * 認証用のヘッダ情報を返す。
   * @param payload リクエスト情報 JSON
   * @return 認証用のヘッダ情報
   * @throws NoSuchAlgorithmException
   * @throws InvalidKeyException
   */
  public Map<String, String> getHeaders(String payload) throws NoSuchAlgorithmException, InvalidKeyException {
    // ベースになるヘッダ
    TreeMap<String, String> headers = new TreeMap<>();
    headers.put("host", host);
    headers.put("content-type", "application/json; charset=utf-8");
    headers.put("content-encoding", "amz-1.0");
    headers.put("x-amz-target", target);
    // 署名を作成するときに使用されるタイムスタンプ
    final Date date = new Date();
    headers.put("x-amz-date", getXAmzDateString(date));
    // 署名付きヘッダー (signed headers)
    String signedHeaders = createSignedHeaders(headers);
    // 正規リクエスト (canonical request)
    String canonicalRequest = createCanonicalRequest(path, headers, signedHeaders, payload);
    // 署名文字列 (string to sign)
    String stringToSign = createStringToSign(date, region, canonicalRequest);
    // 署名 (signature)
    String signature = calculateSignature(awsSecretKey, date, region, stringToSign);
    // Authorization ヘッダー値
    String authorization = buildAuthorizationString(awsAccessKey, region, signature, signedHeaders, date);
    headers.put("Authorization", authorization);
    return headers;
  }

  // 署名付きヘッダー (signed headers)
  private static String createSignedHeaders(TreeMap<String, String> headers) {
    StringBuilder signedHeaderBuilder = new StringBuilder();
    for (String key : headers.keySet()) {
      signedHeaderBuilder.append(key).append(";");
    }
    return signedHeaderBuilder.substring(0, signedHeaderBuilder.length() - 1);
  }

  // 正規リクエスト (canonical request)
  private static String createCanonicalRequest(String path, TreeMap<String, String> headers, String signedHeaders, String payload) throws NoSuchAlgorithmException {
    StringBuilder canonicalRequest = new StringBuilder();
    canonicalRequest.append("POST").append("\n");
    canonicalRequest.append(path).append("\n").append("\n");
    for (String key : headers.keySet()) {
      canonicalRequest.append(key).append(":").append(headers.get(key)).append("\n");
    }
    canonicalRequest.append("\n");
    canonicalRequest.append(signedHeaders).append("\n");
    canonicalRequest.append(sha256(payload));
    return canonicalRequest.toString();
  }

  // 署名文字列 (string to sign)
  private static String createStringToSign(Date current, String region, String canonicalRequest) throws NoSuchAlgorithmException {
    return HMAC_ALGORITHM + "\n"
      + getXAmzDateString(current) + "\n"
      + getYMDString(current) + "/" + region + "/" + SERVICE + "/" + AWS_4_REQUEST + "\n"
      + sha256(canonicalRequest);
  }

  // 署名 (signature)
  private static String calculateSignature(String awsSecretKey, Date current, String region, String stringToSign) throws InvalidKeyException, NoSuchAlgorithmException {
    final String currentDate = getYMDString(current);
    byte[] signatureKey = getSigningKey(awsSecretKey, currentDate, region);
    byte[] signature = hmacSha256(signatureKey, stringToSign);
    return bytesToHex(signature);
  }

  // 署名キー (signing key)
  private static byte[] getSigningKey(String key, String date, String region) throws InvalidKeyException, NoSuchAlgorithmException {
    // 各ハッシュ関数の結果が次のハッシュ関数の入力になる
    byte[] kSecret = ("AWS4" + key).getBytes(StandardCharsets.UTF_8);
    byte[] kDate = hmacSha256(kSecret, date);
    byte[] kRegion = hmacSha256(kDate, region);
    byte[] kService = hmacSha256(kRegion, SERVICE);
    byte[] kSigning = hmacSha256(kService, AWS_4_REQUEST);
    return kSigning;
  }

  // Authorization ヘッダー値
  private static String buildAuthorizationString(String awsAccessKey, String region, String signature, String signedHeaders, Date current) {
    return HMAC_ALGORITHM + " "
      + "Credential=" + awsAccessKey + "/" + getYMDString(current) + "/" + region + "/" + SERVICE + "/" + AWS_4_REQUEST + ","
      + "SignedHeaders=" + signedHeaders + ","
      + "Signature=" + signature;
  }

  // ハッシュ関数 SHA-256
  private static String sha256(String data) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(data.getBytes(StandardCharsets.UTF_8));
    byte[] digest = messageDigest.digest();
    return String.format("%064x", new java.math.BigInteger(1, digest));
  }

  // HMAC-SHA256 関数
  private static byte[] hmacSha256(byte[] key, String data) throws NoSuchAlgorithmException, InvalidKeyException {
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(new SecretKeySpec(key, "HmacSHA256"));
    return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
  }

  // バイナリ値を 16 進数表現に変換
  private static String bytesToHex(byte[] data) {
    final char[] hexCode = "0123456789ABCDEF".toCharArray();
    StringBuilder r = new StringBuilder(data.length * 2);
    for (byte b : data) {
      r.append(hexCode[(b >> 4) & 0xF]);
      r.append(hexCode[(b & 0xF)]);
    }
    return r.toString().toLowerCase();
  }

  // x-amz-date ヘッダ用日時文字列 (UTC で YYYYMMDD'T'HHMMSS'Z' の ISO 8601 形式)
  private static String getXAmzDateString(Date date) {
    DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); // ISO 8601
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    return dateFormat.format(date);
  }

  // 日付文字列 yyyyMMdd 形式
  private static String getYMDString(Date date) {
    DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    return dateFormat.format(date);
  }
}

src/main/java/JsonUtil.java

// 外部ライブラリの Jackson を使う
import com.fasterxml.jackson.core.json.JsonWriteFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;

/**
 * JSON 操作クラス。
 */
public class JsonUtil {

  /**
   * オブジェクトから JSON 文字列を生成する。
   * @param obj オブジェクト
   * @return JSON 文字列
   * @throws IOException
   */
  public String objectToJson(Map<String, Object> obj) throws IOException {
    StringWriter out = new StringWriter();
    ObjectMapper mapper = new ObjectMapper();
    // ASCII 文字以外は Unicode escape する
    mapper.configure(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(), true);
    mapper.writerWithDefaultPrettyPrinter().writeValue(out, obj);
    return out.toString();
  }

  /**
   * JSON を読みやすい形にする。
   * @param json JSON 文字列
   * @return 読みやすい形になった JSON 文字列
   * @throws IOException
   */
  public String prettyPrint(String json) throws IOException {
    StringWriter out = new StringWriter();
    ObjectMapper mapper = new ObjectMapper();
    mapper.writerWithDefaultPrettyPrinter().writeValue(out, mapper.readValue(json, Map.class));
    return out.toString();
  }
}

サンプルコードの実行結果

実行環境: macOS Catalina + Java 15 (AdoptOpenJDK 15) + Gradle 6.6.1

$ gradle run
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :run
===== キーワードから商品を検索: リクエスト =====
{
  "PartnerType" : "Associates",
  "PartnerTag" : "XXXXX-22",
  "Keywords" : "\u30B7\u30A7\u30A4\u30AF\u30B9\u30D4\u30A2",
  "SearchIndex" : "All",
  "ItemCount" : 3,
  "Resources" : [ "ItemInfo.Title", "ItemInfo.ByLineInfo", "ItemInfo.ProductInfo", "ItemInfo.ProductInfo", "Images.Primary.Large", "Images.Primary.Medium", "Images.Primary.Small" ]
}
===== キーワードから商品を検索: レスポンス =====
{
  "SearchResult" : {
    "Items" : [ {
      "ASIN" : "B06ZZH149Y",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/B06ZZH149Y?tag=XXXXX-22&linkCode=osi&th=1&psc=1",
      "Images" : {
        "Primary" : {
          "Large" : {
            "Height" : 500,
            "URL" : "https://m.media-amazon.com/images/I/41Ms+C0NwNL.jpg",
            "Width" : 311
          },
          "Medium" : {
            "Height" : 160,
            "URL" : "https://m.media-amazon.com/images/I/41Ms+C0NwNL._SL160_.jpg",
            "Width" : 100
          },
          "Small" : {
            "Height" : 75,
            "URL" : "https://m.media-amazon.com/images/I/41Ms+C0NwNL._SL75_.jpg",
            "Width" : 47
          }
        }
      },
      "ItemInfo" : {
        "ByLineInfo" : {
          "Contributors" : [ {
            "Locale" : "ja_JP",
            "Name" : "河合祥一郎",
            "Role" : "著",
            "RoleType" : "author"
          } ],
          "Manufacturer" : {
            "DisplayValue" : "祥伝社",
            "Label" : "Manufacturer",
            "Locale" : "ja_JP"
          }
        },
        "ProductInfo" : {
          "IsAdultProduct" : {
            "DisplayValue" : false,
            "Label" : "IsAdultProduct",
            "Locale" : "en_US"
          },
          "ReleaseDate" : {
            "DisplayValue" : "2017-04-21T00:00:00.000Z",
            "Label" : "ReleaseDate",
            "Locale" : "en_US"
          }
        },
        "Title" : {
          "DisplayValue" : "あらすじで読むシェイクスピア全作品 (祥伝社新書)",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    }, {
      "ASIN" : "B015BY1Q6Q",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/B015BY1Q6Q?tag=XXXXX-22&linkCode=osi&th=1&psc=1",
      "Images" : {
        "Primary" : {
          "Large" : {
            "Height" : 500,
            "URL" : "https://m.media-amazon.com/images/I/516XD+o35gL.jpg",
            "Width" : 375
          },
          "Medium" : {
            "Height" : 160,
            "URL" : "https://m.media-amazon.com/images/I/516XD+o35gL._SL160_.jpg",
            "Width" : 120
          },
          "Small" : {
            "Height" : 75,
            "URL" : "https://m.media-amazon.com/images/I/516XD+o35gL._SL75_.jpg",
            "Width" : 56
          }
        }
      },
      "ItemInfo" : {
        "ByLineInfo" : {
          "Contributors" : [ {
            "Locale" : "ja_JP",
            "Name" : "メル・ギブソン",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "グレン・クローズ",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "アラン・ベイツ",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ポール・スコフィールド",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "フランコ・ゼフィレッリ",
            "Role" : "監督",
            "RoleType" : "director"
          }, {
            "Locale" : "ja_JP",
            "Name" : "クリストファー・デヴォア",
            "Role" : "Writer",
            "RoleType" : "writer"
          } ]
        },
        "ProductInfo" : {
          "IsAdultProduct" : {
            "DisplayValue" : false,
            "Label" : "IsAdultProduct",
            "Locale" : "en_US"
          },
          "ReleaseDate" : {
            "DisplayValue" : "2015-09-16T00:00:00.000Z",
            "Label" : "ReleaseDate",
            "Locale" : "en_US"
          }
        },
        "Title" : {
          "DisplayValue" : "ハムレット(字幕版)",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    }, {
      "ASIN" : "B07WPXRT5W",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/B07WPXRT5W?tag=XXXXX-22&linkCode=osi&th=1&psc=1",
      "Images" : {
        "Primary" : {
          "Large" : {
            "Height" : 375,
            "URL" : "https://m.media-amazon.com/images/I/51CnJBKwu5L.jpg",
            "Width" : 500
          },
          "Medium" : {
            "Height" : 120,
            "URL" : "https://m.media-amazon.com/images/I/51CnJBKwu5L._SL160_.jpg",
            "Width" : 160
          },
          "Small" : {
            "Height" : 56,
            "URL" : "https://m.media-amazon.com/images/I/51CnJBKwu5L._SL75_.jpg",
            "Width" : 75
          }
        }
      },
      "ItemInfo" : {
        "ByLineInfo" : {
          "Contributors" : [ {
            "Locale" : "ja_JP",
            "Name" : "マーク・ベントン",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジョー・ジョイナー",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "アンバー・アガ",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "リチャード・サイニー",
            "Role" : "監督",
            "RoleType" : "director"
          }, {
            "Locale" : "ja_JP",
            "Name" : "イアン・バーバー",
            "Role" : "監督",
            "RoleType" : "director"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ウィル・トロッター",
            "Role" : "プロデュース",
            "RoleType" : "producer"
          } ]
        },
        "ProductInfo" : {
          "IsAdultProduct" : {
            "DisplayValue" : false,
            "Label" : "IsAdultProduct",
            "Locale" : "en_US"
          }
        },
        "Title" : {
          "DisplayValue" : "第1話",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    } ],
    "SearchURL" : "https://www.amazon.co.jp/s?k=%E3%82%B7%E3%82%A7%E3%82%A4%E3%82%AF%E3%82%B9%E3%83%94%E3%82%A2&rh=p_n_availability%3A-1&tag=XXXXX-22&linkCode=osi",
    "TotalResultCount" : 146
  }
}
===== ASIN から商品情報を取得: リクエスト =====
{
  "PartnerType" : "Associates",
  "PartnerTag" : "XXXXX-22",
  "Resources" : [ "ItemInfo.Title", "ItemInfo.ByLineInfo" ],
  "ItemIds" : [ "4391641585", "B010EB1HR4", "B0125SPF90", "B07V52KSGT" ]
}
===== ASIN から商品情報を取得: レスポンス =====
{
  "ItemsResult" : {
    "Items" : [ {
      "ASIN" : "4391641585",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/4391641585?tag=XXXXX-22&linkCode=ogi&th=1&psc=1",
      "ItemInfo" : {
        "ByLineInfo" : {
          "Contributors" : [ {
            "Locale" : "ja_JP",
            "Name" : "サンエックス",
            "Role" : "監修",
            "RoleType" : "consultant_editor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "主婦と生活社",
            "Role" : "編集",
            "RoleType" : "editor"
          } ],
          "Manufacturer" : {
            "DisplayValue" : "主婦と生活社",
            "Label" : "Manufacturer",
            "Locale" : "ja_JP"
          }
        },
        "Title" : {
          "DisplayValue" : "すみっコぐらし検定公式ガイドブック すみっコぐらし大図鑑 (生活シリーズ)",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    }, {
      "ASIN" : "B010EB1HR4",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/B010EB1HR4?tag=XXXXX-22&linkCode=ogi&th=1&psc=1",
      "ItemInfo" : {
        "ByLineInfo" : {
          "Brand" : {
            "DisplayValue" : "Hostess Entertainmen",
            "Label" : "Brand",
            "Locale" : "ja_JP"
          },
          "Contributors" : [ {
            "Locale" : "ja_JP",
            "Name" : "ハロウィン",
            "Role" : "アーティスト",
            "RoleType" : "artist"
          } ],
          "Manufacturer" : {
            "DisplayValue" : "ホステス",
            "Label" : "Manufacturer",
            "Locale" : "ja_JP"
          }
        },
        "Title" : {
          "DisplayValue" : "守護神伝 第二章 <エクスパンデッド・エディション>(リマスター)",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    }, {
      "ASIN" : "B0125SPF90",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/B0125SPF90?tag=XXXXX-22&linkCode=ogi&th=1&psc=1",
      "ItemInfo" : {
        "ByLineInfo" : {
          "Brand" : {
            "DisplayValue" : "ルービーズジャパン(RUBIE'S JAPAN)",
            "Label" : "Brand",
            "Locale" : "ja_JP"
          },
          "Manufacturer" : {
            "DisplayValue" : "ルービーズジャパン(RUBIE'S JAPAN)",
            "Label" : "Manufacturer",
            "Locale" : "ja_JP"
          }
        },
        "Title" : {
          "DisplayValue" : "ハロウィン ロッキング パンプキン ホームデコレーション用小物 H 130cm",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    }, {
      "ASIN" : "B07V52KSGT",
      "DetailPageURL" : "https://www.amazon.co.jp/dp/B07V52KSGT?tag=XXXXX-22&linkCode=ogi&th=1&psc=1",
      "ItemInfo" : {
        "ByLineInfo" : {
          "Contributors" : [ {
            "Locale" : "ja_JP",
            "Name" : "リアン・リース",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジェイミー・リー・カーティス",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ウィル・パットン",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジュディ・グリア",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ヴァージニア・ガードナー",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジェファーソン・ホール",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "アンディ・マティチャック",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ニック・キャッスル",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジェームス・ジュード・コートニー",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ハルク・ビルギナー",
            "Role" : "出演",
            "RoleType" : "actor"
          }, {
            "Locale" : "ja_JP",
            "Name" : "デヴィッド・ゴードン・グリーン",
            "Role" : "監督",
            "RoleType" : "director"
          }, {
            "Locale" : "ja_JP",
            "Name" : "デヴィッド・ゴードン・グリーン",
            "Role" : "Writer",
            "RoleType" : "writer"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ダニー・マクブライド",
            "Role" : "Writer",
            "RoleType" : "writer"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジェフ・フラッドリー",
            "Role" : "Writer",
            "RoleType" : "writer"
          }, {
            "Locale" : "ja_JP",
            "Name" : "マレク・アカッド",
            "Role" : "プロデュース",
            "RoleType" : "producer"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ジェイソン・ブラム",
            "Role" : "プロデュース",
            "RoleType" : "producer"
          }, {
            "Locale" : "ja_JP",
            "Name" : "ビル・ブロック",
            "Role" : "プロデュース",
            "RoleType" : "producer"
          } ]
        },
        "Title" : {
          "DisplayValue" : "ハロウィン (字幕版)",
          "Label" : "Title",
          "Locale" : "ja_JP"
        }
      }
    } ]
  }
}

BUILD SUCCESSFUL in 13s
2 actionable tasks: 2 executed

参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0