フリマの中古相場は検索エンジンから見えない — ヘッドレスブラウザでサイト内検索する型
メルカリ等の個別出品は検索エンジンに載らずJS描画のため、WebSearch/WebFetchだけでは原理的に探せず「出品なし」と誤報告される。Playwrightでサイト内検索を実行する2本のツール(探す/読む)と、networkidle不可・スケルトン待ち・価格表記3パターン・ショップ出品の別DOM・横断検索のレート制限といった実測の罠、そして「取得不可を不在に格上げしない」運用ルールをまとめた。
約8.2万トークンの節約 (API料金換算で約120円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「フリマの中古相場は検索エンジンから見えない — ヘッドレスブラウザでサイト内検索する型」は、データ収集カテゴリのAI指示書(MDファイル)です。メルカリ等の個別出品は検索エンジンに載らずJS描画のため、WebSearch/WebFetchだけでは原理的に探せず「出品なし」と誤報告される。Playwrightでサイト内検索を実行する2本のツール(探す/読む)と、networkidle不可・スケルトン待ち・価格表記3パターン・ショップ出品の別DOM・横断検索のレート制限といった実測の罠、そして「取得不可を不在に格上げしない」運用ルールをまとめた。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約8.2万トークン(API料金換算で約120円)・91%のトークンを節約できます。
- カテゴリ
- データ収集
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約9万トークン
- この巻物使用時
- 約8,000トークン
- 節約量
- 約8.2万トークン (約120円)
- 更新日
- 2026-10-02
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-11d7f402/raw を読み込んで、この指示書どおりに実装して"
中身
フリマの中古相場は検索エンジンから見えない — ヘッドレスブラウザでサイト内検索する型
中古品を調達するとき、AI に「相場を調べて」「安いのを探して」と頼むと、実際には大量に出品があるのに「見つかりませんでした」と報告してくることがある。原因は AI の怠慢ではなく、経路の選択ミスで、放置すると「中古市場が成立していない」という誤った結論のまま新品を買わされる。
実例: ある機材の中古を探させたところ「該当出品なし。新品を買うべき」と報告された。人間がフリマアプリの検索窓に一般名詞を1語入れたら 129件 ヒットし、必要な品が定価の半額以下で並んでいた。
なぜ検索エンジンでは見つからないのか
フリマ(メルカリ・ラクマなど)の個別出品は、構造的に外部から見えない。
- 検索エンジンにインデックスされない — 出品は新規・短命(売れたら消える)で、クロールが追いつかない
- 商品ページが JavaScript 描画 — HTTP で取得すると footer とナビゲーションしか返らない
- 検索結果ページも JavaScript 描画 — つまり「読めない」だけでなく 「探せない」
ここが重要で、WebSearch(検索エンジン)と WebFetch(HTTP 取得)しか持っていない AI は、原理的にフリマを扱えない。にもかかわらず「0件でした」と返すため、人間は「本当に無いのだ」と信じてしまう。
解決: サイト内検索をヘッドレスブラウザで実行する
フリマは自前の検索エンジンを持っている。そこを叩けばよい。ツールは2本に分ける。
1. 探すツール(サイト内検索を実行して一覧を返す)
#!/usr/bin/env node
import { chromium } from 'playwright';
const keyword = process.argv[2];
const browser = await chromium.launch();
const ctx = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
locale: 'ja-JP',
viewport: { width: 1440, height: 2400 },
});
const page = await ctx.newPage();
const p = new URLSearchParams({ keyword, status: 'on_sale' });
await page.goto(`<フリマの検索URL>?${p}&sort=price&order=asc`, {
waitUntil: 'domcontentloaded', // ← networkidle は使わない(後述)
timeout: 60000,
});
await page.waitForSelector('<商品カードのセレクタ>', { timeout: 30000 });
await page.waitForTimeout(1200);
const items = await page.evaluate(() =>
[...document.querySelectorAll('<商品カードのセレクタ>')].map((li) => {
const a = li.querySelector('a[href*="/item/"]');
return { href: a?.href ?? '', label: a?.getAttribute('aria-label') ?? '', text: li.innerText.replace(/\n+/g, ' ').trim() };
}),
);
await browser.close();
2. 読むツール(個別ページから価格・状態・発送日数を取る)
一覧には出ない情報(商品の状態・発送までの日数・販売中か)は個別ページでしか取れない。納期が絡む調達では、ここを見ないと判断できない。
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
await page.waitForTimeout(1500);
const body = await page.evaluate(() => document.body.innerText);
const pick = (re) => (body.match(re) ?? [])[1]?.trim() ?? '取得不可';
const result = {
price: pick(/[¥¥]\s?([\d,]{3,})(?:\s|\n)/),
condition: pick(/商品の状態\s*\n?\s*(.+)/),
shipping: pick(/配送料の負担\s*\n?\s*(.+)/),
days: pick(/発送までの日数\s*\n?\s*(.+)/),
status: /SOLD|売り切れ/.test(body) ? '売り切れ' : '販売中',
};
document.body.innerText から正規表現で拾う方式にしておくと、DOM 構造が変わっても壊れにくい。セレクタ依存にしないこと。
実装上の罠(実測で踏んだもの)
waitUntil: 'networkidle' は使わない
フリマも大手通販も広告・計測タグがバックグラウンドで通信し続けるため、networkidle に到達しない。あるサイトでは毎回60秒タイムアウトして0件になっていた。domcontentloaded + waitForSelector に変える。
ローディングスケルトンを待つ
商品ページの初期 HTML はスケルトン(骨組み)だけのことがある。取得できても中身が空になる。ローディング用の要素が消えるまで待つ。
await page.waitForSelector('[data-testid="loading-skeleton"]', { state: 'detached', timeout: 15000 }).catch(() => {});
価格表記は3パターン混在する
¥5,000 / 5,000円 / 5000 が同じサイト内で混ざる。全部拾う正規表現にしないと「不明」だらけになる。
const parsePrice = (t) =>
(t.match(/[¥¥]\s?([\d,]{3,})/) ?? t.match(/([\d,]{3,})\s*円/) ?? t.match(/\b([\d,]{3,})\b/) ?? [])[1]?.replace(/,/g, '') ?? '';
ショップ出品は別 DOM
個人出品(/item/...)とショップ出品(/shops/product/...)で DOM が違う。片方しか対応していないと**全項目「取得不可」**が返る。この状態で一覧側の数字を信じると、実売の数倍の価格を報告してしまう。
横断検索サービスに依存しない
複数フリマを串刺しする横断検索サイトは便利だが、レート制限が厳しい。短時間に数回叩いただけでブロックされ、45秒・90秒待っても復帰せず、数十分〜1時間使えなくなった。しかも「0件」の画面が返るので、AI は「出品がない」と誤認する。一次経路にはせず、自前のヘッドレス経路を持つこと。
サブエージェントに任せるなら「再委譲するな」と明記する
調査を委譲した先がさらに孫エージェントを生み、並列で同じサイトを叩いてブロックを深めた。委譲の指示には必ず「さらに別のサブエージェントへ再委譲しないこと」と書く。
試して駄目だった経路(再挑戦しないため)
| 経路 | 結果 |
|---|---|
| HTTP 取得(WebFetch 等) | footer のみ。商品情報は返らない |
| 検索エンジンで商品ID検索 | インデックスされておらずヒットしない |
| テキスト抽出プロキシのブラウザ描画モード | 401 AuthenticationRequiredError。API キー必須で無料では使えない |
生 HTML から JSON-LD / __NEXT_DATA__ | どちらも存在しない |
| 生 HTML の OGP メタ | 商品名だけは取れる(og:title)。価格・状態は取れない |
OGP から商品名だけ取れるのは覚えておくと役に立つ。「この URL は何の商品か」だけ知りたいときはヘッドレスを起動せずに済む。
運用ルール(これが本体)
技術より、こちらのほうが事故を防ぐ。
- 「取得不可」を「存在しない」に格上げしない。 調査役が正しく「取得できなかったので未確認」と留保していても、まとめ役がそれを「出品がない」と断定して報告してしまう事故が起きる。留保は最終回答まで持ち越す
- 同じ取得失敗に2回ぶつかったら、その時点で経路を変える。 3回目も同じ壁に当たるだけ
- 検索は一般名詞1語で母集団を取ってから絞る。 型番+サイズで最初から絞ると、自分で母集団を潰す
- 納期が絡むなら「発送までの日数」を必ず個別ページで確認する。 一覧には出ない。「8〜14日で発送」の出品を掴むと納期が破綻する
- ツールは消えない場所に置く。 リポジトリ配下に作ったツールと依存パッケージが、クリーン処理で消えていた事例がある。「書いた直後に1回動いた」を恒久化の根拠にせず、別の機会に再実行して存在と動作を確認してから「使えます」と報告する
適用できる場面
- 中古機材・部品の調達判断(買う/借りる/新品にする)
- 相場調査(直近の成約価格は一覧の「売り切れ」から読める)
- 在庫・納期を見ながらの発注計画
逆に、公式通販サイトの価格だけで判断してよい場面には不要。ヘッドレスブラウザは起動コストが高いので、HTTP で取れるサイトはそのまま取る。
よくある質問
+「フリマの中古相場は検索エンジンから見えない — ヘッドレスブラウザでサイト内検索する型」とは何ですか?
メルカリ等の個別出品は検索エンジンに載らずJS描画のため、WebSearch/WebFetchだけでは原理的に探せず「出品なし」と誤報告される。Playwrightでサイト内検索を実行する2本のツール(探す/読む)と、networkidle不可・スケルトン待ち・価格表記3パターン・ショップ出品の別DOM・横断検索のレート制限といった実測の罠、そして「取得不可を不在に格上げしない」運用ルールをまとめた。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約9万トークンかかりますが、この巻物を使えば約8,000トークンで済みます。差し引き約8.2万トークン(API料金換算で約120円)・91%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
定期スクレイピング→Googleスプレッドシート自動集計MD
競合価格・在庫・ランキングなどを毎日自動取得してスプレッドシートに蓄積するバッチを AI に作らせる指示書。robots.txt 尊重・レート制限・差分検知のベストプラクティス込み。
Androidアプリの通知をローカルPCへ取り込む(公式API非対応のチャット向け)
公式APIが無いチャットサービスの投稿を、Android通知経由で手元PCに集める指示書。着手前に『その通知が本当に発生するか』をADBの通知履歴で検証する手順、fail-closedなallowlist設計、個人名を残さない診断ログ、LLM要約の壊れ方と対策までを含む。
CI でだけ落ちるスクレイパの直し方 — WAF/bot判定を疑い、診断→自動復旧まで入れる
定期スクレイパが CI でだけ失敗しローカルでは成功する時の診断手順。失敗履歴の数え方、cookie 名で防御レイヤを特定する診断 artifact の作り方、セッション再作成リトライと部分成功の扱い、そして『IP ベースのブロックにリトライは効かないので実行場所を変える』という実測結論まで。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア