Amazon 価格監視ツール設計書(PA-API + GitHub Actions + CSV)
1. ゴール / 概要
- 対象:Amazon.co.jp の特定商品
- 手段:Amazon Product Advertising API(PA-API)を定期的に叩き、価格を取得
- ストレージ:すべて CSV(Excel で編集可能な前提)
- 処理フロー:
- プロダクト一覧 CSV から「監視対象商品(ASIN + ターゲット価格)」を読み込む
- 各商品の現在価格を PA-API で取得
- 商品ごとの履歴 CSV に追記
- 現在価格がターゲット価格以下になった商品について通知を送信(メール等)
- 一覧から商品を削除した場合、その商品は以降監視されないが、履歴 CSV は残る
2. 商品コード(ASIN)について
- Amazon には、ASIN (Amazon Standard Identification Number) という商品IDがあり、
- 同一マーケットプレイス(今回は Amazon.co.jp)内では、ASIN は一意(ユニーク)。
- 本システムでは、この ASIN を「商品コード」かつ主キー として扱う。
- ユーザー操作:
- 商品ページ URL から ASIN を抽出して「products.csv」に入力するか、
- 生成AI側の実装で「URL → ASIN 抽出」を行っても良い(仕様としては ASIN を持っていればOK)。
3. 全体アーキテクチャ
3.1 コンポーネント構成
- CSV ストレージ
data/products.csv… 監視対象の商品一覧(Excel で編集)data/history/{ASIN}.csv… 各商品の価格履歴ログ- 価格取得スクリプト(Python)
src/fetch_prices.py- やること:products.csv を読み込み → PA-API で価格取得 → history CSV に追記 → 通知判定
- 通知スクリプト(Python)
src/notify.py- やること:fetch_prices.py から渡された「通知対象商品一覧」を元に、メール or Webhook を送信
- GitHub Actions
.github/workflows/price_watcher.yml- スケジュール実行(例:1日1回)+手動実行(dispatch)の両方
3.2 想定テクノロジースタック
- 言語:Python 3.10+
- 依存ライブラリ例:
requests(PA-API 呼び出し)python-amazon-paapi等の PA-API クライアント(採用は実装側判断で可)pandas(CSV 操作を楽にするため、任意)- 通知手段:
- まずは メール送信 を前提
* 例:SMTP(Gmail 等) or SendGrid API など
- 実装側で抽象化しやすいよう、インターフェイスのみ仕様で定義
4. ディレクトリ構成(例)
project-root/
README.md
data/
products.csv
history/
# 例)B0CN28DNQH.csv など ASIN ごとのファイル
src/
fetch_prices.py
notify.py
paapi_client.py # PA-API 呼び出しラッパ
config.py
.github/
workflows/
price_watcher.yml
requirements.txt
5. CSV 仕様(データモデル)
5.1 data/products.csv(監視対象リスト)
- 役割:監視対象の商品と、ターゲット価格などのメタ情報を保持する。
- フォーマット:UTF-8 / カンマ区切り
- 1 行目はヘッダー行。
カラム定義
| カラム名 | 必須 | 型 | 説明 |
|---|---|---|---|
asin | Yes | string | Amazon ASIN(商品コード、ユニーク)例: B0CN28DNQH |
name | Yes | string | 商品名(任意のわかりやすい名前) |
url | Yes | string | 商品ページの URL(Amazon.co.jp) |
target_price | Yes | number | 通知を発火させる「ターゲット価格」(税込、JPY を想定) |
active | No | boolean | 監視対象フラグ。true または false。未指定なら true 扱い。 |
notes | No | string | メモ/備考 |
挙動仕様
- ユーザーが Excel でこの CSV を編集する想定。
- 新規商品を追跡したい場合:
- 新しい行を追加(ASIN、name、url、target_price を入力)。
- この時点で次回の定期実行から監視対象となる。
- 監視をやめたい場合:
- 行を削除する、または
active=falseにする。 - 履歴 CSV (
history/{ASIN}.csv) は残るが、以降更新されない。
5.2 data/history/{ASIN}.csv(商品別価格履歴)
- 役割:各 ASIN の価格履歴を保存。
- ファイル名:
data/history/<ASIN>.csv - 例:
data/history/B0CN28DNQH.csv - 1 商品につき 1 ファイル(Excel で言う「商品ごとのシート」に相当)。
カラム定義
| カラム名 | 必須 | 型 | 説明 |
|---|---|---|---|
timestamp | Yes | string | ISO8601 日時(例: 2025-12-06T00:00:00+09:00) |
date | Yes | string | 日付のみ(例: 2025-12-06)。集計用に冗長保持。 |
asin | Yes | string | 対象商品の ASIN |
price | Yes | number | 取得した販売価格(JPY) |
currency | Yes | string | 通貨コード。JPY 固定想定。 |
source | No | string | 価格のソース(AmazonOffer / LowestNewPrice など)。 |
raw_json | No | string | PA-API のレスポンスのうち、必要な部分を JSON 文字列として保存(任意)。 |
追記ルール
fetch_prices.py実行ごとに、商品の数 × 1 行 を追加。- 行追加は「末尾」へ追記。
- ファイルが存在しない場合:
- 新規作成し、ヘッダー行 + データ 1 行を出力。
- ファイルが存在する場合:
- 最終行の
dateが同一日でも、そのまま追記(デイリー 1 回実行想定だが、複数回でも時系列ログとして許容)。
6. 処理フロー詳細
6.1 fetch_prices.py のロジック
data/products.csvを読み込み
active != falseの行のみを対象とする。- 各行から
asin,name,url,target_priceを取り出す。
- 各 ASIN について PA-API を呼び出し、「現在価格」を取得
paapi_client.get_current_price(asin)のような抽象関数でラップする。- 戻り値例:
{
"asin": "B0CN28DNQH",
"price": 19800,
"currency": "JPY",
"source": "AmazonOffer"
}
```
3. 履歴 CSV (`data/history/<ASIN>.csv`) に追記
timestampは現在日時(タイムゾーン +09:00)。dateはYYYY-MM-DD。
- 通知判定
target_priceが数値として有効な場合、以下を行う:
* 最新の価格 `current_price` と比較し、
`current_price <= target_price` のとき「通知候補」に追加。
- 同じ条件で何度も通知しない工夫(推奨仕様):
* 当該 ASIN の履歴ファイルを読み込み、
* 「直前の価格 > target_price」かつ「今回の価格 <= target_price」のときだけ通知する。
* つまり、「ターゲットを初めて割り込んだタイミング」でのみ通知。
5. 通知候補一覧を notify.py に渡す
- 形式例(Python の dict list):
to_notify = [
{
"asin": "B0CN28DNQH",
"name": "BARWING エアロバイク",
"url": "https://www.amazon.co.jp/...",
"target_price": 18000,
"current_price": 17500,
"timestamp": "2025-12-06T00:00:00+09:00"
},
...
]
```
---
## 6.2 notify.py のロジック(Resend でメール送信)
### 6.2.1 前提
- メール送信は Resend の公式 API を利用する。
- Python からは HTTP(S) で
https://api.resend.com/emailsに POST する。 - 認証は
Authorization: Bearer <RESEND_API_KEY>ヘッダで行う。
6.2.2 環境変数
notify.py は以下の環境変数を参照する。
RESEND_API_KEYResend のダッシュボードで発行した API キー。MAIL_FROM送信元メールアドレス(例:"alerts@example.com")。 Resend 側で認証済みのドメイン/アドレスを利用すること。MAIL_TO送信先メールアドレス。カンマ区切りで複数指定可(例:"user1@example.com,user2@example.com")。
6.2.3 入力(to_notify)
fetch_prices.py から以下形式のリストを受け取る:
to_notify = [
{
"asin": "B0CN28DNQH",
"name": "BARWING エアロバイク",
"url": "https://www.amazon.co.jp/...",
"target_price": 18000,
"current_price": 17500,
"timestamp": "2025-12-06T00:00:00+09:00"
},
# ...
]
6.2.4 処理フロー
to_notifyが空 (len == 0) の場合は何もせず終了。MAIL_FROM,MAIL_TO,RESEND_API_KEYがすべて設定されているか検証。足りなければログ出力して終了(エラー終了でもよい)。MAIL_TOをカンマ区切りで分割し、受信者リストを作成。
6.2.5 Resend へのリクエスト仕様
- エンドポイント:
POST https://api.resend.com/emails - ヘッダ:
Authorization: Bearer <RESEND_API_KEY>Content-Type: application/json- ボディ例(単純なテキストメール):
{
"from": "Your Name <alerts@example.com>",
"to": ["user1@example.com", "user2@example.com"],
"subject": "Amazon価格アラート: 3件の商品がターゲット価格を下回りました",
"text": "本文(プレーンテキスト)"
}
6.2.6 メール本文のフォーマット(text)
本文はプレーンテキストでよい。例:
以下の商品がターゲット価格を下回りました。
1) BARWING エアロバイク
ASIN: B0CN28DNQH
現在価格: 17,500 円
ターゲット価格: 18,000 円
時刻: 2025-12-06T00:00:00+09:00
URL: https://www.amazon.co.jp/...
2) ...
生成ルール:
- 先頭に簡単な説明文。
- 各商品を番号付きで列挙。
- 含める項目:
nameasincurrent_pricetarget_pricetimestampurl
6.2.7 エラーハンドリング
- Resend API が 2xx 以外を返した場合:
- ステータスコードとレスポンスボディをログ出力。
- 必要に応じて例外を投げて GitHub Actions を
failedにしてもよい(運用ポリシー次第)。 - ネットワークエラーなど:
- リトライはとりあえずなし(シンプルに失敗としてログ出力)。
- 将来的に
tenacity等のリトライライブラリで拡張可能な構成にしておく。
7. 環境変数 / シークレット定義(Resend 版)
GitHub Secrets(あるいは Actions Variables)に少なくとも以下を設定する:
7.1 Resend 関連
RESEND_API_KEYResend の API キー。
7.2 メール送信設定
MAIL_FROMResend で利用可能な送信元アドレス(例:alerts@yourdomain.com)。MAIL_TO通知を受け取りたい自分のメールアドレス(複数可)。
7.3 PA-API 関連(前仕様と同じ)
AMAZON_PAAPI_ACCESS_KEYAMAZON_PAAPI_SECRET_KEYAMAZON_PAAPI_ASSOCIATE_TAGAMAZON_PAAPI_REGION
8. GitHub Actions 側での設定補足
.github/workflows/price_watcher.yml 内で、env または with 経由で Python に渡す想定:
env:
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
MAIL_FROM: ${{ secrets.MAIL_FROM }}
MAIL_TO: ${{ secrets.MAIL_TO }}
AMAZON_PAAPI_ACCESS_KEY: ${{ secrets.AMAZON_PAAPI_ACCESS_KEY }}
AMAZON_PAAPI_SECRET_KEY: ${{ secrets.AMAZON_PAAPI_SECRET_KEY }}
AMAZON_PAAPI_ASSOCIATE_TAG: ${{ secrets.AMAZON_PAAPI_ASSOCIATE_TAG }}
AMAZON_PAAPI_REGION: "us-east-1" # 例
あとは実装側で:
fetch_prices.py→ 通知対象をnotify.pyに渡すnotify.py→ 上記 Resend API 仕様でメール送信
という流れにすれば、Resend 前提の構成になります。
9. エラーハンドリング / 考慮事項
- PA-API のレスポンスがエラーの場合:
- 該当 ASIN についてはログにエラーを残し、他の商品処理は続行。
- 失敗した商品についてはその回の履歴追記・通知は行わない。
- レートリミット:
- 商品数が増えた場合にレートリミットにかからないよう、ASIN 数 × 実行頻度を調整する。
- CSV の競合:
- 本システムでは、GitHub Actions 実行ごとに commit/push は行わない前提でもよいが、
- 履歴を GitHub 上に残したい場合は、最後に
git commit && git pushするワークフローも別途検討可能(ただしコンフリクト対策が必要)。 - 通貨・税:
- 本仕様では Amazon.co.jp / JPY / 税込を前提とし、PA-API から取得する価格をそのまま
priceとして保存する。
10. 拡張案(将来的なオプション)
- Slack / Discord / LINE Notify など、メール以外の通知チャネル追加
products.csvに以下の項目を追加して柔軟性アップupper_limit_price(高すぎる場合のアラート)category(家電、トレーニング用品など)last_notified_at(通知制御を CSV 側で行う)- 価格だけでなく、在庫状況・ポイント付与率なども取得して履歴に保存(PA-API で取得できる範囲に依存)
以上です。
この仕様をそのまま「プロジェクトの要求仕様」として生成AIに渡せば、
products.csv/history/*.csvの読み書き- PA-API のラッパ
- 通知ロジック
- GitHub Actions の YAML
まで一通り実装可能なレベルになっているはずです。