仕入元サイト × Amazonの価格差を見つけるシステムの仕組み・用語集 (= ユーザー向け説明書)
最終更新: 2026-05-23
古本Arbitrage (= 価格差仕入販売) を自動化するシステム です。
| 役割 | 説明 |
|---|---|
| ① 仕入元サイトを巡回 | 各サイトの在庫を毎日チェック (= 「スクレイパー」) |
| ② 価格情報をDBに蓄積 | 商品マスタ + 在庫情報を PostgreSQL に保存 |
| ③ Amazon価格を取得 | Keepa API で各商品の Amazon価格を取得 |
| ④ 利益の出る商品を抽出 | 仕入価格 vs Amazon売価 で利益計算 |
| ⑤ ポータルに表示 | /books 画面で仕入候補を一覧表示 |
| 段階 | やること | 担当 |
|---|---|---|
| Phase 1 | 仕入元サイトの一覧を巡回 → 商品情報を取得 | 各サイトの scraper |
| Phase 2 | 各商品の詳細ページから ISBN (= 本のID) を補完 | 各サイトの scraper |
| Phase 3 | ISBN → ASIN (= AmazonのID) を紐付け | auto_pipeline.sh |
| Keepa取得 | ASINに対応する Amazon情報を Keepa API から取得 | continuous_bulk 等 |
| MV更新 | 集計テーブル book_summary_mv を 30分ごと再構築 | auto_pipeline.sh |
| portal表示 | ユーザーが /books で利益商品を一覧 | Next.js (= web画面) |
Amazonに登録されている商品のマスター情報。 約 190万件 (= 紙の本中心)。
| カラム名 | 意味 |
|---|---|
asin | Amazonの商品ID (= 10文字英数字) |
isbn_13 | 本の国際番号 (= 13桁) |
title | 商品タイトル |
amazon_price_jpy | Amazon最安購入価格 (= 新品/中古/BuyBoxの最安) |
amazon_new_price_jpy | 新品最安 |
amazon_used_price_jpy | 中古最安 |
amazon_buybox_price_jpy | Buy Box価格 (= 客が実際に買う価格) |
amazon_sales_rank | 売れ筋ランキング (= 数字が小さいほど売れる) |
amazon_offer_count | 出品者の数 |
has_amazon_or_fba_offer_24h | 24時間以内に Amazon直販/FBA出品があるか |
offers_last_fetched_at | Keepa /offers API で最後に取得した日時 |
keepa_last_fetched_at | Keepa /product API で最後に取得した日時 |
各サイトで見つかった商品の在庫情報。 約 1,500万件。
| カラム名 | 意味 |
|---|---|
platform | 仕入元 (= bookoff / rakuten / mottainai / 等) |
isbn | 本の国際番号 (= 13桁、 Phase 2で補完) |
asin | AmazonのID (= Phase 3で紐付け) |
price_jpy | 仕入元での販売価格 |
in_stock | 在庫あり / なし |
fetched_at | スクレイピングした日時 |
url | 商品ページURL |
portal表示を高速化するための事前集計テーブル (= Materialized View)。 30分ごとに再構築。 約 46万行。
| カラム名 | 意味 |
|---|---|
asin | AmazonのID |
platform | 仕入元プラットフォーム |
min_active_price_jpy | そのASIN×platformの最安在庫価格 |
active_count | 在庫アクティブな件数 |
fetched_at | 最新取得日時 |
| スクリプト | 役割 | 頻度 |
|---|---|---|
bookoff scraper | ブックオフ巡回 | 毎日 |
mottainai scraper | もったいない巡回 | 毎日 |
rakuten scraper | 楽天市場・楽天ブックス巡回 | 毎日 |
valuebooks scraper | バリューブックス巡回 | 毎日 |
netoff scraper | ネットオフ巡回 | 毎日 |
kinokuniya scraper | 紀伊國屋巡回 | 毎日 |
abebooks / thriftbooks | 海外サイト巡回 | 毎日 |
| スクリプト | 役割 | 頻度 |
|---|---|---|
keepa_reverse_lookup_incremental.py | 新規ASIN登録 (= ISBN→ASIN紐付け + 基本情報取得) | 常時 |
continuous_bulk ★主役 | 30日経過したASINの Amazon情報を再取得 | 常時稼働 |
keepa_offers_refresh_oos.py | 在庫切れASINの詳細チェック | 毎日 |
keepa_amazon_price_refresh.py | 異常値の補正 | 必要時 |
| スクリプト | 役割 | 頻度 |
|---|---|---|
auto_pipeline.sh | Phase 3 (= ISBN→ASIN紐付け) + MV更新 | 10分ごと |
| 各サイトの Phase 2 | 商品詳細ページからISBN抽出 | scraper後 |
Amazon商品の価格履歴・在庫状況・出品者情報を提供する第三者APIサービス。 月額制で tokens (= API呼び出し回数の上限) を購入する。
| プラン | 月額 | tpm (= tokens/分) | 契約日 |
|---|---|---|---|
| Keepa 60 tpm | €129 (= 約2万円) | 60 | 2026-05-16 |
| Keepa 250 tpm | €459 (= 約7万円) | 250 | 2026-05-17 |
| Keepa 2000 tpm | €2,499 (= 約40万円) | 2,000 | 2026-05-19 |
| 合計 | €3,087 (= 約50万円) | 2,310 tpm | - |
250 tpm + 2000 tpm を解約。 60 tpm 単独 (€129/月) に縮小。| 期間 | 契約 | サイクル | 用途 |
|---|---|---|---|
| 5/23-5/31 (今月) | 2,310 tpm | 2.6日で完走 | 初回フルロード (= 170万件全部取得) |
| 6/1以降 (来月以降) | 60 tpm | 60日サイクル | 常にデータベース更新 (= 2ヶ月で全件1周) |
4320006232 (= 麦とTwitter)。 本の場合は ISBNと一致するケースも多い。9784320006232。 同じ本なら世界中どこでも同じISBN。1=New (新品), 2=Used-LikeNew (未使用に近い), 3=Used-VeryGood, 4=Used-Good, 5=Used-Acceptable, 6=Refurbished, 7-10=Collectible。 11は存在しない。REFRESH MATERIALIZED VIEW で再構築。~/Library/LaunchAgents/*.plist でジョブ定義。 scraperやauto_pipelineを定刻に動かす。httpx (= Python HTTPクライアント) を使用。 サイトのWAF対策とのいたちごっこ。A. 必須。 削除するとDBが半年で使い物にならなくなる。 「DB蓄積=データ永続」 と思いがちだが、 蓄積したデータは時間が経つと古くなる。 continuous_bulkは「古い情報を新しい情報で上書き」 する役割。 これがないとAmazon価格が永遠に古いまま。
A. portal応答が遅くなる + 同一ASINの重複呼び出しで token浪費。 業界標準は「事前にDB化 + 定期更新」。
A. 最大60日。 6月以降の運用で常に「60日以内のデータ」 を維持。 業界標準より1か月遅れだが、 月50万円→月2万円のコスト削減で許容。
A. ① scraper が拾う → ② listings に登録 → ③ Phase 2 でISBN補完 → ④ Phase 3 でASIN紐付け → ⑤ Keepaから Amazon情報取得 → ⑥ portal表示。 全自動。
A. v3で LIMIT 100,000 → 2,000 + ORDER BY 利益額DESC に変更済。 応答 34秒→5秒に改善。 もし重くなったら book_summary_mv の REFRESH中の可能性。
A. 存在しないKeepaのコード。 過去の指示書が「cond==11=NEW」 と誤認した結果、 4.4万件のデータが壊れた事故あり。 v3で cond==1=NEW に修正済。
A. ① scraper停止 = 新規仕入候補が見つからない (= 既存の portal表示は継続)。 ② continuous_bulk停止 = Amazon価格が古いまま (= 表示は継続)。 ③ portal停止 = ユーザー画面表示不可。 復旧は launchd 再起動で。