さて、前回の記事で接続できたら、早速Amazon MWS APIを使って商品情報を取得してみましょう!
※前回記事はこちら www.yumeigunshi.com
商品情報を取得するにはアクションにGetMatchingProductForIdを指定します。
このアクションでは主に商品名、重さ、長さ、高さ、幅、カテゴリなどを取得できます。
商品名、カテゴリはもちろん欲しい情報ですね。
重さは転送料の計算に使えます。
長さ、高さ、幅はFBAで大型商品かどうか判断することができます。
他に取得できる項目は公式サイトを参考に。 docs.developer.amazonservices.com
複数ASINを送信し、商品情報を取得するコード
前回同様始めに全て載せます。
分からない方は後で解説しているので、読み進めてくださいね。
Excelシート
VBAコード
Option Explicit Private Sub BTN_実行_Click() Dim xml As Object Dim dic As Object Dim lstRow As Long Dim asinRow As Long Dim resultRow As Long Dim result() As Variant Dim asinList As Collection Dim asin As String Dim shohinObj As Object Dim itemObj As Object Dim wkObj As Object Dim i As Integer, j As Integer Dim param As String Dim wk As Variant '最終行取得 lstRow = Cells(Rows.Count, 1).End(xlUp).Row If lstRow = 1 Then MsgBox ("ASINが入力されていません。") Exit Sub End If '初期処理 Set dic = CreateObject("Scripting.Dictionary") asinRow = 2 '開始行数 'Result配列の宣言 ReDim result(1 To lstRow - 1, 1 To 8) While asinRow <= lstRow Set asinList = New Collection With Sheets("ASIN") ' ASINを取り出す j = 0 Do While j < 5 ' 最終行の場合、処理終了 If asinRow > lstRow Then Exit Do End If ' 情報をセット asin = CStr(.Cells(asinRow, 1).Value) If dic.exists(asin) = False Then '未処理のASINを処理 Set wk = New Collection wk.Add asin, "ASIN" wk.Add asinRow - 1, "ROWS" asinList.Add wk, CStr(asinList.Count + 1) '処理済ASINを格納 dic.Add asin, asinRow j = j + 1 End If '配列初期化 result(asinRow - 1, 1) = asin result(asinRow - 1, 2) = "-" result(asinRow - 1, 3) = "-" result(asinRow - 1, 4) = "-" result(asinRow - 1, 5) = "-" result(asinRow - 1, 6) = "-" result(asinRow - 1, 7) = "-" result(asinRow - 1, 8) = "-" ' 次行へ asinRow = asinRow + 1 Loop End With param = "" ' ASINを1つずつ取り出す j = 1 For Each wk In asinList If j = 1 Then param = "&IdList.ASIN." & j & "=" & wk("ASIN") Else param = param & "&IdList.ASIN." & j & "=" & wk("ASIN") End If j = j + 1 Next ' リクエストを作成 param = MakeParam(param) Set xml = getXMLPost("https://mws.amazonservices.jp/Products/2011-10-01", param) '情報取得 Call GetShohinInfo(xml, result, asinList) '1秒のウェイト Sleep 1000 Wend 'Resultへセット With Sheets("Result") 'クリア resultRow = Cells(Rows.Count, 1).End(xlUp).Row .Range(.Range("A2").Address, .Cells(resultRow, 8).Address) = "" '貼り付け .Range(.Range("A2").Address, .Cells(lstRow, 8).Address) = result End With MsgBox "出力完了" End Sub 'パラメータ作成 Function MakeParam(idList As String) As String Dim param As String Dim paramToSign As String Dim sellerId As String Dim accessKey As String Dim seacretKey As String Dim endPoint As String Dim marketPlaceId As String Dim timeStamp As String Dim apiVersion As String Dim country As String Dim sign As String Dim url As String country = "1" 'パラメータの取得 With Sheets("MWS") sellerId = .Range("B1").Value accessKey = .Range("B2").Value seacretKey = .Range("B3").Value End With endPoint = "mws.amazonservices.jp" marketPlaceId = "A1VC38T7YXB528" timeStamp = Format(CDate(DateAdd("h", -9, Now)), "yyyy-mm-dd") & "T" & Format(CDate(DateAdd("h", -9, Time)), "hh%3AMM%3Ass") & "Z" apiVersion = "2011-10-01" ' リクエストを作成(パラメータはアルファベット順なので順番を変えるとNG) param = "AWSAccessKeyId=" & accessKey _ & "&Action=GetMatchingProductForId" _ & idList _ & "&IdType=ASIN" _ & "&ItemCondition=New" _ & "&MarketplaceId=" & marketPlaceId _ & "&SellerId=" & sellerId _ & "&SignatureMethod=HmacSHA256" _ & "&SignatureVersion=2" _ & "&Timestamp=" & timeStamp _ & "&Version=" & apiVersion paramToSign = "POST" & vbLf & endPoint & vbLf & "/Products/2011-10-01" & vbLf & param sign = GetSign(seacretKey, paramToSign) param = param & "&Signature=" & sign MakeParam = param End Function '結果XMLから商品情報を取得 Sub GetShohinInfo(xml As Object, result() As Variant, asinList As Collection) Dim getProObj As Object Dim shohinObj As Object Dim itemObj As Object Dim wkObj As Object Dim strAsin As String Dim shohinMei As String Dim weight As Double Dim width As Double Dim height As Double Dim length As Double Dim category As String Dim reigai As String Dim resultRow As Long Dim wk As Collection Dim k As Integer Set getProObj = xml.SelectNodes("GetMatchingProductForIdResponse/GetMatchingProductForIdResult") ' 取得したProductオブジェクトを順次取り出し For k = 0 To getProObj.length - 1 '初期化 strAsin = "" shohinMei = "-" weight = 0 height = 0 length = 0 width = 0 category = "-" reigai = "-" 'ASIN 取得 For Each wkObj In getProObj(k).Attributes If wkObj.Name = "Id" Then strAsin = wkObj.Value End If Next wkObj ' ASINが取得できていれば処理を行う。 If strAsin <> "" Then 'エラーの場合 Set wkObj = getProObj(k).SelectNodes("Error/Message") If wkObj.length <> 0 Then reigai = wkObj(0).text Else '商品情報 Set shohinObj = getProObj(k).SelectNodes("Products/Product/AttributeSets/ns2:ItemAttributes") If shohinObj.length <> 0 Then ' 商品名を取得 Set wkObj = shohinObj(0).SelectSingleNode("ns2:Title") If Not wkObj Is Nothing Then shohinMei = Replace(wkObj.text, "\n", "") End If 'パッケージ Set itemObj = shohinObj(0).SelectNodes("ns2:PackageDimensions") If itemObj.length <> 0 Then '重さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Weight") If Not wkObj Is Nothing Then weight = wkObj.text * 453.592 End If '高さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Height") If Not wkObj Is Nothing Then height = wkObj.text * 2.54 End If '長さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Length") If Not wkObj Is Nothing Then length = wkObj.text * 2.54 End If '幅を取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Width") If Not wkObj Is Nothing Then width = wkObj.text * 2.54 End If Else '商品のみ Set itemObj = shohinObj(0).SelectNodes("ns2:ItemDimensions") If itemObj.length <> 0 Then '重さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Weight") If Not wkObj Is Nothing Then weight = wkObj.text * 453.592 End If '高さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Height") If Not wkObj Is Nothing Then height = wkObj.text * 2.54 End If '長さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Length") If Not wkObj Is Nothing Then length = wkObj.text * 2.54 End If '幅を取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Width") If Not wkObj Is Nothing Then width = wkObj.text * 2.54 End If End If End If 'カテゴリを取得 Set wkObj = shohinObj(0).SelectSingleNode("ns2:ProductGroup") If Not wkObj Is Nothing Then category = wkObj.text End If End If End If '情報のセット With Sheets("Result") '行数取得 Set wk = asinList(CStr(k + 1)) resultRow = wk("ROWS") result(resultRow, 2) = shohinMei If weight <> 0 Then result(resultRow, 3) = Application.WorksheetFunction.RoundUp(weight, 0) End If If height <> 0 Then result(resultRow, 4) = Application.WorksheetFunction.RoundUp(height, 0) End If If length <> 0 Then result(resultRow, 5) = Application.WorksheetFunction.RoundUp(length, 0) End If If width <> 0 Then result(resultRow, 6) = Application.WorksheetFunction.RoundUp(width, 0) End If result(resultRow, 7) = category result(resultRow, 8) = reigai End With End If Next k End Sub
実行結果
GetMatchingProductForIdの解説
VBAコードの解説の前に、GetMatchingProductForIdを例に公式ドキュメントの見方について説明しておきます。
スロットリングについて
けっこう重要なスロットリング。
ドキュメントにも書いてありますが、リクエストを送信できる頻度を制限するというものです。
スロットリングのドキュメントはこちら
スロットリング: リクエストを送信できる頻度を制限する
商品APIのスロットリング
簡単に言うとスマホの速度制限みたいなものですね。
使いすぎると制限されてリクエストの送信ができなくなります。
GetMatchingProductForIdのスロットリングを見てみると、
最大リクエストクォータ:20リクエスト
回復レート:1秒ごとに5商品
時間あたりのリクエストクォータ:1時間あたり18000リクエスト
と書いてありますね。
それぞれどういうものか解説します。
最大リクエストクォータ
1度に送信できるリクエスト数になります。
20リクエストとなっているので、1度に20商品の情報が取得することができる、ということになります。
それを超えると制限がかかります。
しかし、次で解説する回復レートに従って商品を取得していくので、あまり気にしなくていい項目です。
回復レート
1秒ごとに5商品 となっています。
そのままなんですが、1秒ごとに5商品の情報を取得すれば、制限にかからないことになります。
時間あたりのリクエストクォータ
1時間あたり18000リクエストとなっています。
そのままの意味で、1時間あたり18000リクエスト送ることができます。
単純計算で 1秒ごとに5商品の回復レートなので、1時間(3600秒) * 5商品 = 18000というだけのことです。
リクエストパラメーター
リクエストパラメーターには、このアクションで必須のパラメータが記載されています。
画像を見ていただけると必須パラメーターが3つあるので、それぞれ説明しますと、、、
MarketplaceId
国ごとに固定。日本の場合は、A1VC38T7YXB528 。
IdType
何を元に商品情報を取得するかを指定します。
今回はASINで取得するので「ASIN」を指定します。
IdList
IdTypeで決めたキーを指定します。
今回は商品のASINを指定します。
さらに最大:5つのId値とあるので、一度に5つまで指定できます。
レスポンス要素
リクエストを送信し、返ってくるXML形式のデータについて書いてあります。
正直分かりにくいので、スクラッチパッドや後述のレスポンス例と併用する必要があります。
例
クエリリクエスト例、レスポンス例のサンプルが載っています。
レスポンス例は、レスポンス要素と一緒に見るとこの値はこの項目なのかと理解できると思います。
VBAコードの解説
前回の記事で作成した接続確認のファイルに、新しいシートを追加してやっています。
Excelシート
商品情報を取得したいASINを記載する「ASIN」シート。
取得した情報を反映する「Result」シート。
この2つのシートを用意してください。
VBAコードについて
長いので大事なところだけ解説・・・
VBAに関するところはまた時間のある時に補足します。
結果格納用の2次元配列
ReDim result(1 To lstRow - 1, 1 To 8)
最初の方に取得した結果を保持するための2次元配列を宣言しています。
これはいちいちセルに結果をセットするよりも、配列に格納して最後にまとめて貼り付けた方が高速だからです。
「ASIN」シートからASINの読込
「ASIN」シートに記載されたASINを上から順に読み込んでいます。
一度にリクエストできるASINは5つまでなので、5個取り出したら次の処理へ行きます。
Set asinList = New Collection With Sheets("ASIN") ' ASINを取り出す j = 0 Do While j < 5 ' 最終行の場合、処理終了 If asinRow > lstRow Then Exit Do End If ' 情報をセット asin = CStr(.Cells(asinRow, 1).Value) If dic.exists(asin) = False Then '未処理のASINを処理 Set wk = New Collection wk.Add asin, "ASIN" wk.Add asinRow - 1, "ROWS" asinList.Add wk, CStr(asinList.Count + 1) '処理済ASINを格納 dic.Add asin, asinRow j = j + 1 End If '配列初期化 result(asinRow - 1, 1) = asin result(asinRow - 1, 2) = "-" result(asinRow - 1, 3) = "-" result(asinRow - 1, 4) = "-" result(asinRow - 1, 5) = "-" result(asinRow - 1, 6) = "-" result(asinRow - 1, 7) = "-" result(asinRow - 1, 8) = "-" ' 次行へ asinRow = asinRow + 1 Loop End With
If dic.exists(asin) = False Then '未処理のASINを処理
上記の1行で、重複ASINを除いています。
一度にリクエストする5つの中に同じASINがあると、重複分についてレスポンスが返ってこなくなります。
それを防ぐためにこの処理を入れています。
Set wk = New Collection wk.Add asin, "ASIN" wk.Add asinRow - 1, "ROWS" asinList.Add wk, CStr(asinList.Count + 1)
上記の処理はASINとExcelの行数をCollectionに入れて保持しています。
重複ASINを除くため、行数を保持しておかないと整合性が取れなくなるためです。
IdListのパラメーター作成
上記で必須パラメーターのIdListについて、解説しましたが、そのパラメーターを作成しています。
param = "" ' ASINを1つずつ取り出す j = 1 For Each wk In asinList If j = 1 Then param = "&IdList.ASIN." & j & "=" & wk("ASIN") Else param = param & "&IdList.ASIN." & j & "=" & wk("ASIN") End If j = j + 1 Next ' リクエストを作成 param = MakeParam(param)
上記の実行結果のように3つASINを載せている場合、下記のようなパラメーターになります。
&IdList.ASIN.1=B079CDTFS3
&IdList.ASIN.2=B07RZJMQLG
&IdList.ASIN.3=B07BDW8H1W
リクエストの作成
前回記事の接続確認と似たようなコードになります。
'パラメータ作成 Function MakeParam(idList As String) As String Dim param As String Dim paramToSign As String Dim sellerId As String Dim accessKey As String Dim seacretKey As String Dim endPoint As String Dim marketPlaceId As String Dim timeStamp As String Dim apiVersion As String Dim sign As String Dim url As String 'パラメータの取得 With Sheets("MWS") sellerId = .Range("B1").Value accessKey = .Range("B2").Value seacretKey = .Range("B3").Value End With endPoint = "mws.amazonservices.jp" marketPlaceId = "A1VC38T7YXB528" timeStamp = Format(CDate(DateAdd("h", -9, Now)), "yyyy-mm-dd") & "T" & Format(CDate(DateAdd("h", -9, Time)), "hh%3AMM%3Ass") & "Z" apiVersion = "2011-10-01" ' リクエストを作成(パラメータはアルファベット順なので順番を変えるとNG) param = "AWSAccessKeyId=" & accessKey _ & "&Action=GetMatchingProductForId" _ & idList _ & "&IdType=ASIN" _ & "&ItemCondition=New" _ & "&MarketplaceId=" & marketPlaceId _ & "&SellerId=" & sellerId _ & "&SignatureMethod=HmacSHA256" _ & "&SignatureVersion=2" _ & "&Timestamp=" & timeStamp _ & "&Version=" & apiVersion paramToSign = "POST" & vbLf & endPoint & vbLf & "/Products/2011-10-01" & vbLf & param sign = GetSign(seacretKey, paramToSign) param = param & "&Signature=" & sign MakeParam = param End Function
今回は接続確認で指定したパラメーターに加えて、上記で解説した3つの必須パラメーターが加わっています。
& idList _
は先ほど説明したASINのリストになります。
& "&IdType=ASIN" _
でASINを指定。
& "&MarketplaceId=" & marketPlaceId _
は日本なので、A1VC38T7YXB528で固定。
商品情報取得
今回のキモとなる部分ですね。
レスポンスから商品情報を取得します。
長いですがやってることは単純です。
'結果XMLから商品情報を取得 Sub GetShohinInfo(xml As Object, result() As Variant, asinList As Collection) Dim getProObj As Object Dim shohinObj As Object Dim itemObj As Object Dim wkObj As Object Dim strAsin As String Dim shohinMei As String Dim weight As Double Dim width As Double Dim height As Double Dim length As Double Dim category As String Dim reigai As String Dim resultRow As Long Dim wk As Collection Dim k As Integer Set getProObj = xml.SelectNodes("GetMatchingProductForIdResponse/GetMatchingProductForIdResult") ' 取得したProductオブジェクトを順次取り出し For k = 0 To getProObj.length - 1 '初期化 strAsin = "" shohinMei = "-" weight = 0 height = 0 length = 0 width = 0 category = "-" reigai = "-" 'ASIN 取得 For Each wkObj In getProObj(k).Attributes If wkObj.Name = "Id" Then strAsin = wkObj.Value End If Next wkObj ' ASINが取得できていれば処理を行う。 If strAsin <> "" Then 'エラーの場合 Set wkObj = getProObj(k).SelectNodes("Error/Message") If wkObj.length <> 0 Then reigai = wkObj(0).text Else '商品情報 Set shohinObj = getProObj(k).SelectNodes("Products/Product/AttributeSets/ns2:ItemAttributes") If shohinObj.length <> 0 Then ' 商品名を取得 Set wkObj = shohinObj(0).SelectSingleNode("ns2:Title") If Not wkObj Is Nothing Then shohinMei = Replace(wkObj.text, "\n", "") End If 'パッケージ Set itemObj = shohinObj(0).SelectNodes("ns2:PackageDimensions") If itemObj.length <> 0 Then '重さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Weight") If Not wkObj Is Nothing Then weight = wkObj.text * 453.592 End If '高さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Height") If Not wkObj Is Nothing Then height = wkObj.text * 2.54 End If '長さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Length") If Not wkObj Is Nothing Then length = wkObj.text * 2.54 End If '幅を取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Width") If Not wkObj Is Nothing Then width = wkObj.text * 2.54 End If Else '商品のみ Set itemObj = shohinObj(0).SelectNodes("ns2:ItemDimensions") If itemObj.length <> 0 Then '重さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Weight") If Not wkObj Is Nothing Then weight = wkObj.text * 453.592 End If '高さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Height") If Not wkObj Is Nothing Then height = wkObj.text * 2.54 End If '長さを取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Length") If Not wkObj Is Nothing Then length = wkObj.text * 2.54 End If '幅を取得 Set wkObj = itemObj(0).SelectSingleNode("ns2:Width") If Not wkObj Is Nothing Then width = wkObj.text * 2.54 End If End If End If 'カテゴリを取得 Set wkObj = shohinObj(0).SelectSingleNode("ns2:ProductGroup") If Not wkObj Is Nothing Then category = wkObj.text End If End If End If '情報のセット With Sheets("Result") '行数取得 Set wk = asinList(CStr(k + 1)) resultRow = wk("ROWS") result(resultRow, 2) = shohinMei If weight <> 0 Then result(resultRow, 3) = Application.WorksheetFunction.RoundUp(weight, 0) End If If height <> 0 Then result(resultRow, 4) = Application.WorksheetFunction.RoundUp(height, 0) End If If length <> 0 Then result(resultRow, 5) = Application.WorksheetFunction.RoundUp(length, 0) End If If width <> 0 Then result(resultRow, 6) = Application.WorksheetFunction.RoundUp(width, 0) End If result(resultRow, 7) = category result(resultRow, 8) = reigai End With End If Next k End Sub
Set getProObj = xml.SelectNodes("GetMatchingProductForIdResponse/GetMatchingProductForIdResult")
上記のコードでXML形式のオブジェクトを取得しています。
ここでAmazon スクラッチパッドの出番です。
Amazon.com - Marketplace Web Service
下記画像のように入力すると、結果が返ってきます。
Set getProObj = xml.SelectNodes("GetMatchingProductForIdResponse/GetMatchingProductForIdResult")
これタグをスラッシュ区切りにして取得しているんですね。
SelectNodesとSelectSingleNodeを使って取得しているだけのコードになっています。
SelectNodesは指定された文字列に該当するものを全て取得。配列になります。
SelectSingleNodeは最初に見つかった1つを取得します。
GetMatchingProductForIdResult タグに1つのASINの情報が入っていて、今回はそれが3つあるのでSelectNodesで取得。
商品名や重さなどの項目は1つしかないはずなのでSelectSingleNodeで取得しています。
ウェイト
1リクエストしたら、スロットリングの制限を受けないように1秒のウェイトを入れます。
'1秒のウェイト Sleep 1000
まとめ
いかがでしたでしょうか?
また分からないこと等ありましたら、コメントやTwitterでご連絡ください。