🐴

【Python】静的ページはrequests、動的ページはDrissionPage:スクレイピングの使い分け実践録

に公開

スクレイピングとは

Webスクレイピングとは、Webサイトにある情報を自動的に抽出し、出力したい構造に合わせた形式でデータを保存する技術です。

本記事の目的

学習用のデータ収集やデータ分析などに利用するためのデータ収集として学んだスクレイピングの手法の使い分けについて整理します。

本記事の結論

  • 静的ページ → requests + BeautifulSoup
  • 動的ページやBot対策 → DrissionPage

このように使い分けることで、効率的かつ安定したデータ収集が可能になります。
ただし、スクレイピングは対象サイトや法律・規約に従うことが大前提です。安全・適切に活用していきましょう。

ライブラリのインストール

今回は以下の3つを利用しました。

  • requests
  • BeautifulSoup
  • DrissionPage
pip install requests bs4 DrissionPage

基本的にはrequests + beautifulsoupによる方法です。
JavaScriptなどの動的要素や、Bot対策などによって取得が困難な場合は、Drissionpageによる方法でブラウザ操作を行い、スクレイピングをしています。

DrissionPage

ブラウザ操作というと、SeleniumやPlaywrightなどのライブラリが使われるかと思います。

DrissionPageは、requestsに近い書き方でChromeのブラウザ操作ができ、比較的高速で処理が可能です。また、CloudflareなどのBot回避も可能であり、Seleniumなどのライブラリに比べメモリ消費も少ないです。初学者にとっては、シンプルな実装でブラウザ操作ができる点がメリットかなと思います。

【参考記事】
https://qiita.com/Kazukiya/items/707d56e8f1122e41fee1
https://github.com/g1879/DrissionPage

実装ステップ

requests + Beautifulsoupによる方法

作品のレビュー情報の収集

アニメや映画などのレビュー情報(タイトル、コメント数、コメント内容など)を収集し、作品のトレンド把握や市場分析に生かすことができます。

import requests
from bs4 import BeautifulSoup

BASE_URL = "https://www.test.jp/"

def scrape_info(work_id):
    """ 作品情報を取得する """
    works = []
    WORK_URL = f"{BASE_URL}/{work_id}"
    response = requests.get(WORK_URL)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    title = soup.find("div", class="title").get_text(strip=True)
    tags  = [tag.get_text(strip=True) for tag in soup.find_all("span", class="tag_lists")]
    comments = [comment.get_text(strip=True) for comment in soup.find_all("div", class="comment_content")]

    works.append({
        'title':title,
        'tag':tags,
        "comments": comments,
        })
    return works

ランキング情報 × 商品評価の比較検討

ECサイトなどの商品評価をランキング情報を関連させて取得することで、「なぜその商品がランキング上位なのか」「どのような商品が売れているのか」などの調査のためのデータを収集することができます。先ほどのレビュー取得のコードを組み合わせることで、レビュー情報も取得可能です。

import requests
from bs4 import BeautifulSoup

def scrape_listing_page(url) -> list[dict]:
    """ 指定ページのランキング一覧 """
    res = requests.get(url)
    res.raise_for_status()
    soup = BeautifulSoup(res.text, 'html.parser')

    items = []
    for item in soup.find_all('div', class_="ranking_item"):
        product_name = item.find("div", class="product").get_text(strip=True)
        company = item.find("div", class="companies").get_text(strip=True)
        rank = item.find_all('p', class_='product-rank')
        if len(rank) > 0:
            rank = int(rank[0].get_text())
        else :
            continue

        star_count_tag = item.find_all('a', class_='reviewPoints')
        if star_count_tag:
            star_count = star_count_tag[0].get_text()
            star_count = int(star_count.lstrip("★").replace(",",""))

        # タグの取得
        tags_list = item.find_all('span', class_='work-tags')
        if len(tags_list) > 0:
            tags_list = tags_list[0].find_all('span')
            tags = [t.get_text() for t in tags_list]
        else :
            tags = []

        # 情報の格納
        items.append({
            'ranking': rank,
            'product_name': product_name,
            'company': company,
            'star_count': star_count,
            'tags': tags
        })
    return items

DrissionPageによる方法

requests + beautifulsoupで取得できない場合に使います。

物件サイトの情報収集

不動産分析をするために、物件情報(住所、間取り、価格など)を収集します。

import time
from bs4 import BeautifulSoup
from DrissionPage import ChromiumPage

BASE_URL = "https://example-realestate.com/property"

def scrape_property_info(property_id: int) -> dict[str, str | None]:
    """ 指定された物件IDから、物件情報を取得する """
    page = None
    try:
        # 物件詳細ページURL
        detail_url = f"{BASE_URL}/{property_id}/"

        page = ChromiumPage()
        page.get(detail_url, retry=2, interval=2, timeout=20)

        time.sleep(2)  
        soup = BeautifulSoup(page.html, "html.parser")

        address = soup.find("span.address")
        price = soup.find("span.price")
        layout = soup.find("span.layout")
        age = soup.find("span.age")

        property_info = {
            "property_id": property_id,
            "address": address.get_text(strip=True) if address else None,
            "price": price.get_text(strip=True) if price else None,
            "layout": layout.get_text(strip=True) if layout else None,
            "age": age.get_text(strip=True) if age else None,
        }

        return property_info
    finally:
        if page:
            try:
                page.quit()
            except:
                pass

sample_id = 12345
info = scrape_property_info(sample_id)
print(info)

Chromiumの共通インスタンス作成の検討

ここまで紹介したように、DrissionPageの基本処理はChromeのブラウザ操作をして、Bot対策や動的要素の取得を可能にします。
しかし、大量のデータを取得する場合、Chromeを繰り返し起動するため、処理時間の増加が起きます。
そのため、共通のインスタンスを作成することで高速化が可能です。一方でメモリ使用量の増加もあります。用途に合わせて検討するのが良いかと思います。

共通インスタンス利用のメリット・デメリット

観点 メリット デメリット
パフォーマンス ブラウザ起動が1回で済み、高速化できる 長時間利用でメモリ使用量が増え、重くなることがある
セッション Cookieやログイン情報を引き継げる 状態が汚染され、前の操作が影響する可能性あり
安定性 一貫した環境でスクレイピングできる 共通インスタンスが落ちると全体が止まるリスク
並列処理 同じセッション内で複数ページを効率的に扱える 並列タスクでは競合しやすく、新規インスタンスの方が安全

まとめ

本記事では、Webスクレイピングの代表的な2つの手法について整理しました。

  • requests + BeautifulSoup

    • 静的なページから情報を収集するのに適しており、軽量かつ高速。
    • 基本的なスクレイピングはこれで十分対応可能。
  • DrissionPage

    • JavaScriptによる動的要素や、Bot対策があるサイトに有効。
    • Seleniumに比べてシンプルな書き方でブラウザ操作ができ、メモリ消費も比較的少ない。
    • 共通インスタンスの利用により効率化できるが、リソース消費や安定性には注意が必要。

Discussion