ScrapeGraphAI実践ガイド:LLMとPythonでWebスクレイピングを自動化する

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

背景:セレクター保守の悪夢

BeautifulSoupやSeleniumを使ってECサイトから10,000件の商品データを抽出するクローラーを構築したとします。しかし翌朝、パイプライン全体が停止してしまいます。原因はお馴染みの問題です。フロントエンドチームがUIをリビルドし、クラス名がclass="product-price"からclass="_2rK9a"のようなランダムなハッシュ文字列に変更されてしまったのです。

XPathやCSSセレクターを手動で調査・更新する作業は、定期的なクローラー保守時間の30%〜50%を消費します。これこそが、従来のデータ抽出手法における根深い弱点です。

ScrapeGraphAIはこの課題を根本から解決します。固定されたDOMツリーに依存する代わりに、グラフ処理パイプライン(Graph pipeline)と大規模言語モデル(LLM)を活用します。LLMは人間の目のようにWebページのコンテキストを理解するため、URLと抽出したいデータを指定するプロンプトを渡すだけで、ScrapeGraphAIが自動でページを解析し、正確なJSONを返してくれます。

環境構築

ScrapeGraphAIはPython 3.10以上を必要とします。ライブラリの競合を防ぐため、仮想環境(virtualenv)での実行を推奨します:

# 仮想環境の作成と有効化
python3 -m venv venv
source venv/bin/activate

# ScrapeGraphAIと動的JSレンダリング用Playwrightのインストール
pip install scrapegraphai playwright

# ブラウザバイナリのダウンロード
playwright install

このライブラリは、OpenAI、Google Gemini、Groq、Azure OpenAI、またはOllama経由で実行するローカルモデルなど、多数のLLMバックエンドを標準でサポートしています。

実践的なグラフパイプラインの設定

ScrapeGraphAIの中核は、事前定義されたグラフパイプラインです。最も代表的な2つのクラスとして、SmartScraperGraph(単一ページ抽出)とSearchGraph(検索エンジン連携)があります。

1. SmartScraperGraphとGPT-4o-miniによるデータ抽出

以下の例では、テクノロジーニュースサイトから1リクエストあたりわずか約0.002ドルのコストで記事一覧を抽出します:

import json
import os
from scrapegraphai.graphs import SmartScraperGraph

graph_config = {
    "llm": {
        "api_key": os.getenv("OPENAI_API_KEY"),
        "model": "openai/gpt-4o-mini",
        "temperature": 0,
    },
    "headless": True,
    "verbose": False,
}

prompt = """
ページ上の記事リストから以下の情報を抽出してください:
- title: 記事のタイトル(string)
- author: 著者名(string、存在しない場合はnull)
- points: アップボート数(integer)
- comments_count: コメント数(integer)
"""

smart_scraper = SmartScraperGraph(
    prompt=prompt,
    source="https://news.ycombinator.com",
    config=graph_config
)

result = smart_scraper.run()
print(json.dumps(result, indent=2, ensure_ascii=False))

2. OllamaによるローカルLLMの実行(完全なプライバシー保護、APIコスト0円)

社内データをスクレイピングする場合や、1日数十万ページ規模で処理する場合は、ローカルのOllamaクラスターに接続します:

from scrapegraphai.graphs import SmartScraperGraph

local_config = {
    "llm": {
        "model": "ollama/qwen2.5:7b",
        "base_url": "http://localhost:11434",
        "temperature": 0,
    },
    "embeddings": {
        "model": "ollama/nomic-embed-text",
        "base_url": "http://localhost:11434",
    },
    "headless": True
}

scraper = SmartScraperGraph(
    prompt="商品名、通常価格、セール価格を取得してください",
    source="https://example-shop.com/flash-sale",
    config=local_config
)

data = scraper.run()

3. トークン最適化とコスト削減

ECサイトの生のHTMLは通常2MB〜5MBものサイズがあり、無数のSVGタグやインラインCSS、不要なスクリプトが含まれています。このHTMLをそのままLLMに投入すると、大量のトークンを消費しレイテンシが増加します。

ScrapeGraphAIはLLMに送信する前にHTMLを自動的にパース・圧縮します。さらに、ページのDOM構造が非常に大きい場合は、設定でmax_tokensを制限し、chunk_sizeを調整することをお勧めします。

本番環境へのデプロイとモニタリング

スクレイパーをCeleryワーカーやKubernetes CronJobに組み込む際は、適切な例外処理とトークン消費量のモニタリングが不可欠です。

1. リトライおよびフォールバック機構の設計

ネットワークエラーや429 Rate Limitによってバッチジョブ全体がクラッシュしないよう、実行ロジックをリトライ関数でラップします:

import logging
import time
from scrapegraphai.graphs import SmartScraperGraph

logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)

def fetch_with_retry(url: str, prompt: str, config: dict, max_retries: int = 3, backoff_factor: int = 2):
    for attempt in range(1, max_retries + 1):
        try:
            logger.info(f"スクレイピング中: {url}(試行 {attempt}/{max_retries})")
            scraper = SmartScraperGraph(prompt=prompt, source=url, config=config)
            output = scraper.run()
            if output:
                return output
        except Exception as err:
            logger.warning(f"試行 {attempt} でエラー発生: {err}")
            if attempt == max_retries:
                logger.error(f"{max_retries} 回の試行後に完全失敗: {url}")
                raise
            time.sleep(backoff_factor ** attempt)
    return None

2. トークン使用量の監視

get_execution_info()関数を使用すると、入力/出力トークン数や各ノードのレイテンシの詳細を取得できます。このメトリクスをPrometheusやGrafanaに送信して、リアルタイムでAPIコスト予算を管理することをお勧めします:

execution_info = smart_scraper.get_execution_info()
logger.info(f"Total tokens used: {execution_info.get('total_tokens', 0)}")
logger.info(f"Execution time: {execution_info.get('execution_time', 0):.2f}s")

3. 運用における3つの重要ポイント

  • Anti-bot対策: Cloudflareなどが有効なサイトをスクレイピングする際は、生のHTTPリクエストを直接送信するのではなく、Playwright設定でローテーションプロキシプールを構成してください。
  • 構造化プロンプト: モデルが一貫した出力を返し、バックエンドでのフォーマットエラーを防ぐため、プロンプト内のJSONキー名には常に英語(例: price、sku、stock_status)を使用してください。
  • ハイブリッドアーキテクチャ: 構造変更の少ない静的ページの90%には、軽量なパーサー(ScrapyやSelectolax)を使用して100 req/sの高速処理を実現します。ScrapeGraphAIは、従来のパーサーが空データを返した際のフォールバック層としてのみトリガーするのが最適です。
Share: