WebスクレイピングとLLM

Python WebスクレイピングとLLMデータ抽出実践ガイド (2026)

クイックアンサー:2026年におけるLLM向けpython web scraping projectsでは、高並行ヘッドレスブラウザ(async PlaywrightまたはCrawl4AI)とアルゴリズムによるDOMノイズ除去(SVG、スクリプト、ナビゲーションの削除)を組み合わせた2段階パイプラインが必須です。構造化データ抽出にはPydanticスキーマとInstructorを活用することで、LLMの推論トークンコストを75〜88%削減可能です。


1. はじめに:最先端LLMと自律型AIエージェント時代のWebスクレイピング

自律型AIエージェントやRAGパイプラインにとって、最新かつ検証可能なWebデータは不可欠な燃料です。Claude 3.7 Sonnet、DeepSeek V3/R1、GPT-4oといったフロンティアモデルが128k〜200万トークンの巨大コンテキストを提供しているとはいえ、未処理のHTMLをそのまま流し込む手法は莫大なコストを生むアンチパターンです。

従来、Pythonでscrape website pythonを実行する場合、requestsBeautifulSoup、あるいはScrapyが主流でした。しかし現代のWebはNext.jsやReactで構築された動的SPAが主流であり、Cloudflare TurnstileやDataDome、Akamaiなどの強力なWAFが立ちはだかります。

目的も大きく変化しました:

  • 従来のスクレイピング (2015–2023): XPath/CSSセレクタによる固定フィールドのDB格納。
  • エージェント・LLM向けスクレイピング (2026): ノイズ除去によるトークン圧縮、Markdown構造の維持、Pydanticスキーマによる確実なJSON抽出。

2. フレームワーク比較:BeautifulSoup vs Scrapy vs Playwright vs Crawl4AI

評価指標 BeautifulSoup4 + Requests Scrapy (Twisted/AsyncIO) 生Playwright (Async Python) Crawl4AI (v0.9.x+)
主な用途 小規模スクリプト・静的HTML 大規模分散クローリング 動的SPA・複雑なJS操作 AIエージェント・RAG・LLM抽出
JavaScript実行 なし なし (要Scrapy-Playwright) 完全対応 (Chromium, WebKit) 最適化Chromiumエンジン
スループット ~15-25 req/s /ワーカー ~150-300 req/s /スパイダー ~5-12 pages/s /16GB RAM ~25-45 pages/s (コンテキスト再利用)
メモリ消費 最小 (~40MB) 低い (~120MB) 高い (150-350MB/コンテキスト) 中程度 (~80-140MB/タブ)
Markdown変換 外部ライブラリ必須 外部パイプライン必須 手動実装 ネイティブLLM最適化Markdown
DOMノイズ削減 手動コード実装 手動セレクタ CDPによる手動評価 内蔵PruningContentFilter
ボット検知回避 脆弱 (UA偽装のみ) ミドルウェアプロキシ 優秀 (playwright-stealth) 内蔵ステルス・TLS偽装
Pydantic連携 なし ItemLoaders なし ネイティブPydantic抽出エンジン

3. LLMスクレイピングの経済学:DOMノイズ削減とトークン最適化

一般的なWebページには大量のCSSクラス、インラインSVG、トラッキングコードが含まれ、実際のコンテンツは全体の5〜15%程度にすぎません。

1日50,000ページ取得時のコスト比較(GPT-4o $2.50/1Mトークン想定)

  • 未処理HTMLのトークン総数: 50,000 × 55,000 = 27.5億トークン
  • ノイズ削除後Markdownのトークン総数: 50,000 × 4,200 = 2.1億トークン
  • 1日あたりのコスト削減額: (2,750 - 210) × $2.50 = $6,350.00 /日
  • 月間削減額: $190,500.00 /月

4. 実装例:Async Playwright + Selectolaxによるノイズ削減

# clean_scraper.py
import asyncio
from playwright.async_api import async_playwright
from selectolax.parser import HTMLParser
import markdownify

async def scrape_clean(url: str) -> str:
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True, args=["--no-sandbox"])
        page = await browser.new_page()
        await page.goto(url, wait_until="networkidle", timeout=30000)
        html = await page.content()
        await browser.close()

    # Selectolaxによる不要タグ削除
    tree = HTMLParser(html)
    for tag in ["script", "style", "svg", "nav", "footer", "header", "noscript"]:
        for node in tree.css(tag):
            node.decompose()
    
    main = tree.css_first("main, article, #content") or tree.css_first("body")
    cleaned_html = main.html if main else tree.html

    return markdownify.markdownify(cleaned_html, heading_style="ATX", strip=['img'])

5. 次世代スクレイピング:Crawl4AIの実践

# crawl4ai_pipeline.py
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
from crawl4ai.content_filter_strategy import PruningContentFilter

async def run_crawl4ai(url: str):
    async with AsyncWebCrawler(config=BrowserConfig(headless=True)) as crawler:
        config = CrawlerRunConfig(
            cache_mode=CacheMode.BYPASS,
            content_filter=PruningContentFilter(threshold=0.48),
            wait_until="networkidle"
        )
        res = await crawler.arun(url=url, config=config)
        return res.markdown

6. PydanticとInstructorによる確実な構造化JSON抽出

# pydantic_extractor.py
import os
from typing import List, Optional
from pydantic import BaseModel, Field
import instructor
from openai import OpenAI

class TechSpec(BaseModel):
    name: str = Field(description="機能名")
    supported: bool = Field(description="対応可否")

class ProductInfo(BaseModel):
    name: str
    price_usd: Optional[float] = None
    specs: List[TechSpec]

def extract_json(clean_md: str) -> ProductInfo:
    client = instructor.from_openai(OpenAI(api_key=os.environ["OPENAI_API_KEY"]))
    return client.chat.completions.create(
        model="gpt-4o-mini",
        response_model=ProductInfo,
        messages=[{"role": "user", "content": clean_md}]
    )

7. WAF回避とcurl_cffiによる高速リクエスト

# stealth_requester.py
from curl_cffi import requests

def fetch_stealth(url: str, proxy: str = None) -> str:
    proxies = {"http": proxy, "https": proxy} if proxy else None
    res = requests.get(url, impersonate="chrome124", proxies=proxies, timeout=15)
    return res.text

8. 10万ページ処理時のトータルコスト比較

項目 生Playwright (HTML) Playwright + Selectolax Crawl4AI Firecrawl Cloud
コンピュート費用 $48.00 $22.00 $16.00 $0.00
レジデンシャルプロキシ $120.00 $32.00 $30.00 込み
LLM推論費 (GPT-4o) $13,750.00 $1,050.00 $975.00 $825.00
合計 $13,918.00 $1,104.00 $1,021.00 $1,024.00

9. まとめ:本番運用の設計原則

  1. 軽量アクセス優先: 静的ページにはcurl_cffiを使い、SPAのみCrawl4AIを起動する。
  2. ノイズ削減の徹底: 生HTMLはモデルに渡さず、80%以上のトークン圧縮を行う。
  3. Pydanticによる型保証: Instructorで自動リトライと検証を組み込む。
  4. クロールと推論の分離: Celery等の非同期キューでパイプラインを疎結合にする。
← 記事一覧へ
0 / 4