DOMの墓場で消耗するな:GPT-4oで「自律型スクレイピングエージェント」を構築する
「またCSSセレクタが死んでるぞ」――早朝のSlackに飛んでくるアラート。開発者の朝は、壊れたスクレイパーの修正から始まる。
2024年、モダンなWebサイトは動的かつ複雑だ。ReactやVueが生成するカオスなDOM構造を、血眼になって追いかける時代はもう終わった。セレクタのメンテナンスに人生を捧げるのは、もはやエンジニアリングではない。ただの「DOMの奴隷」だ。
私は最近、PlaywrightとGPT-4oを組み合わせた自律型エージェントを構築し、この不毛な戦いに終止符を打った。これは単なるAPIラッパーではない。「失敗を許容し、自己修復する」ための泥臭いエンジニアリングの記録だ。
1. なぜ「セレクタ」ではなく「意味」を抽出するのか
現代のWebスクレイピングにおいて、セレクタ指定は極めて脆弱だ。クラス名が`css-1a2b3c`のようにハッシュ化される環境下では、セレクタは数日で陳腐化する。
ここでAIエージェントの出番だ。AIはDOMのツリー構造ではなく、人間が認識する「UIの文脈」を理解する。これにより、メンテナンスコストを定量的に激減させた。具体的には、HTMLをそのまま投げるのではなく、`Readability.js`等を用いてMarkdown形式に変換し、トークン効率を最大化するというアプローチをとる。
トークン効率を最大化するDOM変換
`document.body.innerText`で生のテキストを投げつけるのは素人のやることだ。ノイズを削ぎ落とし、意味のある構造だけをAIに渡す。from readability import Document
import html2text
def get_clean_markdown(page_content: str) -> str:
# 不要なスクリプトタグなどを削除し、Markdownに変換
doc = Document(page_content)
text = html2text.html2text(doc.summary())
return text[:8000] # トークン消費を抑えつつ、重要なコンテキストを維持
2. 「無限ループ」を封じる:状態管理の設計
AIエージェント構築最大の罠は「無限ループ」だ。目的を達成するまでボタンを押し続けるAIは、気付かぬうちにAWSの料金を溶かす。
これを防ぐには、「実行履歴のコンテキスト管理」が不可欠だ。直近のアクションをスタックし、同じ操作が繰り返された場合に強制的にロジックを分岐させる。
class AgentContext:
def __init__(self):
self.history = []
def update(self, action):
self.history.append(action)
if len(self.history) > 3 and all(x == action for x in self.history[-3:]):
raise Exception("無限ループ検知:同一アクションの連続")
# 実行ループ内での制御
try:
action = get_next_action(page_markdown)
context.update(action)
await execute_action(page, action)
except Exception as e:
logger.error(f"エージェントが迷子になりました: {e}")
# フォールバック処理へ
3. コストと速度を最適化する:エンジニアリングの解法
「APIを叩くたびに数円かかる」という愚痴をこぼす前に、アーキテクチャを見直すべきだ。
| 戦略 | 内容 | 効果 |
|---|---|---|
| モデルの使い分け | 構造解析にはGPT-4o mini、推論にはGPT-4o | コストを約1/10に削減 |
| キャッシュ戦略 | ページ構成が変わらない場合はキャッシュを返す | 速度向上とトークン節約 |
| 並列実行 | PlaywrightのBrowserContextを分離して並列化 | 待機時間のボトルネック解消 |
特に「LLMの推論待ち」をいかに減らすかが重要だ。全てのページをAIに判断させるのではなく、まずは正規表現や軽量なパーサーでフィルタリングし、AIには「最終的な判断」だけを委ねるハイブリッド構成が、実運用では最も安定する。
4. 「完全自律」という幻想を乗り越える
正直に言おう。Cloudflareの検知や、複雑なOAuth認証をAIだけで突破するのは、現時点では「泥沼への招待状」だ。
私がたどり着いた結論は、「AIは判断まで、認証は人間(または固定Cookie)」という役割分担だ。Playwrightで`stealth`プラグインを使い、セッションを永続化する。AIには「ログイン後のページ遷移」や「データ抽出」という、最も人間がやりたくない作業を任せる。
結論:AIは免罪符ではない
AIを使ったからといって、エラーハンドリングをサボっていい理由にはならない。むしろ、AIという「不確定な要素」が加わる分、従来のスクレイピングよりも強固な防壁(ガードレール)をコードで書く必要がある。
- 失敗したときにどう死ぬか(例外処理)
- コストをどう監視するか(予算アラート)
- AIの判断をどう検証するか(バリデーション)
さあ、次はどのサイトのDOMを破壊しに行く? 私は、AIにコードを書かせるのではなく、AIを「エンジニアの分身」として使いこなす側に回るつもりだ。