コンテンツにスキップ

BeautifulSoupより784倍速いWebスクレイピング手法

概要

従来の Python スクレイピングの定番ライブラリ BeautifulSoup と比べて約784倍速い手法が登場。サイトの防御をすり抜けながら止まらず壊れずデータ取得できるという内容。

詳細

なぜ BeautifulSoup は遅いのか

# 従来の手法(BeautifulSoup)
import requests
from bs4 import BeautifulSoup

# 問題点:
# 1. 1ページずつ順番にリクエスト(シリアル処理)
# 2. JavaScript で生成されるコンテンツが取得できない
# 3. Bot 対策(レート制限・CAPTCHA)に弱い
# 4. 大量データ時のメモリ効率が悪い

url = "https://example.com"
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
data = soup.find_all("div", class_="item")

高速スクレイピングの手法

784倍速に対応するアプローチとして、以下が考えられる:

1. 非同期処理 + 並列リクエスト

import asyncio
import aiohttp
from bs4 import BeautifulSoup

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def scrape_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        return await asyncio.gather(*tasks)  # 全URL並列取得

# 1000URLを並列取得 → シリアルより大幅に高速
results = asyncio.run(scrape_all(url_list))

2. Playwright / Puppeteer(JS レンダリング対応)

from playwright.async_api import async_playwright

async def scrape_with_js():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        await page.goto("https://example.com")
        # JavaScript が動いた後のDOMを取得
        data = await page.query_selector_all(".item")
        await browser.close()

3. Crawlee(Node.js)や Scrapy(Python)フレームワーク

# Scrapy: 高スループット、分散対応
# 自動的に:
#   - リクエストのキュー管理
#   - レート制限の遵守
#   - リトライ処理
#   - データパイプライン

class MySpider(scrapy.Spider):
    name = "myspider"
    start_urls = ["https://example.com"]

    def parse(self, response):
        for item in response.css(".item"):
            yield {"title": item.css("h2::text").get()}

4. AI を活用した構造化データ抽出

# LLM でページ内容を解析(構造が複雑なサイト向け)
from anthropic import Anthropic

client = Anthropic()
response = client.messages.create(
    model="claude-haiku-4-5-20251001",
    messages=[{
        "role": "user",
        "content": f"Extract product names and prices from this HTML: {html_content}"
    }]
)

Bot 対策への対処

# User-Agent のローテーション
headers_list = [
    {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."},
    {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)..."},
]

# リクエスト間隔のランダム化
import random, time
time.sleep(random.uniform(1, 3))

# プロキシのローテーション(大規模スクレイピング)
proxies = {"http": "http://proxy1:port", "https": "http://proxy1:port"}

なぜ重要か / いつ使うか

  • 大量のWebデータを定期的に収集する自動化パイプラインを作るとき
  • データ収集速度がボトルネックになっているとき
  • AI エージェントに Web 情報を提供するデータ収集基盤を作るとき