11月にアマゾンからアソシエイトツールバーで作成した「画像リンク」、「テキストと画像リンク」が廃止されるとのメールを受け、とりあえずスクラッチパッドでASINを入れてHTMLを取得する方法を試してみました。
しかしさすがにこれまで作成したリンク一つ一つからASINを抜き出しスクラッチパッドに入れるのは骨がおれるため、PythonのSDKを使い既存のリンクからASINを抜き出し、PA-APIから画像とURLを取得してHTMLを吐き出すまでのスクリプトを書いてみました。
PA-API(商品情報API)とは
PA-API(商品情報API)とは、アマゾンに掲載されている商品の名称、URL、画像、価格など様々な情報を取得できるAPIです。使用するには認証キーの取得が必要なこと、アマゾンアソシエイトで一定の売上をあげている必要があります。認証キーの取得、スクラッチパッドの基本的な使い方は前回の記事をご参考ください。
アマゾンアソシエイト アソシエイトツールバー画像リンク作成機能の廃止
11月30日に、突然アマゾンから「【重要】アソシエイトツールバー画像リンク作成機能 廃止のご連絡 ...
動作環境とPythonのライブラリ
Linux(Ubuntu)にPython3.11.6です。WindowsでもMacOSでもおそらくそのままかほぼそのまま動作するのではと思います。
HTMLの解析のためにBeautifulSoupを使っているため、BeautifulSoupが必要です。その他はPA-APIのSDKと標準ライブラリのみ使っています。
$ pip install beautifulsoup4
SDKのダウンロード
PA-API開発者ガイドのページからダウンロードします。PHP、Java、Node.js、PythonのSDKが公開されています。今回はPyhonのSDKをダウンロードしました。SDKにはサンプルコードも含まれています。
以下、APIのバージョンは2024年1月4日時点の5.0を前提に解説していきます。
必要な情報
認証キー(アクセスキー、シークレットキー)、アソシエイトIDが必要です。また、ASINをもとに商品情報を取得しますが、これは以前にアソシエイトツールバーで作成したHTMLタグをクリップボードにコピーして、クリップボードからASINを読み取るようにします。
サンプルコードを確認
ダウンロードしたpaapi5-python-sdk-example.zip
を解凍してみます。__MACOSX
と、paapi5-python-sdk-example
という2つのディレクトリができました。Linuxなので__MACOSX
は無視するとして、paapi5-python-sdk-example
の中にはいろいろ入っていますが、今回直接使うのは、sample_get_items_api.py
です。
.
├── __MACOSX
│ └── paapi5-python-sdk-example
├── paapi5-python-sdk-example
│ ├── COPYING.txt
│ ├── LICENSE.txt
│ ├── NOTICE.txt
│ ├── README.md
│ ├── paapi5_python_sdk/
│ ├── requirements.txt
│ ├── sample_get_browse_nodes_api.py
│ ├── sample_get_items_api.py ←これを使う
│ ├── sample_get_variations_api.py
│ ├── sample_request_with_conn_pool_settings.py
│ ├── sample_search_items_api.py
│ ├── setup.cfg
│ ├── setup.py
│ ├── test/
│ ├── test-requirements.txt
│ └── tox.ini
└── paapi5-python-sdk-example.zip
sample_get_items_api.py
の中のget_items()
関数を使えば商品情報を取得できそうです。サンプルコードは、少し修正しました。
def get_items(akey, skey, ptag, asin): #① 引数追加。オリジナルは引数なし get_items()
""" Following are your credentials """
""" Please add your access key here """
= akey #①
access_key
""" Please add your secret key here """
= skey #①
secret_key
""" Please add your partner tag (store/tracking id) here """
= ptag #①
partner_tag
""" PAAPI host and region to which you want to send request """
""" For more details refer: https://webservices.amazon.com/paapi5/documentation/common-request-parameters.html#host-and-region"""
= "webservices.amazon.co.jp" #② webservices.amazon.comから日本(co.jp)に変更
host = "us-wast-2" #③us-east-1から変更
region
""" API declaration """
= DefaultApi(
default_api =access_key, secret_key=secret_key, host=host, region=region
access_key
)
""" Request initialization"""
""" Choose item id(s) """
= [asin] #①
item_ids
######## 省略 ########
""" Forming request """
try:
= GetItemsRequest(
get_items_request =partner_tag,
partner_tag=PartnerType.ASSOCIATES,
partner_type="www.amazon.co.jp", #② webservices.amazon.comから日本(co.jp)に変更
marketplace=Condition.NEW,
condition=item_ids,
item_ids=get_items_resource,
resources
)
######## 省略 ########
return response.items_result except Exception as exception:
print("Exception :", exception, file=sys.stderr)
# ~~~~~~~~~~~~~~~ ④printが多くうるさいのでstderrに出力
return response.items_result # ⑤戻り値を追加
######## ファイル最後の関数呼び出しはコメントアウト ########
# get_items()
# get_items_with_http_info()
# get_items_async()
- 関数の中にアクセスキーなどの認証情報を直接書き込むようになっているため、引数で渡すように変更しました。
- 問い合わせ先がアメリカのアマゾン(amazon.com)になっていたのでamazon.co.jpに変更。
- reagionも変更必要です。日本はなぜかus-wast-2になるようです。
- 途中、printで標準出力に色々書き出すようになっていましたが、最終的に整形したHTMLのみ出力したいので力技ですが、すべてのprint文に標準エラー出力に書き出すように変更。(sysモジュールのインポート必要です)
- 取得した情報は
response.items_result
に入っていそうです。別の関数から戻り値を使いたいのでreturn
文を最後に追加しました。
既存のリンクをクリップボードから読み、HTMLを出力するスクリプト
既存のリンクは、iframe
タグのsrc
属性の中にasins=**********
という形でASINが埋め込まれています。
<iframe frameborder="0" height="240" marginheight="0" marginwidth="0" sandbox="allow-popups allow-scripts allow-modals allow-forms allow-same-origin" scrolling="no"
src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=アソシエイトID&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B005RFSIUW&linkId=f741756446a26bffc9ce95581b04542f" style="width:120px;height:240px;" title="アマゾン 絶縁ナットドライバー" width="120"></iframe>
標準入力からiframe
タグを読み込み、ASINを取り出し、先程のget_items
で商品情報を取得、商品情報、URL、画像のURLをHTMLテンプレートに流し込み標準出力に出す感じです。iframe
タグを複数続けて設置していることもあるため、複数タグを選択しても動くようにしました。
iframe
タグ無しでも、ASINを指定して同じHTMLを出せるようにコマンドラインオプション無しだと標準入力から読み込み、-a --asin
オプションでASINを指定するオプションも付けました。
import get_items_api as paap
from bs4 import BeautifulSoup
import re
import json
import sys
import argparse
### Amazon associates credidentials
= "アクセスキー"
access_key = "シークレットキー"
secret_key = "アソシエイトID"
partner_tag
### 雛形
# {0} アソシエイトID
# {1} URL
# {2} タイトル
# {3} イメージURL
= """\
template <div class="paapi5-pa-ad-unit"><div class="paapi5-pa-product-container"><div class="paapi5-pa-product-image"><div class="paapi5-pa-product-image-wrapper"><a class="paapi5-pa-product-image-link" href="{1}" title="{2}" target="_blank"><img class="paapi5-pa-product-image-source" src="{3}" alt="{2}" width={4} height={5}></a></div></div><div class="paapi5-pa-product-details"><div class="paapi5-pa-product-title"><a class="paap5-pa-product-title-link" href="{1}" title="{2}" target="_blank">{2}</a></div><div class="paapi5-pa-product-list-price"><span class="paapi5-pa-product-list-price-value"></span></div><div class="paapi5-pa-product-prime-icon"><span class="icon-prime-all"></span><a class="paap5-pa-product-title-link" href="{1}" title="{2}" target="_blank"><span class="buy-on-amazon">Amazonで買う</span></a></div></div></div></div>\
"""
### 認証情報とASINを受取り、HTMLを返す関数
def create_html(access_key, secret_key, partner_tag, asin, template):
= paap.get_items(access_key, secret_key, partner_tag, asin)
response = response.items[0].detail_page_url
url = response.items[0].item_info.title.display_value
title = response.items[0].images.primary.medium
img print(template.format(partner_tag, url, title, img.url, img.width, img.height))
### コマンドラインオプション
= argparse.ArgumentParser()
parser "-a", "--asin", help="与えられたASINに対するHTMLを返す", action="store")
parser.add_argument(= parser.parse_args()
args if args.asin:
= args.asin
asin print("found asin: {0}".format(asin), file=sys.stderr)
create_html(access_key, secret_key, partner_tag, asin, template)else:
= BeautifulSoup(sys.stdin.read(), "lxml")
soup = soup.find_all("iframe", src=re.compile("asin"))
asin_tags for asin_tag in asin_tags:
= re.search(r"asins=(\w+)", str(asin_tag["src"]))
m = m.group(1)
asin print("found asin: {0}".format(asin), file=sys.stderr)
create_html(access_key, secret_key, partner_tag, asin, template)
プログラマーでは無いので拙いコードですが、とりあえず即席でなんとか動かすことができました。書いてみてBeautifulSoupを使うほどでもなく、単なる文字列置換でよかった気もします。また、sample_get_items_api.py
の中のget_items()
関数は途中でいろいろprint
するのでこのあたりは削除して書き直したほうがよかったかもしれません。
使い方
既存のテキストと画像タグの置き換え
iframe
タグ全体を(あっても可)選択し、クリップボードにコピーします。
xsel
でクリップボードの内容をパイプでこのスクリプトに渡します。標準エラー出力は表示しないようにして、端末の標準出力に出てきたHTMLタグをコピーしてブログに貼り付ける使い方です。
$ xsel -bo | python3 create_link.py 2>/dev/null
ASINからHTMLタグを生成
$ python3 create_link.py -a ASIN番号 2>/dev/null
出力されたHTML
スクラッチパッドのHTMLを参考にしました。やたらとdiv
タグにラップされていていちいち長いクラス名が付いていてもっとスッキリさせたいですが、同じくスクラッチパッドで出力されたCSSもほぼそのままで使いたいので、面倒なのでスクラッチパッドとほぼ同じにしています。
<div class="paapi5-pa-ad-unit"><div class="paapi5-pa-product-container"><div class="paapi5-pa-product-image"><div class="paapi5-pa-product-image-wrapper"><a class="paapi5-pa-product-image-link" href="https://www.amazon.co.jp/dp/B005RFSIUW?tag=アソシエイトID&linkCode=ogi&th=1&psc=1" title="クニペックス KNIPEX 9803-10 絶縁ナットドライバー 1000V" target="_blank"><img class="paapi5-pa-product-image-source" src="https://m.media-amazon.com/images/I/31QfMSIO87L._SL160_.jpg" alt="クニペックス KNIPEX 9803-10 絶縁ナットドライバー 1000V" width=160 height=160></a></div></div><div class="paapi5-pa-product-details"><div class="paapi5-pa-product-title"><a class="paap5-pa-product-title-link" href="https://www.amazon.co.jp/dp/B005RFSIUW?tag=アソシエイトID&linkCode=ogi&th=1&psc=1" title="クニペックス KNIPEX 9803-10 絶縁ナットドライバー 1000V" target="_blank">クニペックス KNIPEX 9803-10 絶縁ナットドライバー 1000V</a></div><div class="paapi5-pa-product-list-price"><span class="paapi5-pa-product-list-price-value"></span></div><div class="paapi5-pa-product-prime-icon"><span class="icon-prime-all"></span><a class="paap5-pa-product-title-link" href="https://www.amazon.co.jp/dp/B005RFSIUW?tag=アソシエイトID&linkCode=ogi&th=1&psc=1" title="クニペックス KNIPEX 9803-10 絶縁ナットドライバー 1000V" target="_blank"><span class="buy-on-amazon">Amazonで買う</span></a></div></div></div></div>
CSSもスクラッチパッドほぼそのままです。
.paapi5-pa-ad-unit {
width: 232px;
height: auto;
border: 1px solid #eee;
margin:2px;
position: relative;
overflow: hidden;
padding: 22px 20px;
line-height: 1.1em;
margin: auto;
}.paapi5-pa-ad-unit * {
box-sizing: content-box;
box-shadow: none;
font-family: Arial, Helvetica, sans-serif;
margin: 0;
outline: 0;
padding: 0;
}.paapi5-pa-ad-unit a {
box-shadow: none !important;
}.paapi5-pa-ad-unit a:hover {
color: #c45500;
}.paapi5-pa-product-container {
width: 180px;
height: 210px;
}/* fixed width and height of product image to 150px */
.paapi5-pa-product-image {
display: table;
width: 150px;
height: 150px;
margin: 0 auto;
text-align: center;
}.paapi5-pa-product-image-wrapper {
display: table-cell;
vertical-align: middle;
}.paapi5-pa-product-image-link {
position: relative;
display: inline-block;
vertical-align: middle;
}.paapi5-pa-product-image-source {
max-width: 150px;
max-height: 150px;
vertical-align: bottom;
}.paapi5-pa-percent-off {
display: block;
width: 32px;
height: 25px;
padding-top: 8px;
position: absolute;
top: -16px;
right: -16px;
color: #ffffff;
font-size: 12px;
text-align: center;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
50%;
-ms-border-radius: border-radius: 50%;
background-color: #a50200;
background-image: -webkit-linear-gradient(top, #cb0400, #a50200);
background-image: linear-gradient(to bottom, #cb0400, #a50200);
}.paapi5-pa-ad-unit.hide-percent-off-badge .paapi5-pa-percent-off {
display: none;
}.paapi5-pa-product-details {
display: inline-block;
max-width: 100%;
margin-top: 11px;
text-align: center;
width: 100%;
}.paapi5-pa-ad-unit .paapi5-pa-product-title a {
display: block;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 13px;
color: #0066c0;
text-decoration: none;
margin-bottom: 3px;
}.paapi5-pa-ad-unit .paapi5-pa-product-title a:hover {
text-decoration: underline;
color: #c45500;
}.paapi5-pa-ad-unit.no-truncate .paapi5-pa-product-title a {
text-overflow: initial;
white-space: initial;
}.paapi5-pa-product-offer-price {
font-size: 13px;
color: #111111;
}.paapi5-pa-product-offer-price-value {
color: #AB1700;
font-weight: bold;
font-size: 1.1em;
margin-right: 3px;
}.paapi5-pa-product-list-price {
font-size: 13px;
color: #565656;
}.paapi5-pa-product-list-price-value {
text-decoration: line-through;
font-size: 0.99em;
}.paapi5-pa-product-prime-icon .icon-prime-all {
background: url("https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x_weblab_AUI_100106_T1-4e9f4ae74b1b576e5f55de370aae7aedaedf390d._V2_.png") no-repeat;
display: inline-block;
margin-top: -1px;
vertical-align: middle;
background-position: -192px -911px;
background-size: 560px 938px;
width: 52px;
height: 15px;
}.paapi5-pa-product-offer-price,
.paapi5-pa-product-list-price,
.paapi5-pa-product-prime-icon {
display: inline-block;
margin-right: 3px;
}@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
.paapi5-pa-ad-unit .paapi5-pa-product-prime-icon .icon-prime-all {
background: url("https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x_weblab_AUI_100106_T1-4e9f4ae74b1b576e5f55de370aae7aedaedf390d._V2_.png") no-repeat;
display: inline-block;
margin-top: -1px;
vertical-align: middle;
background-position: -192px -911px;
background-size: 560px 938px;
width: 52px;
height: 15px;
}
}/* css for mobile devices when device width is less than 441px*/
@media screen and (max-width: 440px) {
.paapi5-pa-ad-unit {
float: none;
width: 100%;
}.paapi5-pa-product-container {
margin: 0 auto;
width: 100%;
}.paapi5-pa-product-details {
text-align: center;
margin-top: 11px;
}
}.paapi5-pa-product-prime-icon .buy-on-amazon {
border-radius: 5px;
background: #232F3E;
color: white;
font-size: 13px;
border: none;
padding: 3px;
font-weight: bold;
}
作成したリンク
こんな感じです。
Bloggerでは手動埋め込みしかできなさそう
さて、ここまでできたらレンタルサーバーを使っている場合などはアクセスの度にPA-APIを使いリンクを生成すればよいのですが、Bloggerでは無理なので上のリンクをコピペ手動で貼り付け、結局力技で更新していきました。
アマゾンアソシエイトPA-APIの規約を読むと、結果をキャッシュする場合、24時間以内にAPIから情報を更新すること、価格情報は1時間以内に更新すること、と書かれているためこれを永久的に貼り付けておくのは微妙です。
特に価格情報は頻繁に変わるので作成したリンクには載せないようにしました。商品へのURLは、アソシエイトツールバーのテキストリンクと同じものが帰ってきてるようで、アソシエイトツールバーのテキストリンクはコピペで更新しなくても良いため問題無いのでは、と思っています。
画像は微妙ですが、リンク先のURLを見ると頻繁に更新されるようなものでは無さそうなので画像も入れて様子見してみます。
Javascriptのfetchでクライアント側から取得すればよいのでは!?と思いやってみましたが、同一オリジンポリシーとかいうのがあってダメみたいです。
まとめ
SDKを使うことで動かなくなったアマゾンアソシエイトツールバーで作成した「テキストと画像リンク」をPA-APIで取得したリンクに変換することができました。
Bloggerでは、結局1個1個手動でタグを置き換える必要がありますが、SDKを使ったスクリプトを書くことで作業自体はだいぶ楽になりました。
2024/1/20追記:Netlify functions (FaaS) を使い、動的に商品情報を取得する方法にも挑戦してみました。詳細は、下の関連記事を参照ください。
関連記事
アマゾンPA-API FaaSを使いリアルタイムで商品情報を取得
アマゾンアソシエイトの画像リンクが廃止になり、API経由で商品画像、価格などの情報を取得必要にな ...
アマゾンアソシエイト アソシエイトツールバー画像リンク作成機能の廃止
11月30日に、突然アマゾンから「【重要】アソシエイトツールバー画像リンク作成機能 廃止のご連絡 ...
Blogger: モバイルで画像の解像度が低いときの対処法
このブログはGoogleのブログサービス、Bloggerを使っています。無料で広告が出ず、アドセンス ...
Googleアドセンス 3回目の振り込みと買ったもの
ブログを始めてから3回目のアドセンスの振り込みがありました。振り込みまでの期間と収益、そして買ったも ...
GPSトラックログを編集するフリーソフト QMapShack
サイクリングや登山に行った際、GPSサイコンやスマホアプリを使ってGPSログを残しています。後か ...
0 件のコメント:
コメントを投稿