座標推測を撲滅し、DOM要素を直接撮る設計。案件タイプで取得対象を切り替え、背景透過と白ロゴ検証まで自動化した lp-capture スキルの内部を解剖する。
element.screenshot() で直撮り、一発で正確に切り抜くtodo.json のジャンル情報で自動分岐、曖昧ならユーザー確認1回のページ訪問でFVと商品画像/ロゴをセット取得。7つのPhaseを1ターンで走破する
lp-captureは、案件LPを1回開くだけでFVキャプチャと商品画像/ロゴをセットで取得するスキル。バナー等の追加撮影は依頼があった時のみ。
| Phase | 役割 | 出力 |
|---|---|---|
| 0 | 前提確認・案件タイプ判定 | todo.jsonからslug取得 |
| 1 | DOM構造調査 | 撮影対象のセレクタ特定 |
| 2 | 要素を直接screenshot | fv.png / product.png |
| 3 | trim + WebP変換 | *.webp(余白除去済み) |
| 3.5 | 背景透過 + 視認性検証 | pkg-{slug}.webp(透過済み) |
スキルの原則: 1つのLP URLにつき必ず lp-capture-{slug}.webp と pkg-{slug}.webp の2ファイルをセットで出力する。片方だけの出力は失敗扱い。
毎回ズレる・切れる・余白が入る座標指定を捨て、DOMに直接聞く設計思想
| 方法 | 結果 |
|---|---|
| fullPage撮影 → sharp.extract(手動座標) | 禁止。毎回ズレる。切れる。余白が入る。微調整無限ループ |
| DOM調査 → 要素を特定 → element.screenshot() | 正解。一発で正確に撮れる |
| ロゴは画像URLを直接ダウンロード | 最善。ズレようがない・画質劣化ゼロ |
// Phase 1: DOMに聞く(座標を推測しない) const structure = await page.evaluate(() => { const result = []; function walk(el, depth) { if (depth > 2) return; const rect = el.getBoundingClientRect(); if (rect.height > 10 && rect.y < 1000) { result.push({ tag: el.tagName, class: el.className, y: rect.y, h: rect.height }); } } for (const c of document.body.children) walk(c, 0); return result; });
絶対禁止: 「だいたいこの辺り」と目測で座標を推測すること。微調整が発生した時点で方法が間違っている。DOMに聞けば正確な座標がわかる。
EC系=商品パッケージ、サービス系=ロゴ。判定はtodo.jsonのジャンル情報から
| 案件タイプ | 取得するもの | 該当ジャンル例 |
|---|---|---|
| EC系 | 商品画像(パッケージ写真) | サプリ・食品・コスメ・日用品・健康食品 |
| サービス系 | ロゴ | クリニック・買取・宅食・転職・脱毛 |
サービス系=ロゴ2段構え
header img, [class*=logo] img の src を直接ダウンロード → 元画像そのまま、画質劣化ゼロbackground-image でURLが取れない場合、ロゴを包む親要素(h1やロゴリンク)を element.screenshot()EC系=商品画像3段構え
element.screenshot()(img[src*=product], img[src*=item], FV内で最も大きい画像)slug は todo.json の値を必ず使う。anken/{ジャンル}/todo.json の 案件一覧 から該当商品の slug フィールドを読み取り、その値をファイル名(pkg-{slug}.webp)にそのまま使う。LLMが独自生成してはいけない。
API課金なしで商品画像・ロゴの背景を透明化。バックアップ→透過→検証で復元可能に
商品画像・ロゴを案件サイトに貼るとき、白背景のままだとサイト背景から浮いてしまう。remove.bg のヘッドレス自動操作で背景を透明化する。
// Phase 3.5: 背景透過(バックアップ→変換→透過→WebP戻し) fs.copyFileSync(productWebp, backupWebp); // 0. バックアップ必須 await sharp(productWebp).png().toFile(tempPng); // 1. WebP→PNG execSync(`node scripts/removebg-headless.mjs "${tempPng}"`); // 2. 透過処理 await sharp(removebgPng).webp({ quality: 90 }).toFile(productWebp); // 3. WebP戻し
バックアップは必須。透過後の視認性検証(白on透過チェック)で失敗した場合、backupWebpから復元する必要がある。透過処理単体では戻せない。
| 項目 | 仕様 |
|---|---|
| 処理時間 | 1画像あたり約30〜40秒(5案件なら約3分) |
| 解像度 | プレビュー版500x500(案件サイト商品画像200〜300pxには十分) |
| バッチモード | --batch オプションでブラウザ使い回し、起動コスト削減 |
| エラー時 | remove.bgが応答しない場合は透過なしWebPをそのまま使い、処理スキップ |
| FVの扱い | 透過しない(背景ごと必要なため対象外) |
白背景のサイトに白ロゴ透過を貼ると消える。validate-logo で検知→SVG色置換 or ラスタ反転
案件サイトは白背景が多い。白いロゴを透過すると真っ白=見えなくなる。透過後に自動検証をかけ、white-on-transparent 判定なら反転処理に回す。
# 視認性検証(必須・スキップ禁止) node scripts/lp-capture.mjs validate-logo "pkg-{slug}.webp" # → visible:true = OK、backup削除して続行 # → visible:false, reason:"white-on-transparent" = 反転処理へ
| 優先 | 方法 | 内容 | 画質 |
|---|---|---|---|
| 1 | 方法A: SVG色置換 | SVGソース取得 → sed で fill="#fff" を "#333" に置換 → sharpで再変換 | 完璧(ベクター) |
| 2 | 方法B: ラスタ反転 | sharpでピクセル走査 → R/G/B>200 の白ピクセルを 0x33 に置換 | 許容範囲 |
背景色を追加する対応は禁止。ロゴの周りに白や色付きの背景を敷くと、サイト全体のデザインから浮いて不自然になる。必ず反転で対応する。
// 方法B: ラスタ画像の白ピクセル反転(アルファチャネル保持) const { data, info } = await sharp(productWebp).raw().toBuffer({ resolveWithObject: true }); for (let i = 0; i < data.length; i += info.channels) { const r = data[i], g = data[i+1], b = data[i+2]; if (r > 200 && g > 200 && b > 200) { // 白〜薄グレー data[i] = 0x33; data[i+1] = 0x33; data[i+2] = 0x33; // ダークグレー化 } }
DOM要素直撮り + 案件タイプ分岐 + 透過視認性自動検証 の3層構造positioning-map-image が先に画像取得済みならPhase 2をスキップして後処理のみ実行する連携設計。site-builder / scenario-popup-gen とも pkg-{slug}.webp を参照する形で疎結合連携