Skip to content

Latest commit

 

History

82 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kakaku-ai

中古車の相場・口コミ・壊れやすい点を毎週スナップショットして、 時系列の追える 1 冊の xlsx にまとめるパイプライン。

対象は 2 層に分かれている。

① 全車種・全年式(小売相場のみ) — カーセンサー掲載の約 2,200 車種を 年式別に。メーカー / 国産・輸入 / ボディタイプ(用途)/ 車種 / 年式 で絞り込める。

② 深掘り 20 車種(2013年式以降の 7人乗りミニバン・全国) — 落札実績・口コミ・ 不具合・在庫追跡まで含めた重い収集。ヤフオクを全車種でやると 4〜6 時間かかり、 車種カテゴリが無い車種も多くて空振りが大半になるため、実際に検討している車種に絞る。

  • トヨタ: アルファード / ヴェルファイア / ノア / ヴォクシー / エスクァイア / シエンタ / エスティマ / ウィッシュ / プリウスα / アイシス / グランエース
  • ホンダ: ステップワゴン / フリード / オデッセイ
  • 日産: セレナ / エルグランド
  • 三菱: デリカD:5
  • マツダ: ビアンテ / プレマシー / MPV

出力物は Google Drive の共有フォルダにも週次で上がる。


何が入っているか

シート 中身
グラフ_価格差 落札価格と店頭価格の差が大きい順の横棒。走行距離も併記。まずここ
グラフ_車種別 車種ごとの落札相場 vs 小売相場の棒グラフ
グラフ_年式別 車種 × 年式 の落札中央値マトリクス(行内で色分け)+ 値落ちカーブ
相場_最新 直近時点の 車種 × 年式 相場を数字で
相場_時系列 全スナップショットを積んだ long format
推移_落札中央値 / 推移_小売中央値 行=車種×年式 / 列=時点 のピボット。折れ線はここから
車種サマリ 新車・中古価格レンジ、掲載台数、店舗数、満足度
口コミ_年式別 / 口コミ_明細 みんカラのレビュー(年式・グレード・6軸スコア・満足/不満/総評)
壊れやすい点 国交省の不具合通報を装置別に集計。発生時の走行距離中央値つき
リコール 国交省リコール届出(不具合の状況・改善措置の全文)
相場_累計 全スナップショットの落札を名寄せした年式集計。サンプルが欲しいときはこちら
落札明細 ヤフオク!の落札 1 台ずつ(累計)。グレード・車検・諸費用込み総額つき
店頭_成約推定 カーセンサーの在庫を個体で追い、掲載が消えた=売れたとみなしたもの
参考_ジモティー掲載 ジモティーの掲載 1 件ずつ。業者フィードか直接投稿かの別つき
全車種_年式別相場 全車種・全年式の小売相場。メーカー / 国産・輸入 / 用途 / 年式でフィルタ
全車種_一覧 全車種のサマリ。新車時価格・中古レンジ・掲載台数・評価
車種マスタ 深掘り 20 車種の世代・型式の一覧

相場は 3 系統を並べて持つ:

  • オークション相場 — ヤフオク!「中古車・新車」の終了180日間の落札実績(成約値)
  • 小売相場 — カーセンサー掲載車の価格分布(販売店の売り値)
  • ジモティー掲載 — 売り希望額。業者と個人が混在する参考値(成約値ではない)

オークションと小売の差(小売プレミアム)が、業販と店頭の値付けギャップの目安になる。

「いくらで売れたか」がどこまで見えるか

経路 成約価格 状態
ヤフオク! 落札 そのもの 2026-02-23 以降 782 件(週次で伸びる)
店頭(カーセンサー) 非公開 → 掲載終了で推定 追跡中。2 回目のクロールから貯まる
ジモティー 非公開(掲載価格のみ) 参考のみ
業者オークション / 官公庁 非公開・会員限定 対象外

店頭の成約価格はどのサイトも公開していない。そこでカーセンサーの在庫を 個体 ID で毎週追い、掲載が消えたら売れたとみなしてそのときの価格を記録している (店頭_成約推定 シート)。取り下げや掲載期限切れでも消えるし、実際の成約額は 値引きぶん下がるので、上限の目安として読むこと。

落札データは週を重ねるほど厚くなる

ヤフオクの落札検索は「終了180日間」しか返さない。ただし週次スナップショットを auction_id で名寄せしているので、実効期間は 180 日を超えて伸びていく。 半年回せば約 1 年ぶんが貯まる計算で、年式ごとのサンプル数もそのぶん増える。

あわせて、落札商品ページ(/jp/auction/<id>)から検索結果には無い グレード・車検・修復歴・諸費用込み総額を取っている。落札済みの出品はもう変わらないので、 パース結果は data/auction_details.jsonl に永続キャッシュして二度と取りに行かない。 初回だけ 780 ページぶん時間がかかるが、2 週目以降は新規分(週 30〜60 件)だけ。

相場を並べるときの落とし穴

2 系統をそのまま比べると数字が嘘をつくので、2 つ補正している。

  1. 年式構成のズレ — ヤフオクの落札は古い年式に、カーセンサーの掲載は新しい年式に偏る。 車種単位で単純に中央値を比べると、ノアで差額 243万円という実在しない数字が出た。 グラフ_車種別 では小売側を落札と同じ年式構成で重み付けし直している(同じノアで 29万円)。
  2. 走行距離のズレ — 同じ年式で揃えても、落札車は距離が伸びている。 シエンタ 2016年式は落札車が中央 22.0万km、掲載車が 3.9万km。 価格差 159% はほぼこれで説明がつく。だから グラフ_価格差 には両方の走行距離を並べてある。 差額をそのまま利ざやと読んではいけない。

使い方

uv venv && uv pip install -e .

uv run kakaku-ai crawl                  # 今日のスナップショットを取る
uv run kakaku-ai crawl --only alphard   # 車種を絞る
uv run kakaku-ai crawl --sources yahoo  # ソースを絞る
uv run kakaku-ai excel                  # 全スナップショットから xlsx を組む
uv run kakaku-ai upload                 # Drive にアップロード
uv run kakaku-ai weekly                 # 上の 3 つを通しで
uv run kakaku-ai list                   # 収録済みスナップショットを表示

crawl は取得した生レスポンスを data/cache/<日付>/ に置くので、 同じ日に何度回しても相手サイトを叩き直さない。 パーサだけ直して再集計したいときは crawl をもう一度走らせればキャッシュから作り直す。 本当に取り直したいときだけ --no-cache


週次で回す

ローカル(systemd user timer)— こちらが本番

毎週月曜 04:23 に scripts/weekly.sh が走り、 crawl → xlsx 生成 → Drive アップロード → main へ push までを通す。 rclone の認証情報がローカルにあるので、これがいちばん素直。

mkdir -p ~/.config/systemd/user
cp scripts/systemd/kakaku-ai-weekly.{service,timer} ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now kakaku-ai-weekly.timer

systemctl --user list-timers kakaku-ai-weekly.timer   # 次回の実行予定
systemctl --user start kakaku-ai-weekly.service       # 今すぐ 1 回まわす
journalctl --user -u kakaku-ai-weekly -f              # ログ
systemctl --user disable --now kakaku-ai-weekly.timer # やめる

マシンが落ちていて実行時刻を逃しても Persistent=true で次の起動時に追いつく。

GitHub Actions(手動のバックアップ)

.github/workflows/weekly.ymlcron を持たないworkflow_dispatch のみ)。 定期実行をここにも置くと、同じ月曜の朝に systemd timer と二重に走り、 同じ snapshot 日付を両方が commit して push が衝突する。 ローカルが長期間落ちるときに手で起動する代役として使う。

Drive へのアップロードは rclone の認証情報が要るので、 RCLONE_CONFIG_GDRIVE_TOKEN / _CLIENT_ID / _CLIENT_SECRET が Secrets に設定されているときだけ実行される(未設定ならスキップ)。

出品監視(1日4回)— Slack 通知

出品中のオークションを見て、相場から外れているものを #notif-car-auction に流す。 落札の積み上げ(週次)とは別物で、こちらは速報。ヤフオクの出品期間は数日〜1週間 なので週次だと終わってから気づくことになる。

cp scripts/systemd/kakaku-ai-watch.{service,timer} ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now kakaku-ai-watch.timer   # 毎日 07/12/18/22 時台

uv run kakaku-ai watch --budget 200 --dry-run   # 送らずに中身だけ見る
uv run kakaku-ai watch --budget 200             # 実際に流す(既定で修復歴なしのみ)
uv run kakaku-ai watch --repair any             # 修復歴で絞らない

既定は --repair none で、修復歴「なし」の申告があるものだけを流す。 「わからない」は「なし」ではないので通さない(落札実績では 17% がこれ)。 出品中の一覧は修復歴が 99% 埋まっている(実測 901件中 NONE 819 / EXISTS 70 / 未記載 12)ので、一覧の値でほぼ判定でき、未記載の分だけ商品ページで確認して落とす。

判定の中身は src/kakaku_ai/watch.py の docstring に書いてある。 要点だけ:

  • 価格を判定するのは「即決価格がある」か「終了24時間以内」のときだけ。 出品直後の現在価格は競り上がる前なので相場と比べても意味がない。 これを入れずに動かしたら ¥1スタートの新規出品が「相場より99%安い」として 300件中220件ヒットした。
  • モデルの当てはまりが悪い車種では、しきい値を広げて言い切らない。 R² は ノア 0.84 〜 エルグランド 0.29 まで開きがある。
  • 「壊れやすさ n%」は出さない。 検証する手段がないから。 代わりに国交省データから「この世代の通報1位の装置」「故障発生の中央走行距離を 超えているか」など、数えられる事実だけをフラグで出す。

通知の見た目

1 出品 = 1 attachment。左に割安度の色棒(🟢 40%以上安い / 🟡 それ未満 / ▫️ 判定不能)、 右にサムネイル。数字は 2 列で、価格・終了までの時間・出品者を並べる。 注意点は context ブロックの小さい文字にして、本体を邪魔しないようにしてある。

🟢 セレナ 2015年 C26系 ・ 13.1万km                      [サムネ]
   現在 21.7万円              即決 21.7万円
   落札相場 30.4万 比 -29%     即決相場 比 49% 安い
   まだ競り上がる
   残り13日                   ストア 評価96.8%
   入札 0件                   大阪狭山市池之原
   ⚠️ 「電気装置」の故障発生の中央走行距離 7.0万km を超過(この個体 13.1万km)
   ℹ️ 修復歴なし(申告)・ この世代の通報1位は「電気装置」(325件・35.4%)
   📊 2015年の落札 68件 + 距離補正

同じ出品を二度流さない仕組み

既読は data/watch_seen.json(git 管理下)に auction_id → 終了日時 で残す。 ただしローカルのファイルだけには頼らない。 実際にこのファイルを消してしまい、 投稿済み 64件のうち 28件が既読から抜けて再通知され得る状態になったことがある。

そこで投稿の前に Slack のチャンネル履歴も読んで、そこに出ている auction_id を 既読として扱い、ローカルにも書き戻す。Slack 自身が真実の記録になるので、 ローカルの状態が壊れても復旧する。履歴が読めなかったときは通知を止めずに続ける。

終了日時を持たせているのは、終わった出品を既読から落としてリストが際限なく 伸びるのを防ぐため(終了済みの ID で再出品されることはない)。保持は 14 日。

Slack トークンは hermes の ~/.hermes/.envSLACK_BOT_TOKEN を借りている。

全車種クロール(週次・別枠)

約 2,200 車種の相場ページを 1 枚ずつ舐める。75 分前後かかるので本体とは別のタイマー。

cp scripts/systemd/kakaku-ai-wide.{service,timer} ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now kakaku-ai-wide.timer   # 毎週火曜 02:41

uv run kakaku-ai wide                  # 全車種
uv run kakaku-ai wide --prefix TO      # メーカーを絞る
uv run kakaku-ai wide --limit 20       # 試運転

手で回す

uv run kakaku-ai weekly    # crawl → excel → upload
./scripts/weekly.sh        # 上に加えて git push まで

設計

  • 過去のスナップショットは絶対に書き換えない。 週次実行は data/snapshots/<YYYY-MM-DD>/ を 1 つ足すだけ。xlsx は毎回全断面を読み直して組み直す。
  • 相場は long format(1行 = 時点 × 車種 × 年式)。週を重ねても列は増えない。
  • 車種マスタ config/vehicles.*.yaml が全ソースの結節点(メーカー別にファイルを分割)。 ここに各サイトの ID を持たせて、収集側は ID を引くだけにしてある。 他メーカー・他ボディタイプに広げるときは、この YAML を増やす。

詳しくは:

  • docs/crawl-research.md — どのサイトから何をどう取るか(実測ベース)
  • docs/schema.md — データスキーマと相場の算出方法
  • docs/market-research.md — 同種サービスの競合調査(日本・海外)と、 このデータを事業にできるかの評価

クロールのお作法

  • robots.txt を読んだうえで、許可されている経路だけを使っている。 ヤフオク!は /closedsearch/closedsearchAllow されている一方、 禁止クエリパラメータが列挙されているので、コード側でも FORBIDDEN_PARAMS として弾いて事故らないようにしてある。
  • ホストごとに 1.5〜2.5 秒の間隔を空ける。ジッタも入れる。
  • 素性のわかる User-Agent(このリポジトリの URL 入り)。
  • 429 / 5xx は指数バックオフで最大 3 回。
  • 業者オークション(USS / TAA など)の落札相場は会員限定の有料情報なので扱わない

データソース

ソース 用途
ヤフオク! オークション落札相場(年式・走行距離つき)
カーセンサー 小売相場(年式×価格帯の度数分布)、評価6軸
価格.com 新車価格、満足度、レビュー件数
みんカラ オーナー口コミ
ジモティー 掲載価格(業者・個人混在。参考値)
国土交通省 連ラクダ リコール届出・不具合情報

オークション/フリマ系は他にも当たったが、官公庁オークション(対象車が無く落札価格も 非公開)、メルカリ(データがサーバ側に無く、内部 API は robots で禁止)、 ラクマDisallow: /search/)は見送った。ヤフオクの定額(フリマ)出品は 既存の落札明細に 114 件含まれている。詳細は docs/crawl-research.md

About

中古車の相場・口コミ・壊れやすい点を週次スナップショットして時系列 xlsx にするパイプライン(第一弾: 2013年以降のトヨタ・ミニバン)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages