.NETでAWSのAPIを使う
2018/03/28
VB.NETでAmazonのWEB APIを使った際の備忘録。
今回調べて分かったことは、
・URLのパラメータに、タイムスタンプ(GMT)と、シグネチャが必須となっている
・他にもパラメータの順番や使用可否など、細かいガイドラインがある。しかも国で違うらしい
・リクエストには制限がある(1回/秒、最大10回/秒?)ので、連続して実行する場合は、sleepをかける必要がある
リクエスト数の上限/秒 = 1 + (過去30日間の配送済み商品売上実績 / 460,000円)の小数点以下を四捨五入した数
・新品価格がうまく取れない場合もあるらしい(未確認)
以下、ASINから商品情報、在庫情報などを取得(ItemLookUp)するVBのサンプルコード
Public Class Form1
Private Const AWS_ASSOCIATE_TAG As String = "xxxx-22"
Private Const AWS_ACCESS_KEY_ID As String = "ABCDEFGHIJKLMNOPQRST"
Private Const AWS_SECRET_KEY As String = "UVWXYZ1234567890abcdefghijklmnopqrstuvwx"
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' ASINを指定
Dim asin As String = "B015IFTSMM"
' リクエストURLを作成する
Dim url As String = CreateAWSUrl(asin)
Console.Write(url)
End Sub
Private Function CreateAWSUrl(ByVal asin As String) As String
Try
' パラメータハッシュテーブル
Dim reqtionary As New Dictionary(Of String, String)
reqtionary("Service") = "AWSECommerceService"
reqtionary("Version") = "2008-04-07"
reqtionary("AssociateTag") = AWS_ASSOCIATE_TAG
reqtionary("ContentType") = "Text/XML"
reqtionary("Operation") = "ItemLookup" ' "ItemSearch"
reqtionary("Availability") = "Available"
reqtionary("ResponseGroup") = "ItemAttributes,OfferSummary" ' 商品情報と在庫情報なんかを見たいとき
'reqtionary("ResponseGroup") = "Small,ItemAttributes,Reviews,EditorialReview,Images,BrowseNodes,SalesRank,Offers"
reqtionary("AWSAccessKeyId") = AWS_ACCESS_KEY_ID
'reqtionary("Condition") = "New"
'reqtionary("SearchIndex") = "All" ' ItemSearchなら必要
reqtionary("ItemId") = asin
'reqtionary("Keywords") = ""
' タイムスタンプはGMT!
Dim dteNow As DateTime = DateTime.UtcNow
Dim sTimeStamp As String = dteNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
reqtionary("Timestamp") = sTimeStamp
' ソートして
Dim paramComp As New ParameterComparer()
Dim sortedReqtionary As New SortedDictionary(Of String, String)(reqtionary, paramComp)
' canonical用正規URL取得
Dim canonicalQueryStr As String = CreateCanonicalQueryString(sortedReqtionary)
' ヘッダ部に以下の文字列を追加する
'GET
'ecs.amazonaws.jp(US:ecs.amazonaws.com)
'/onca/xml
Dim urlBuilder As New System.Text.StringBuilder()
urlBuilder.Append("GET")
urlBuilder.Append(vbLf)
urlBuilder.Append("ecs.amazonaws.jp")
urlBuilder.Append(vbLf)
urlBuilder.Append("/onca/xml")
urlBuilder.Append(vbLf)
urlBuilder.Append(canonicalQueryStr)
' シグネチャを作成する
Dim urlStr As Byte() = System.Text.Encoding.UTF8.GetBytes(urlBuilder.ToString())
Dim secKey As Byte() = System.Text.Encoding.UTF8.GetBytes(AWS_SECRET_KEY)
Dim signHMAC As System.Security.Cryptography.HMAC = New Security.Cryptography.HMACSHA256(secKey)
Dim signByte As Byte() = signHMAC.ComputeHash(urlStr)
Dim signature As String = Convert.ToBase64String(signByte)
' 最終整形
urlBuilder.Length = 0
urlBuilder.Append("http://")
urlBuilder.Append("ecs.amazonaws.jp")
urlBuilder.Append("/onca/xml")
urlBuilder.Append("?")
urlBuilder.Append(canonicalQueryStr)
urlBuilder.Append("&Signature=")
urlBuilder.Append(EncodeRfc3986(signature))
Return urlBuilder.ToString()
Catch ex As Exception
MsgBox("ERROR!" & vbCrLf & "詳細:" & ex.Message, vbOKOnly)
Return ""
End Try
End Function
''' <summary>
''' canonical用URLを作成する
''' </summary>
''' <param name="sortedParamHash"></param>
''' <returns></returns>
Private Function CreateCanonicalQueryString(ByVal sortedParamHash As SortedDictionary(Of String, String)) As String
Try
If sortedParamHash.Count = 0 Then Return ""
Dim queryBuilder As New System.Text.StringBuilder()
For Each kvp As KeyValuePair(Of String, String) In sortedParamHash
queryBuilder.Append(EncodeRfc3986(kvp.Key))
queryBuilder.Append("=")
queryBuilder.Append(EncodeRfc3986(kvp.Value))
queryBuilder.Append("&")
Next
Dim canonicalQueryStr As String = queryBuilder.ToString()
canonicalQueryStr = canonicalQueryStr.Substring(0, canonicalQueryStr.Length - 1)
Return canonicalQueryStr
Catch ex As Exception
Throw
End Try
End Function
''' <summary>
''' Rfc3986に基づき、URLをエンコーディングする
''' </summary>
''' <param name="str"></param>
''' <returns></returns>
Private Function EncodeRfc3986(ByVal str As String) As String
Try
' UTF-8でURLエンコ
str = System.Web.HttpUtility.UrlEncode(str, System.Text.Encoding.UTF8)
' RFC3986に基づき、文字列を置換する
str = str.Replace("'", "%27").Replace("(", "%28").Replace(")", "%29").Replace("*", "%2A").Replace("!", "%21").Replace("%7e", "~").Replace("+", "%20")
Dim strBuilder As New System.Text.StringBuilder(str)
For i As Integer = 0 To strBuilder.Length - 1
' マルチバイト文字対応
If strBuilder(i) = "%"c Then
strBuilder(i + 1) = [Char].ToUpper(strBuilder(i + 1))
strBuilder(i + 2) = [Char].ToUpper(strBuilder(i + 2))
End If
Next
Return strBuilder.ToString()
Catch ex As Exception
Throw
End Try
End Function
End Class
''' <summary>
''' Parameter Comparer Class
''' </summary>
Class ParameterComparer
Implements IComparer(Of String)
Public Function Compare(ByVal pram1 As String, ByVal param2 As String) As Integer Implements IComparer(Of String).Compare
Return String.CompareOrdinal(pram1, param2)
End Function
End Class
多くに人が利用するので当然といえば当然ですが、ガイドラインがやたら細かいし、複雑に思えました。
それをインターネットで調べようとすると古い情報がそのまま残っていたりするおかげで、さらに混乱しそうになりました。
この記事も、すぐに古い情報になるでしょう。
シグネチャ(署名)の作成あたりは特に敷居が高いように思います。
とりあえず、検索結果が返ってくるようになったので、よし!