【API】AmazonのAPIをイジってみる@PA-API5

2023年3月20日プライベート

追記:browse_nodesが入ってない場合がある

追記:一部追記

追記:jsonレスポンスデータ(サンプル)

追記:指定値のメモリスト

前バージョンのPA-API4は触った事があるのですが、いつぞやサービスが終了していた。

(;^ω^)

現在はPA-API5として仕様が変わり提供されているようです(2020年頃の話ですがw)

サンプルコードがあるので、こちらを動作させたり、ちょいちょいカスタムしてみたりした程度の入り口付近記事で御座います。

まだ、リファレンスの細々としたところまで見てないので、了承ください。

公式ドキュメント(Product Advertising API 5.0 Documentation)

Python環境を用意

まずは、Pythonを捕獲しなくてはいけません。そっからです。

(;^ω^)

あとは、コーラとポテチを用意。

(他には、Java/PHP/Node.jsのサンプルがある)

公式SDKサンプル

※ここではPythonで話を進めていきます

これは普通にインストールして、SDK内のsetup.pyを実行して、必要なパッケージをインストールしておく必要があります。

※コンソールで試すなら、環境変数/PATH設定も行ってください

python setup.py install

これで、AmazonのGithubから必要なパッケージがインストールされます。

自分は、VisualStudioでテストしたいので、こちらから利用出来るよう設定しました。

VisualStudio内蔵(同時導入)と同じにしたくないので、別にPython環境を入れて、切り替えます。

上写真、パッケージの所で、Amazon/paapi5関連のパッケージを確認できます。

Amazonアソシエイトにキー申請

既にAmazonアソシエイト利用者さんと仮定しますが、こちらから、APIの認証キーを取得する必要があります。

ちなみに、APAAPI4の頃に取得した、認証キーではエラーになるようです。新しく取得し直す必要があるようです。

ここで、2つのキー(アクセスキー、シークレットキー)を入手する事になります。

※シークレットキーは、再確認できないのでメモする事

とりあえず動作させてみる

ここでは商品検索(sample_search_items_api.py)を実行してみましょう。

以下の部分を書き換えます。

access_key = “アクセスキー"
secret_key = “シークレットキー"
partner_tag = “アソシエイトタグ"
host = “webservices.amazon.co.jp" 日本はこれ
region = “us-west-2″ 日本はこれ

デフォルトだと、「ハリーポッター」を1件検索するコードになってるんですが、気分に応じて以下も書き換えてみてください。Amazonの検索の所と同じように書けるはず。

keywords = “検索ワード"

コンソールから実行するなら、以下で実行できます。

python sample_search_items_api.py

(生データ)json形式でずらずらーと表示されてから、最後に、1件の検索結果が表示されるはずです。

プログラミングに精通してるなら、最初に表示される生データのjson部分を見ると、こんな感じで結果が返されると分かると思います。

かつてのXMLよりも、スマートで綺麗に見えますねw

(;^ω^)

イジってみるタイム

んでは、イジイジしてみたくなるのが世の常で御座います。

サンプルから、余計?な部分を、省いた省エネなコードをご用意しましたので、よければこちらをどうぞ。

解説も入れてます。さっぱりしてるでしょ。

出力は、amazon_response.txtというテキストファイルとして書き出してます。

# -*- coding: utf-8 -*-

#from msilib.schema import Condition コメントにしないと動かんかった
from paapi5_python_sdk.api.default_api import DefaultApi
from paapi5_python_sdk.models.partner_type import PartnerType
from paapi5_python_sdk.models.search_items_request import SearchItemsRequest
from paapi5_python_sdk.models.search_items_resource import SearchItemsResource
from paapi5_python_sdk.rest import ApiException
import sys

def search_items():
     access_key = “アクセスキー“
     secret_key = “シークレットキー“
     partner_tag = “アソシエイトタグ“
     host = “webservices.amazon.co.jp"
     region = “us-west-2"
     default_api = DefaultApi(
         access_key=access_key, secret_key=secret_key, host=host, region=region
     )
     keywords = “検索ワード“
     search_index = “ジャンル" # 後述
     item_count = 10 # 1リクエスト辺りの数
     search_items_resource = [ # 要求したい戻り値のリスト
         SearchItemsResource.ITEMINFO_TITLE,
         SearchItemsResource.OFFERS_LISTINGS_PRICE,
         SearchItemsResource.IMAGES_PRIMARY_LARGE, # 画像のリクエスト
     ]

# リクエスト情報
     search_items_request = SearchItemsRequest(
         partner_tag=partner_tag,
         partner_type=PartnerType.ASSOCIATES,
         keywords=keywords,
         search_index=search_index,
         item_count=item_count,
         resources=search_items_resource,
         condition="New" # 新品/中古を選ぶ
     )

# APIコール
    response = default_api.search_items(search_items_request)
     if response.search_result is not None:
         print(“検索結果数:",response.search_result.total_result_count)
         for item_0 in response.search_result.items: # 全件出力
             if item_0 is not None:
                 if item_0.asin is not None:
                     print(“ASIN: “, item_0.asin)
                 if item_0.detail_page_url is not None:
                     print(“URL: “, item_0.detail_page_url)
                     print(“画像:", item_0.images.primary.large.url)
                 if (
                     item_0.item_info is not None
                     and item_0.item_info.title is not None
                     and item_0.item_info.title.display_value is not None
                 ):
                     print(“商品名: “, item_0.item_info.title.display_value)
                 if (
                     item_0.offers is not None
                     and item_0.offers.listings is not None
                     and item_0.offers.listings[0].price is not None
                     and item_0.offers.listings[0].price.display_amount is not None
                 ):
                     print(
                         “価格: “, item_0.offers.listings[0].price.display_amount
                     )
     print(“生データ:")
     print(response)

path = 'amazon_response.txt’ # 文字化けするんでSJISにしてます
sys.stdout = open(path, 'w’, encoding=’shift_jis’)

search_items()

コードここまで

SearchItemsRequest/item_countの数だけ結果が戻る仕様なのは、前版と同様です。SearchItemsRequest/ItemPageでページ指定して、再度コールする形になります。

SearchItemsRequest/search_indexには、検索するカテゴリ(ジャンル?)を指定しますが、これは、国別のAmazon毎に仕様が異なります。

日本のジャンルはここですが、もしページが翻訳されていたら、それは間違いで・・w

実際は、英単語になります。上写真、ソースを見てもらえると分かります。これが実際です。

トップで検索したのと同じなら”All”です。

ソートは、SortByで指定。関連・レビュー数やランク、価格順など。

商品へのリンクは、items/detail_page_urlになります。以前は、もっと、長ったらしい感じだったように記憶してますが、随分とすっきりしたようです。

価格は、price.display_amountで通貨表記(¥)も込みで得られますが、実際は、数値で扱えるprice.amountを利用する事になるかと思います。

画像リンクは、様々なサイズ(標準3/変形3)が用意されてますが、それぞれに要求しないといけないようです。

実際のAmazon商品では、新品や中古(マーケットプレイス等)、販売店が複数あったりします。

※Amazon販売だけならSearchItemsRequest/Merchant="Amazon"を指定する

詳しくは、公式ドキュメントを見てくださいね。

そういえば、評価レビューを取得する方法が見当たらないんですが、無くなった?

公式のSearchItemsのドキュメント

追記:browse_nodesが入ってない場合がある

データ見てたら、登録されたカテゴリ情報であるはずの、browse_nodesがNoneの場合があるようです。

Campingという商品で、書籍?アプリ?

配信先Fireとかあるんで、多分、アプリなんでしょう。

(;^ω^)

アプリも検索結果として帰ってくるのは分かったが、ん?アプリには、カテゴリが無い・・とか?

もしくは、販売前の登録中状態のものとか。。

カテゴリがあるものと思ってると、こういう事になるので注意です。

おわり

まだ、search itemsしか触ってませんが、概ねイメージできました。

レスポンスも早く、さすがAmazonという感じです。

あるブログ記事で見たんですが、このPAAPI5に変わった辺りから、Amazonアソシエイトとしてある程度の売上が無いと、APIが利用出来なくなるとの事です。

(;´Д`)えっ

公式の一文:一定以上の売上実績を重ねることでご利用が可能となります。

どんな感じで利用出来なくなるのか分かりませんが、自分は一応、利用可能って事でいいのかな。。

以前は、各大手ショッピング系サイトでは、こぞってAPIを提供してましたが、Yahooは(オークション含め)全て終了、楽天とAmazonはまだ継続してるようです。

※ドロップシッピングとかもありましたね

サーバの維持管理にコストが掛かってるんでしょうね。。

もしくは、アホな程のAPIリクエストを送りまくってる、ユーザーがいるとか。。

さらっと触ってみた簡単な感想記事で御座いましたが、参考になれば幸いで御座います。

資料

追記:jsonレスポンスデータ(サンプル)

※1アイテム分、そのまんま貼り付け、あくまで参考データ(一部加工)

search_items_resourceでの要求により、内容は大きく増減します。海外のAmazonも含め対応してるので、見方に慣れが必要です。

一部、リスト形態ですので注意(販売店とか)、また、SDKサンプルでも丁寧に書かれてますが、枝/項目の有り無しチェックも必須。

{'errors’: None,

'search_result’: {'items’: [{'asin’: 'B000FHUS64’,

'browse_node_info’: {'browse_nodes’: [{'ancestor’: None,

'children’: None,

'context_free_name’: 'レジスターサプライ’,

'display_name’: 'レジスターサプライ’,

'id’: '45793011’,

'is_root’: False,

'sales_rank’: None}],

'website_sales_rank’: None},

'customer_reviews’: None,

'detail_page_url’: 'https://www.amazon.co.jp/リンク先’,

'images’: {'primary’: {'large’: {'height’: 417,

'url’: 'https://m.media-amazon.com/images/I/21SuFccEdTL._SL500_.jpg’,

'width’: 500},

'medium’: None,

'small’: None},

'variants’: None},

'item_info’: {'by_line_info’: {'brand’: {'display_value’: 'CASIO(カシオ)’,

'label’: 'Brand’,

'locale’: 'ja_JP’},

'contributors’: None,

'manufacturer’: {'display_value’: 'CASIO(カシオ)’,

'label’: 'Manufacturer’,

'locale’: 'ja_JP’}},

'classifications’: None,

'content_info’: None,

'content_rating’: None,

'external_ids’: {'ea_ns’: {'display_values’: ['4971850505532’],

'label’: 'EAN’,

'locale’: 'en_US’},

'isb_ns’: None,

'up_cs’: None},

'features’: {'display_values’: ['メーカー型番:TRP-5880X5’,

'カシオのキャッシュレジスター純正交換用ロールペーパー’,

'厚みのある紙、白さ、クッキリ美しい印字など、純正ならではの高品質’,

'小売業にはなくてはならないキャッシュレジスター’,

'5個パックというのは、個人営業者には適切な量’],

'label’: 'Features’,

'locale’: 'ja_JP’},

'manufacture_info’: None,

'product_info’: None,

'technical_info’: None,

'title’: {'display_value’: 'カシオ '

'レジ用ロールペーパー '

'5個入 '

'TRP-5880X5’,

'label’: 'Title’,

'locale’: 'ja_JP’},

'trade_in_info’: None},

'offers’: {'listings’: [{'availability’: None,

'condition’: None,

'delivery_info’: None,

'id’: 'zErxciHi78%,

'is_buy_box_winner’: None,

'loyalty_points’: {'points’: 9},

'merchant_info’: None,

'price’: {'amount’: 891.0,

'currency’: 'JPY’,

'display_amount’: '¥891 '

'(¥891 '

'/ '

'count)’,

'price_per_unit’: 891.0,

'price_type’: None,

'price_type_label’: None,

'savings’: {'amount’: 649.0,

'currency’: 'JPY’,

'display_amount’: '¥649 '

'(42%)’,

'percentage’: 42,

'price_per_unit’: 649.0}},

'program_eligibility’: None,

'promotions’: None,

'saving_basis’: None,

'violates_map’: False}],

'summaries’: None},

'parent_asin’: None,

'rental_offers’: None,

'score’: None,

'variation_attributes’: None},

追記:指定値のメモリスト(SDK)

参考にどうぞ。絞り/フィルター的な感じ。ソート指定で、がらっと内容が変わるので注意(実際のAmazon検索ソート参考)

戻り値を見てみると、言うほど厳密な結果が帰ってこないっぽい。やっぱsortによる感じ。

SearchItemsRequest()の指定値

    'actor’: 'str’,
     'artist’: 'str’,
     'author’: 'str’,
     'availability’: 'Availability’,
     'brand’: 'str’,
     'browse_node_id’: 'str’,
     'condition’: 'Condition’,
     'currency_of_preference’: 'str’,
     'delivery_flags’: 'list[DeliveryFlag]’,
     'item_count’: 'int’,
     'item_page’: 'int’,
     'keywords’: 'str’,
     'languages_of_preference’: 'list[str]’,
     'marketplace’: 'str’,
     'max_price’: 'MaxPrice’,
     'merchant’: 'Merchant’,
     'min_price’: 'MinPrice’,
     'min_reviews_rating’: 'MinReviewsRating’,
     'min_saving_percent’: 'MinSavingPercent’,
     'offer_count’: 'OfferCount’,
     'partner_tag’: 'str’,
     'partner_type’: 'PartnerType’,
     'properties’: 'Properties’,
     'resources’: 'list[SearchItemsResource]’,
     'search_index’: 'str’,
     'sort_by’: 'SortBy’,
     'title’: 'str’

search_items_resource要求リソースタイプの定義リスト

以下から欲しい情報をリクエストします。大量すぎ、必要なものだけに絞りましょう。

カテゴリ情報
BROWSENODEINFO_BROWSENODES = “BrowseNodeInfo.BrowseNodes"
BROWSENODEINFO_BROWSENODES_ANCESTOR = “BrowseNodeInfo.BrowseNodes.Ancestor"
BROWSENODEINFO_BROWSENODES_SALESRANK = “BrowseNodeInfo.BrowseNodes.SalesRank"
※別カテゴリの情報も出ますが、いまいち分からない
BROWSENODEINFO_WEBSITESALESRANK = “BrowseNodeInfo.WebsiteSalesRank"


評価(機能してない?)
CUSTOMERREVIEWS_COUNT = “CustomerReviews.Count"
CUSTOMERREVIEWS_STARRATING = “CustomerReviews.StarRating"

画像(サイズはあてにならない)
IMAGES_PRIMARY_SMALL = “Images.Primary.Small" 約サイズ75
IMAGES_PRIMARY_MEDIUM = “Images.Primary.Medium" 約サイズ160
IMAGES_PRIMARY_LARGE = “Images.Primary.Large" 約サイズ500
IMAGES_VARIANTS_SMALL = “Images.Variants.Small"
IMAGES_VARIANTS_MEDIUM = “Images.Variants.Medium"
IMAGES_VARIANTS_LARGE = “Images.Variants.Large"

メーカー情報
ITEMINFO_BYLINEINFO = “ItemInfo.ByLineInfo"

ITEMINFO_CONTENTINFO = “ItemInfo.ContentInfo"
ITEMINFO_CONTENTRATING = “ItemInfo.ContentRating"
ITEMINFO_CLASSIFICATIONS = “ItemInfo.Classifications"

JAN(日)やEAN(米)のようなコード
ITEMINFO_EXTERNALIDS = “ItemInfo.ExternalIds"

製品特徴
ITEMINFO_FEATURES = “ItemInfo.Features"

ITEMINFO_MANUFACTUREINFO = “ItemInfo.ManufactureInfo"
ITEMINFO_PRODUCTINFO = “ItemInfo.ProductInfo"
ITEMINFO_TECHNICALINFO = “ItemInfo.TechnicalInfo"

商品タイトル
ITEMINFO_TITLE = “ItemInfo.Title"


商品状態・取引
ITEMINFO_TRADEININFO = “ItemInfo.TradeInInfo"
OFFERS_LISTINGS_AVAILABILITY_MAXORDERQUANTITY = “Offers.Listings.Availability.MaxOrderQuantity"
OFFERS_LISTINGS_AVAILABILITY_MESSAGE = “Offers.Listings.Availability.Message"
OFFERS_LISTINGS_AVAILABILITY_MINORDERQUANTITY = “Offers.Listings.Availability.MinOrderQuantity"
OFFERS_LISTINGS_AVAILABILITY_TYPE = “Offers.Listings.Availability.Type"
OFFERS_LISTINGS_CONDITION = “Offers.Listings.Condition"
OFFERS_LISTINGS_CONDITION_CONDITIONNOTE = “Offers.Listings.Condition.ConditionNote"
OFFERS_LISTINGS_CONDITION_SUBCONDITION = “Offers.Listings.Condition.SubCondition"

送料など
OFFERS_LISTINGS_DELIVERYINFO_ISAMAZONFULFILLED = “Offers.Listings.DeliveryInfo.IsAmazonFulfilled"
OFFERS_LISTINGS_DELIVERYINFO_ISFREESHIPPINGELIGIBLE = “Offers.Listings.DeliveryInfo.IsFreeShippingEligible"
OFFERS_LISTINGS_DELIVERYINFO_ISPRIMEELIGIBLE = “Offers.Listings.DeliveryInfo.IsPrimeEligible"
OFFERS_LISTINGS_DELIVERYINFO_SHIPPINGCHARGES = “Offers.Listings.DeliveryInfo.ShippingCharges"
OFFERS_LISTINGS_ISBUYBOXWINNER = “Offers.Listings.IsBuyBoxWinner"

ポイント
OFFERS_LISTINGS_LOYALTYPOINTS_POINTS = “Offers.Listings.LoyaltyPoints.Points"

販売店
OFFERS_LISTINGS_MERCHANTINFO = “Offers.Listings.MerchantInfo"

価格
OFFERS_LISTINGS_PRICE = “Offers.Listings.Price"

OFFERS_LISTINGS_PROGRAMELIGIBILITY_ISPRIMEEXCLUSIVE = “Offers.Listings.ProgramEligibility.IsPrimeExclusive"
OFFERS_LISTINGS_PROGRAMELIGIBILITY_ISPRIMEPANTRY = “Offers.Listings.ProgramEligibility.IsPrimePantry"

プロモーション
OFFERS_LISTINGS_PROMOTIONS = “Offers.Listings.Promotions"
OFFERS_LISTINGS_SAVINGBASIS = “Offers.Listings.SavingBasis"

複数の価格帯
OFFERS_SUMMARIES_HIGHESTPRICE = “Offers.Summaries.HighestPrice"
OFFERS_SUMMARIES_LOWESTPRICE = “Offers.Summaries.LowestPrice"
OFFERS_SUMMARIES_OFFERCOUNT = “Offers.Summaries.OfferCount"


レンタル(海外ではそういうサービスしてる?)
PARENTASIN = “ParentASIN"
RENTALOFFERS_LISTINGS_AVAILABILITY_MAXORDERQUANTITY = “RentalOffers.Listings.Availability.MaxOrderQuantity"
RENTALOFFERS_LISTINGS_AVAILABILITY_MESSAGE = “RentalOffers.Listings.Availability.Message"
RENTALOFFERS_LISTINGS_AVAILABILITY_MINORDERQUANTITY = “RentalOffers.Listings.Availability.MinOrderQuantity"
RENTALOFFERS_LISTINGS_AVAILABILITY_TYPE = “RentalOffers.Listings.Availability.Type"
RENTALOFFERS_LISTINGS_BASEPRICE = “RentalOffers.Listings.BasePrice"
RENTALOFFERS_LISTINGS_CONDITION = “RentalOffers.Listings.Condition"
RENTALOFFERS_LISTINGS_CONDITION_CONDITIONNOTE = “RentalOffers.Listings.Condition.ConditionNote"
RENTALOFFERS_LISTINGS_CONDITION_SUBCONDITION = “RentalOffers.Listings.Condition.SubCondition"
RENTALOFFERS_LISTINGS_DELIVERYINFO_ISAMAZONFULFILLED = “RentalOffers.Listings.DeliveryInfo.IsAmazonFulfilled"
RENTALOFFERS_LISTINGS_DELIVERYINFO_ISFREESHIPPINGELIGIBLE = “RentalOffers.Listings.DeliveryInfo.IsFreeShippingEligible"
RENTALOFFERS_LISTINGS_DELIVERYINFO_ISPRIMEELIGIBLE = “RentalOffers.Listings.DeliveryInfo.IsPrimeEligible"
RENTALOFFERS_LISTINGS_DELIVERYINFO_SHIPPINGCHARGES = “RentalOffers.Listings.DeliveryInfo.ShippingCharges"
RENTALOFFERS_LISTINGS_MERCHANTINFO = “RentalOffers.Listings.MerchantInfo"
SEARCHREFINEMENTS = “SearchRefinements"

*おわり

2023年3月20日プライベート

Posted by nabe