Go言語でAmazonの商品検索を行う。

# やりたいこと

Go言語の勉強の一環として、Amazonの商品検索結果を取得するプログラミングを作成する。

# 環境

* Windows 11 Pro
* Go バージョン 1.22.4

# 事前準備

## アクセスキーとシークレットキーの取得

AmazonアソシエイトのAmazon Product Advertising API(PA-API）にアプリケーションを登録し、アクセスキーとシークレットキーを取得する。

https://affiliate.amazon.co.jp/

![スクリーンショット 2024-07-15 101513.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624329/e28e7417-171b-f7bc-2412-912f08d53b78.png)

## pa-apiモジュールの取得

github.com/goark/pa-apiからモジュールを取得する

```powershell
go mod init pa-api
go get github.com/goark/pa-api@latest
```

# コード

アソシエイトタグはAmazonアソシエイトのページの右上に表示されているIDを入力。

```main.go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"

	paapi5 "github.com/goark/pa-api"
	"github.com/goark/pa-api/entity"
	"github.com/goark/pa-api/query"
)

type Response struct {
	SearchResult SearchResultContent `json:"SearchResult"`
}

type SearchResultContent struct {
	Items            []Item `json:"Items"`
	SearchURL        string `json:"SearchURL"`
	TotalResultCount int    `json:"TotalResultCount"`
}

type Item struct {
	ASIN          string   `json:"ASIN"`
	ParentASIN    string   `json:"ParentASIN"`
	DetailPageURL string   `json:"DetailPageURL"`
	Images        Images   `json:"Images"`
	ItemInfo      ItemInfo `json:"ItemInfo"`
}

type Images struct {
	Primary ImageSet `json:"Primary"`
}

type ImageSet struct {
	Large  Image `json:"Large"`
	Medium Image `json:"Medium"`
	Small  Image `json:"Small"`
}

type Image struct {
	URL    string `json:"URL"`
	Height int    `json:"Height"`
	Width  int    `json:"Width"`
}

type ItemInfo struct {
	ByLineInfo      ByLineInfo      `json:"ByLineInfo"`
	Classifications Classifications `json:"Classifications"`
	ContentInfo     ContentInfo     `json:"ContentInfo"`
	ProductInfo     ProductInfo     `json:"ProductInfo"`
	TechnicalInfo   TechnicalInfo   `json:"TechnicalInfo"`
	Title           Title           `json:"Title"`
}

type ByLineInfo struct {
	Manufacturer Manufacturer  `json:"Manufacturer"`
	Contributors []Contributor `json:"Contributors"`
}

type Manufacturer struct {
	DisplayValue string `json:"DisplayValue"`
	Label        string `json:"Label"`
	Locale       string `json:"Locale"`
}

type Contributor struct {
	Name   string `json:"Name"`
	Locale string `json:"Locale"`
	Role   string `json:"Role"`
}

type Classifications struct {
	Binding      Classification `json:"Binding"`
	ProductGroup Classification `json:"ProductGroup"`
}

type Classification struct {
	DisplayValue string `json:"DisplayValue"`
	Label        string `json:"Label"`
	Locale       string `json:"Locale"`
}

type ContentInfo struct {
	Languages  Languages `json:"Languages"`
	PagesCount struct {
		DisplayValue int    `json:"DisplayValue"`
		Label        string `json:"Label"`
		Locale       string `json:"Locale"`
	} `json:"PagesCount"`
	PublicationDate struct {
		DisplayValue string `json:"DisplayValue"`
		Label        string `json:"Label"`
		Locale       string `json:"Locale"`
	} `json:"PublicationDate"`
}

type Languages struct {
	DisplayValues []Language `json:"DisplayValues"`
	Label         string     `json:"Label"`
	Locale        string     `json:"Locale"`
}

type Language struct {
	DisplayValue string `json:"DisplayValue"`
	Type         string `json:"Type"`
}

type ProductInfo struct {
	IsAdultProduct struct {
		DisplayValue bool   `json:"DisplayValue"`
		Label        string `json:"Label"`
		Locale       string `json:"Locale"`
	} `json:"IsAdultProduct"`
	ReleaseDate struct {
		DisplayValue string `json:"DisplayValue"`
		Label        string `json:"Label"`
		Locale       string `json:"Locale"`
	} `json:"ReleaseDate"`
	ItemDimensions ItemDimensions `json:"ItemDimensions,omitempty"`
	UnitCount      struct {
		DisplayValue int    `json:"DisplayValue"`
		Label        string `json:"Label"`
		Locale       string `json:"Locale"`
	} `json:"UnitCount,omitempty"`
}

type ItemDimensions struct {
	Height Length `json:"Height"`
	Length Length `json:"Length"`
	Weight Length `json:"Weight"`
	Width  Length `json:"Width"`
}

type Length struct {
	DisplayValue float64 `json:"DisplayValue"`
	Label        string  `json:"Label"`
	Locale       string  `json:"Locale"`
	Unit         string  `json:"Unit"`
}

type TechnicalInfo struct {
	Formats Formats `json:"Formats"`
}

type Formats struct {
	DisplayValues []string `json:"DisplayValues"`
	Label         string   `json:"Label"`
	Locale        string   `json:"Locale"`
}

type Title struct {
	DisplayValue string `json:"DisplayValue"`
	Label        string `json:"Label"`
	Locale       string `json:"Locale"`
}

func main() {
	//Create client for Janan region
	client := paapi5.New(
		paapi5.WithMarketplace(paapi5.LocaleJapan),
	).CreateClient(
		[アソシエイトタグ],
		[アクセスキー],
		[シークレットキー],
		paapi5.WithHttpClient(http.DefaultClient),
	)
	fmt.Println("Marketplace:", client.Marketplace())
	// Output:
	// Marketplace: www.amazon.co.jp

	q := query.NewSearchItems(
		client.Marketplace(),
		client.PartnerTag(),
		client.PartnerType(),
	).Search(query.Keywords, [けんさくわーど]).EnableImages().EnableItemInfo().EnableParentASIN()

	//Request and response
	body, err := client.RequestContext(context.Background(), q)
	if err != nil {
		fmt.Printf("%+v\n", err)
		return
	}

	jsonString, err := entity.DecodeResponse(body)
	if err != nil {
		fmt.Printf("%+v\n", err)
		return
	}
	fmt.Println(jsonString.String())

	var response Response
	err1 := json.Unmarshal([]byte(jsonString.String()), &response)
	if err1 != nil {
		fmt.Println("Error decoding JSON:", err1)
		return
	}
	fmt.Printf("Parsed Response: %+v\n", response)

}
```

# 実行結果(jsonを整形したもの)

```
{
  "GenreInformation": [],
  "Items": [
    {
      "affiliateRate": 2,
      "affiliateUrl": "",
      "asurakuArea": "",
      "asurakuClosingTime": "",
      "asurakuFlag": 0,
      "availability": 1,
      "catchcopy": "かっこいい ホンダ VFR ステッカー 防水耐水 車 バイク ヘルメット アウトドア用品 雑貨グッズ おしゃれ ステッカーチューン ボディ ドア ボンネット へこみ引っかき傷隠しに",
      "creditCardFlag": 1,
      "endTime": "",
      "genreId": "112034",
      "giftFlag": 0,
      "imageFlag": 1,
      "itemCaption": "【サイズ】2枚で1セット 1枚：約120mmX約95mm ※多少の誤差がある場合があります。【カラー】 ブラック:黒色/ホワイト:白色/ブルー:青色 レッド:赤色/オレンジ:橙色/イエロー:黄色 シルバー:銀色/ゴールド:金色/ピンク:桃色 ラベンダー:薄紫 色/ライム:黄緑色 アイスブルー:水色 　の全12色より1色をお選びください。 　 　※お使いのモニター環境により実色と 　 　　異なる場合がございます。 　 　　色の見え方は個人差がございます。 　 　　了承ください。 【カッティングステッカーとは】 図柄、ロゴ、文字部分のみが残る「切り文字」「抜き文字」タイプの転写ステッカー デカールです 透明シートと図柄部分を一緒に台紙より剥がし、貼り付けた後、透明シートを剥し、図柄を残すステッカーで す。 到着後、直ぐに貼付け可能なフィルムタイプの透明転写シート（緩曲面対応）付き。　 裏面同色、屋外使用可能（屋外耐候4-5年、耐水）　 裏面同色ですので、内張用に鏡反転の作成も可能です。 ご希望の方はご連絡ください。 無料で反転処理いたします。 当店 M'sWorks ( エムズワークス )のステッカーは全てカッティングステッカーです。 お気に入りのアイテム、グッズにカッティングステッカーを簡単に貼るだけで、存在感をアップさせ、個性豊かな唯一無二のオンリーワンに変化させませんか？ 貼り付け場所はオリジナルなキラリと光るセンスとアイデア次第。 一緒にこちらもいかが？？ 個性豊かな数多くのステッカーをご用意 ↓↓他の類似ステッカーはコチラ↓↓まだまだあります↓↓ランキング&オススメはコチラ↓↓格好良くクール、オシャレで可愛い、ワンポイント 目印 DIYに最適と人気なバイナル カッティングステッカー。 貼るだけ簡単お手軽ステッカーチューンで自慢の愛車、バイクやお気に入りのアイテムを自分好みに。 個性的でカッコよく目立つカスタム&ドレスアップが可能。 趣味をアピールしたり、ユニークでユーモアのある面白マークステッカー装飾で所有者をさりげなく主張。 【屋外耐候性に優れています】 カー用品 として ボデ ィ、ボンネッ ト、リアゲー ト、バンパー、給油口、リアウィンドウ、サイドウィンドウや愛車のドアなどに張り付けるステッカーチューンに。 オートバイ カウル、タンク、フェンダー、スクリーン、パニアケース、リアボックス (リアbox)、ロードバイクのヘルメットなど、バイク用品のワンポイントにも。 チョットした 擦り傷 、引っかき傷 などの傷隠しに最適です。 普通車、 軽カー、 軽トラ、 トラック、 デコトラ 車種を問わずに ステッカー チューニング 【耐水性です】 水が掛かる場所への貼り付けもOK。 スキー板やスノーボード（スノボ板）、サーフボード、ダイビング用品、ジェットスキー(水上バイク)、バスボートなどの船舶。 クーラーボックスを始めアウトドア用品、釣り用具、工具箱、グッズなどに。 【野外野内、屋内屋外を問わず】 インテリア、エクステリア用品、冷蔵庫、トイレ 蓋、雑貨や ノートパソコン、タブレット、ショーウィンドウや看板、お店の窓ガラスやウェルカムプレート、表札、ツールボックス、ギター バイオリンケース や 楽器のハードケース、スーツケースの目印などに。 【オンリーワン】 ツーリング、サークル、部活動や趣味の仲間同士、チームメイト同士の目印やワンチームとしての統一感に。 他人の持ち物との差別化が図れるため、盗難防止にも一役。 【手軽なサプライズプレゼント】 父の日にはお父さんのバイクに。母の日にはお母さんの愛車に。彼氏彼女恋人の誕生日や記念日。 同僚への納車祝いや各種イベント時などの手軽なサプ ライズプレゼントにも。 気を使わない気軽な贈り物としても重宝されてます。 【材質】 　 ・素材：ソフト塩ビシート 　 ・糊：溶剤系ポリアクリル強粘着糊 　 ・フィルム厚：80μ（0.08mm） 　 　 ※離型紙、糊を含まず 　 ・転写 用透明シートを貼った状態 　 　 ※緩曲面対応の為、一般より柔らかい 　 ・屋外広告用（看板）マーキングフィルム 　 ・屋外耐候4-5年 　 　 ※メーカーカタログ値です 　 　 　　　　使用環境により大きく変動 　 　 ※保証値ではございません。 【直ぐ剥がれる・貼りつかない素材】 　 ・セロハンテープなどがしっかり貼れない素材 　 ・フッ素加工されたもの 　 ・プラスチックでもマット加工のもの 　 ・布やテント生地等の繊維素材 　 ・柔らかい・伸び る素材 　 ・ワックス・コーティング済素材 　 ・ザラザラ素材(シボ面、凹凸面、粗面等) 　 ・変形素材(布・繊維生地/テント生地/PP/PE/ゴム)等 　 　 ※人体への使用、食器へは使用不可。 【ご注意】 　 ・低い気温では粘着が低 下します。 　 　高い気温では伸びる場合が在ります。 　 　 ※適温下での作業をお勧め致します。 　 ・細かい部分は非常に剥がれ易い為、貼付け時貼付け後の管理は十分ご注意ください。 　 ・貼付け後は擦らない様にしてください。 ↓↓カッティングステッカーの詳しい説明はコチラ↓↓ ↓↓貼り方の例はコチラ↓↓【商品名】VFR 乗りですがなにか？ (2枚1セット) カッティングステッカー全12色 約120mmX約95mm HITBNH-006バイク ステッカー スクリーン VFR400 VFR750 VFR1000 VFR1200 ツール ボックス ケース おもしろ デカール 防水 耐水 アウトドア 切り文字 転写 シール格好良くクール、オシャレで可愛い、ワンポイント 目印 DIYに最適と人気なバイナル カッティングステッカー。 貼るだけ簡単お手軽ステッカーチューンで自慢の愛車、バイクやお気に入りのアイテムを自分好みに。 個性的でカッコよく目立つカスタム&ドレスアップが可能。 趣味をアピールしたり、ユニークでユーモアのある面白マークステッカー装飾で 所有者をさりげなく主張。 【屋外耐候性に優れています】 カー用品 として ボディ、ボンネッ ト、リアゲー ト、バンパー、給油口、リアウィンドウ、サイドウィンドウや愛車のドアなどに張り付けるステッカーチューンに。 オート バイ カウル、タンク、フェンダー、スクリーン、パニアケース、リアボックス (リアbox)、ロードバイクのヘルメットなど、バイク用品のワンポイントにも。 チョットした 擦り傷 、引っかき傷 などの傷隠しに最適です。 普通車、  軽カー、 軽トラ、 トラック、 デコトラ 車種を問わずに ステッカー チューニング 【耐水性です】 水が掛かる場所への貼り付けもOK。 スキー板やスノーボード（スノボ板）、サーフボード、ダイビング用品、ジェットスキー(水上バイク)、バスボートなどの船舶。 クーラーボックスを始めアウトドア用品、釣り用具、工具箱、グッズなどに。 【野外野内、屋内屋外を問わず】 インテリア、エクステリア用品、冷蔵庫、トイレ 蓋、雑貨や ノートパソコン、タブレット、ショーウィンドウや看板、お店の窓ガラスやウェルカムプレート、表札、ツールボックス、ギター バイオリンケース や 楽器のハードケース、スーツケースの目印などに。 【オンリーワン】 ツーリング、サークル、部活動や趣味 の仲間同士、チームメイト同士の目印やワンチームとしての統一感に。 他人の持ち物との差別化が図れるため、盗難防止にも一役。 【手軽なサプライズプレゼント】 父の日にはお父さんのバイクに。母の日にはお母さんの愛車に。彼 氏彼女恋人の誕生日や記念日。 同僚への納車祝いや各種イベント時などの手軽なサプライズプレゼントにも。 気を使わない気軽な贈り物としても重宝されてます。 お気に入りのアイテム、グッズにカッティングステッカーを簡単に貼 るだけで、存在感をアップさせ、個性豊かな唯一無二のオンリーワンに変化させませんか？ 貼り付け場所はオリジナルなキラリと光るセンスとアイデア次第。【サイズ】2枚で1セット 1枚：約120mmX約95mm ※多少の誤差がある場合があ ります。カラーはブラック(黒色)、ホワイト(白色)、ブルー(青色)、レッド(赤色)、オレンジ(橙色)、イエロー(黄色)、シルバー(銀色)、ゴールド(金色)、ピンク(桃色)、ラベンダー(薄紫色)、ライム(黄緑色)、アイスブルー(水色)全12色よりお選び頂けます。耐候耐水に優れてますので貼る場所はアイデア次第！！シールと違い余計な部分が無いので素材との一体感があります。ご注文後に弊社にて一点一点作成致します。曲がらないように厚紙で梱包しての発送です。「かご」が別(注文番号が別)の物は当店で勝手に同梱致しません。「かご」(注文番号)単位で発送致します。送料は「かご」単位に発生します。ご注意ください。 おすすめカッティングステッカーの使い方 車、バイクの簡単、お手軽ドレスアップやカスタマイズに。簡易的な傷隠しや盗難防止にも一役 カー用品 ボンネット、フロント、リア、サイド、ボディ、バンパー、給油口 、リアウィンドウ、サイドウィンドウ、リアガラス、サイドガラス、窓ガラス、バックウ ィンドウ オートバイ、バイク用品 ヘルメット タンク カウル フェンダー スクリーン リアボックス リアbox パニアケース サイドボックス レーシングチーム、ツーリングチームなどのグループの一体感に！！納車祝いや誕生日、父の日、母の日等、ちょっとしたサプライズプレゼント贈り物としても最適。 防水 耐水 なのでマリン、ウインタースポーツやレジャーにキラリと光る個性を スポーツ用品 スキー、スノーボード、スノボー、ボード(板)、スケートボード 板、スケボー板、ジェットスキー(水上バイク)、バスボートなどの船舶 自転車用品 マウンテンバイク ロードバイク クロスバイク レジャー用品 スーツケース、ハードケース、旅行ケース サークルやチームメイトなど団体、部活仲間 同士の目印に！！ ワンポイントで趣味の主張、アピール 釣り具用品 フィッシング、魚釣り(つり)、クーラーボックス(ハードボックス) アウトドア用品 キャンプ、バーベキュー(BBQ)、用具 文字やマークで所有者を主張して、盗難防 止にも一役！！ インテリア、エクステリアなど自分好みにカスタマイズ 屋外 野外 表札、看板、ポスト、ウェルカムボード、ドア、窓ガラス。店舗やお店の自動ドア、注意喚起、ディスプレイ、ショーウィンドウ 屋内 野内 ギター、 楽器ケース、トイレ (お手洗い) 蓋、、冷蔵庫、洗濯機、掃除機 、タンス。 道具箱、ツールボックス、パソコン、ノートパソコン、PC、タブレッド ちょっとした生活空間のワンポイントに！！ ※張り付かない素材も御座います。ご注 意ください。 ※セロハンテープ等がしっかり張り付く場所なら大丈夫です。 ※一般的な印刷シールタイプとは異なります。お間違いのないようお願い致します。",
      "itemCode": "msworks:10000362",
      "itemName": "バイク ステッカー VFR 乗りですがなにか？ (2枚1セット) カッティングステッカー 全12色(120{
  "SearchResult": {
    "Items": [
      {
        "ASIN": "B00EYXMA9I",
        "ParentASIN": "",
        "DetailPageURL": "https://www.amazon.co.jp/dp/B00EYXMA9I?tag=taki0416-22&linkCode=osi&th=1&psc=1",
        "Images": {
          "Primary": {
            "Large": {
              "URL": "https://m.media-amazon.com/images/I/41ETMZ7i9qL._SL500_.jpg",
              "Height": 500,
              "Width": 356
            },
            "Medium": {
              "URL": "https://m.media-amazon.com/images/I/41ETMZ7i9qL._SL160_.jpg",
              "Height": 160,
              "Width": 113
            },
            "Small": {
              "URL": "https://m.media-amazon.com/images/I/41ETMZ7i9qL._SL75_.jpg",
              "Height": 75,
              "Width": 53
            }
          }
        },
        "ItemInfo": {
          "ByLineInfo": {
            "Manufacturer": {
              "DisplayValue": "SBクリエイティブ",
              "Label": "Manufacturer",
              "Locale": "ja_JP"
            },
            "Contributors": [
              {
                "Name": "結城 浩",
                "Locale": "ja_JP",
                "Role": "著"
              }
            ]
          },
          "Classifications": {
            "Binding": {
              "DisplayValue": "Kindle版",
              "Label": "Binding",
              "Locale": "ja_JP"
            },
            "ProductGroup": {
              "DisplayValue": "Digital Ebook Purchas",
              "Label": "ProductGroup",
              "Locale": "ja_JP"
            }
          },
          "ContentInfo": {
            "Languages": {
              "DisplayValues": [
                {
                  "DisplayValue": "日本語",
                  "Type": "発行"
                }
              ],
              "Label": "Language",
              "Locale": "ja_JP"
            },
            "PagesCount": {
              "DisplayValue": 332,
              "Label": "NumberOfPages",
              "Locale": "en_US"
            },
            "PublicationDate": {
              "DisplayValue": "2007-06-26T00:00:00Z",
              "Label": "PublicationDate",
              "Locale": "en_US"
            }
          },
          "ProductInfo": {
            "IsAdultProduct": {
              "DisplayValue": false,
              "Label": "IsAdultProduct",
              "Locale": "en_US"
            },
            "ReleaseDate": {
              "DisplayValue": "2014-03-12T00:00:00Z",
              "Label": "ReleaseDate",
              "Locale": "en_US"
            }
          },
          "TechnicalInfo": {
            "Formats": {
              "DisplayValues": [
                "Kindle本"
              ],
              "Label": "Format",
              "Locale": "ja_JP"
            }
          },
          "Title": {
            "DisplayValue": "数学ガール",
            "Label": "Title",
            "Locale": "ja_JP"
          }
        }
      },
      {
        "ASIN": "B0BXDHFVRC",
        "ParentASIN": "",
        "DetailPageURL": "https://www.amazon.co.jp/dp/B0BXDHFVRC?tag=taki0416-22&linkCode=osi&th=1&psc=1",
        "Images": {
          "Primary": {
            "Large": {
              "URL": "https://m.media-amazon.com/images/I/41oTvYE4DbL._SL500_.jpg",
              "Height": 500,
              "Width": 348
            },
            "Medium": {
              "URL": "https://m.media-amazon.com/images/I/41oTvYE4DbL._SL160_.jpg",
              "Height": 160,
              "Width": 111
            },
            "Small": {
              "URL": "https://m.media-amazon.com/images/I/41oTvYE4DbL._SL75_.jpg",
              "Height": 75,
              "Width": 52
            }
          }
        },
        "ItemInfo": {
          "ByLineInfo": {
            "Manufacturer": {
              "DisplayValue": "SBクリエイティブ",
              "Label": "Manufacturer",
              "Locale": "ja_JP"
            },
            "Contributors": [
              {
                "Name": "結城 浩",
                "Locale": "ja_JP",
                "Role": "著"
              }
            ]
          },
          "Classifications": {
            "Binding": {
              "DisplayValue": "Kindle版",
              "Label": "Binding",
              "Locale": "ja_JP"
            },
            "ProductGroup": {
              "DisplayValue": "Digital Ebook Purchas",
              "Label": "ProductGroup",
              "Locale": "ja_JP"
            }
          },
          "ContentInfo": {
            "Languages": {
              "DisplayValues": [
                {
                  "DisplayValue": "日本語",
                  "Type": "発行"
                }
              ],
              "Label": "Language",
              "Locale": "ja_JP"
            },
            "PagesCount": {
              "DisplayValue": 0,
              "Label": "",
              "Locale": ""
            },
            "PublicationDate": {
              "DisplayValue": "2023-04-26T00:00:00Z",
              "Label": "PublicationDate",
              "Locale": "en_US"
            }
          },
          "ProductInfo": {
            "IsAdultProduct": {
              "DisplayValue": false,
              "Label": "IsAdultProduct",
              "Locale": "en_US"
            },
            "ReleaseDate": {
              "DisplayValue": "2023-04-27T00:00:00Z",
              "Label": "ReleaseDate",
              "Locale": "en_US"
            }
          },
          "TechnicalInfo": {
            "Formats": {
              "DisplayValues": [
                "Kindle本"
              ],
              "Label": "Format",
              "Locale": "ja_JP"
            }
          },
          "Title": {
            "DisplayValue": "数学ガールの秘密ノート／数を作ろう",
            "Label": "Title",
            "Locale": "ja_JP"
          }
        }
      },
    :
}
```