2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python Webスクレイピング厳選10ライブラリ

Posted at

Pythonのウェブスクレイピング必須ライブラリ10選 🐍

Pythonは、ウェブスクレイピングで圧倒的に広く使われているプログラミング言語です。学習コストが低く、巨大なコミュニティと充実したライブラリエコシステムを持つことが人気の理由です。

この記事では、ウェブスクレイパーなら知っておくべきPythonの優れたスクレイピングライブラリトップ10を、実践的な視点から解説します。以下のような幅広い用途をカバーしています:

  • HTTP通信の効率化
  • ブラウザ自動操作
  • HTMLとJSONのパース処理
  • データ品質の検証と保証

これらのライブラリは、実際のウェブスクレイピングガイドシリーズでも活用されており、実戦的な使い方を学べます。

この記事で得られる知見 💡

包括的なデータ抽出のために、HTTPリクエストからブラウザ自動化、データ検証まで、Pythonの最高峰ウェブスクレイピングライブラリをマスターしましょう。

  • HTTPXで非同期対応のモダンなHTTP/2リクエストを実装し、従来のrequestsライブラリを超えるパフォーマンスを実現
  • BeautifulSoupで初心者にも優しいシンプルなHTML解析とデータ抽出を行う
  • Scrapyフレームワークで分散クローリングとデータ処理パイプラインを構築し、大規模スクレイパーを実現
  • SeleniumPlaywrightでJavaScriptレンダリングされた動的コンテンツを扱う
  • parselによる高度なXPath/CSS解析やjmespathによるJSON処理などの特化ライブラリを活用
  • プロジェクトの複雑さ、パフォーマンス要件、開発チームの専門性に基づいた適切なライブラリ選択

HTTPX 🚀

HTTPXは、Pythonで最も完成度が高く先進的なHTTPクライアントパッケージです。人気の高いrequestsライブラリからインスピレーションを得ながらも、モダンなPythonとHTTPの機能をさらに充実させています。

最大の特徴は、非同期と同期の両方のPython APIをサポートしている点です。これにより、httpxベースのリクエストを大規模にスケールさせつつ、シンプルなスクリプトでも使いやすくなっています:

import httpx

# 同期APIの使用
with httpx.Client() as client:
    response = client.get("https://web-scraping.dev/product/1")
    print(response.text)

# 非同期APIの使用
import asyncio

async def fetch_data():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://web-scraping.dev/product/1")
        print(response.text)

asyncio.run(fetch_data())

HTTPXはHTTP/2もサポートしており、実際の人間のトラフィックの大半がHTTP/2または3を使用しているため、ブロックされる可能性が大幅に低下します:

with httpx.Client(http2=True) as client:
    response = client.get("https://web-scraping.dev/product/1")
    print(response.text)

さらに、httpxはHTTP標準を尊重し、実際のウェブブラウザに近い形でリクエストを構築するため、ブロックされるリスクを大幅に軽減できます。ヘッダーの順序を正しく保つなど、細部にまでこだわった実装が特徴です。

ParselとLXML

LXMLは、Pythonで高速かつ機能豊富なHTML/XMLパーサーです。Cライブラリのlibxml2をラップしており、PythonでHTMLを解析する最も速く信頼性の高い方法として知られています。

LXMLは強力で柔軟なXPathセレクタを使ってHTML内の要素を見つけることができます:

from lxml import html

html_content = """
<html>
<title>My Page Title</title>
<body>
<div class="title">Product Title</div>
</body>
</html>
"""

tree = html.fromstring(html_content)
print(tree.xpath("//title/text()"))
# ['My Page Title']
print(tree.xpath("//div[@class='title']/text()"))
# ['Product Title']

さらに進化した形として、Parselがlxmlを拡張し、API使用を簡素化し、CSSセレクタのサポートも追加しています:

from parsel import Selector

html_content = """
<html>
<title>My Page Title</title>
<body>
<div class="title">Product Title</div>
</body>
</html>
"""

selector = Selector(html_content)
# XPathの使用
print(selector.xpath("//title/text()").get())
# "My Page Title"

# CSSセレクタの使用
print(selector.css(".title::text").get())
# "Product Title"

Parselは、lxmlのスピードとCSSおよびXPathセレクタの使いやすさを組み合わせているため、大量のHTMLドキュメントを解析する際の事実上の標準となりつつあります。

BeautifulSoup

BeautifulSoup (bs4とも呼ばれる)は、Pythonにおけるもう一つのHTMLパーサーライブラリですが、単なるパーサー以上の機能を提供します。

LXMLやParselとは異なり、bs4はfindfind_allといった、Pythonらしいアクセス可能なメソッドを使った解析をサポートしています:

from bs4 import BeautifulSoup

html_content = """
<html>
<title>My Page Title</title>
<body>
<div class="title">Product Title</div>
</body>
</html>
"""

soup = BeautifulSoup(html_content, 'lxml')  # 注意: bs4は内部でlxmlを使用できるため超高速!

# ノード名で単一要素を検索
print(soup.find("title").text)
# "My Page Title"

# find_allと属性マッチングで複数要素を検索
for element in soup.find_all("div", class_="title"):
    print(element.text)

このアプローチは、CSSやXPathセレクタよりも初心者に優しく、読みやすい構文となっており、複雑なHTMLドキュメントを扱う際の保守性と開発効率が高まります。

BeautifulSoup4には、HTMLのフォーマットや編集など、多くのユーティリティ機能も含まれています。例えば:

from bs4 import BeautifulSoup

html_content = """
<html><body><h2>The Avengers: Endgame</h2>is one of the most popular Marvel movies</body></html>
"""

soup = BeautifulSoup(html_content, 'lxml')
print(soup.prettify())

"""
<html>
 <body>
  <h2>
   The Avengers:
   Endgame
  </h2>
  is one of the most popular Marvel movies
 </body>
</html>
"""

HTML修正、選択的パース、クリーンアップなど、他にも多くのユーティリティ機能が用意されています。

JMESPathとJSONPath

JMESPathJSONPathは、XPathに似たクエリ言語を使ってJSONデータをクエリできる2つのライブラリです。

ウェブスクレイピングの世界でJSONの重要性が高まるにつれ、これらのライブラリは不可欠なツールとなっています。

例えば、JMESPathを使えば、JSONデータセットのクエリ、再構築、フラット化を簡単に行えます:

import jmespath

data = {
    "people": [
        {
            "name": "John",
            "age": 33,
            "addresses": [
                "123 Main St", "California", "US"
            ],
            "primary_email": "john@email.com",
            "secondary_email": "john.work@email.com",
        },
        # ...
    ]
}

result = jmespath.search("""
people[].{
    first_name: name,
    age_in_years: age,
    address: addresses[0],
    state: addresses[1],
    country: addresses[2],
    emails: [primary_email, secondary_email]
}
""", data)

print(result)
# [
#     {
#         'address': '123 Main St',
#         'state': 'California',
#         'country': 'US',
#         'age_in_years': 33,
#         'emails': ['john@email.com', 'john.work@email.com'],
#         'first_name': 'John',
#     },
#     # ...
# ]

この機能は、巨大で操作が難しいJSONデータセットを含む隠れたウェブデータをスクレイピングする際に特に有用です。

一方、JSONPathはデータセットの再構築よりも、複雑でネストが深いJSONデータセットから値を選択することに注力し、高度なマッチング機能をサポートしています:

import jsonpath_ng.ext as jp

data = {
    "products": [
        {"name": "Apple", "price": 12.88, "tags": ["fruit", "red"]},
        {"name": "Peach", "price": 27.25, "tags": ["fruit", "yellow"]},
        {"name": "Cake", "tags": ["pastry", "sweet"]},
    ]
}

# すべての商品名を検索
query = jp.parse("products[*].name")
for match in query.find(data):
    print(match.value)

# 価格が20を超える商品を検索
query = jp.parse("products[?price>20].name")
for match in query.find(data):
    print(match.value)

JSONPathの最強機能は、再帰的な$..セレクタです。これを使うと、データセット内のどこにあっても、キーで素早く値を選択できます(XPathの//セレクタに似ています):

import jsonpath_ng.ext as jp

data = {
    "products": [
        {"name": "Apple", "price": 12.88},
        {"name": "Peach", "price": 27.25},
        {"name": "Cake"},
        {"multiproduct": [{"name": "Carrot"}, {"name": "Pineapple"}]}
    ]
}

# どこにあっても全ての"name"フィールドを検索
query = jp.parse("$..name")
for match in query.find(data):
    print(match.value)

PlaywrightとSelenium ⚙️

ヘッドレスブラウザは、動的なJavaScriptやスクレイパーブロッキングに対処する方法として、ウェブスクレイピングで非常に人気が高まっています。

多くのウェブサイトは、バックグラウンドリクエストやJavaScript関数を通じてオンデマンドでデータを生成する複雑なフロントエンドを使用しています。このデータにアクセスするにはJavaScript実行環境が必要であり、実際のヘッドレスウェブブラウザを使用するのが最良の方法です。

JavaScriptフィンガープリンティングも、多くのモダンウェブサイトをスクレイピングする際に必要なステップとなってきています。

Pythonでヘッドレスブラウザをウェブスクレイピング用に制御するには、2つの人気ライブラリがあります:SeleniumPlaywrightです。

Seleniumは最初の主要なブラウザ自動化ライブラリの1つであり、ブラウザができることのほぼすべてを実行できます:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# ブラウザを設定
options = Options()
options.headless = True
options.add_argument("--window-size=1920,1080")
options.add_argument("start-maximized")

driver = webdriver.Chrome(options=options)
driver.get("https://web-scraping.dev/product/1")

# レビューがページに表示されるのを待つ
element = WebDriverWait(driver=driver, timeout=5).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, '#reviews'))
)

# ボタンをクリック
button = WebDriverWait(driver=driver, timeout=5).until(
    EC.element_to_be_clickable((By.ID, "load-more-reviews"))
)
button.click()

# レンダリングされたHTMLを取得
print(driver.page_source)

driver.quit()

一方、Playwrightはブラウザ自動化のモダンなアプローチを提供し、これらすべての機能を最新の非同期・同期APIで利用できます:

from playwright.sync_api import sync_playwright

# 同期Pythonの使用
with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context(viewport={'width': 1920, 'height': 1080})
    page = context.new_page()
    page.goto("https://web-scraping.dev/product/1")
    
    # DOM内に要素が存在するまで待つ
    page.wait_for_selector('#reviews')
    
    # ボタンをクリック
    page.wait_for_selector("#load-more-reviews", state="attached")
    page.click("#load-more-reviews")
    
    # HTMLを出力
    print(page.content())
    
    browser.close()

# または非同期
import asyncio
from playwright.async_api import async_playwright

async def scrape():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        context = await browser.new_context(viewport={'width': 1920, 'height': 1080})
        page = await context.new_page()
        await page.goto("https://web-scraping.dev/product/1")
        
        # DOM内に要素が存在するまで待つ
        await page.wait_for_selector('#reviews')
        
        # ボタンをクリック
        await page.wait_for_selector("#load-more-reviews", state="attached")
        await page.click("#load-more-reviews")
        
        # HTMLを出力
        print(await page.content())
        
        await browser.close()

asyncio.run(scrape())

CerberusとPydantic

ウェブスクレイピングプロセスで見落とされがちなのが、データ品質保証のステップです。ウェブスクレイピングは結果のデータセットが非常に動的であるため、品質テストが極めて困難な独特な領域です。

幸いなことに、ウェブスクレイピングデータの品質を保証するのに役立ついくつかのツールがあります。

リアルタイムでのデータ検証が必要なウェブスクレイピングアプリケーションには、Pydanticが優れた選択肢です。Pydanticは、スクレイピングしたデータを検証・変換するための厳密なデータモデルを指定できます:

from typing import Optional
from pydantic import BaseModel, validator

# スクレイピングした企業データの例
class Company(BaseModel):
    # 許可されるフィールド名と型を定義
    size: int
    founded: int
    revenue_currency: str
    hq_city: str
    hq_state: Optional[str]  # 一部のフィールドはオプション(Noneの値を持つ可能性)
    
    # カスタム検証関数を定義
    @validator("size")
    def must_be_reasonable_size(cls, v):
        if not (0 < v < 20_000):
            raise ValueError(f"unreasonable company size: {v}")
        return v
    
    @validator("founded")
    def must_be_reasonable_year(cls, v):
        if not (1900 < v < 2026):
            raise ValueError(f"unreasonable founded date: {v}")
        return v
    
    @validator("hq_state")
    def looks_like_state(cls, v):
        if v and len(v) != 2:
            raise ValueError(f'state should be 2 character long, got "{v}"')
        return v

より柔軟で厳格でないデータ検証が必要なデータスクレイパーには、Cerberusが最適です。Cerberusは、シンプルな辞書構文でデータモデルを指定できるスキーマ検証ライブラリです:

from cerberus import Validator

def validate_name(field, value, error):
    """検証用の関数"""
    if "." in value:
        error(field, f"contains a dot character: {value}")
    if value.lower() in ["classified", "redacted", "missing"]:
        error(field, f"redacted value: {value}")
    if "<" in value.lower() and ">" in value.lower():
        error(field, f"contains html nodes: {value}")

schema = {
    "name": {
        # nameは文字列型である必要がある
        "type": "string",
        # 2文字から20文字の間
        "minlength": 2,
        "maxlength": 20,
        # 追加の検証
        "check_with": validate_name,
    },
}

v = Validator(schema)
v.validate({"name": "H."})
print(v.errors)
# {'name': ['contains a dot character: H.']}

Cerberusの最強機能は使いやすさと、高度に動的なウェブスクレイピングデータで動作する柔軟なスキーマを定義できる能力です。Scrapflyでは、すべてのサンプルスクレイパーをテストするためにCerberusを使用しています。

Scrapy 🕸️

Scrapyは、Pythonにおける包括的なウェブスクレイピングフレームワークです。単なるライブラリではなく、完全なスクレイピングアーキテクチャを提供します。

Scrapyは、大規模なクローリングプロジェクトに特に適しており、以下の機能を備えています:

  • ビルトインの並行処理とリクエストキューイング
  • 自動的なリトライとエラーハンドリング
  • データパイプライン処理
  • ミドルウェアを通じた拡張性
  • エクスポート機能(JSON、CSV、XMLなど)

基本的なScrapyスパイダーの例:

import scrapy

class ProductSpider(scrapy.Spider):
    name = 'product_spider'
    start_urls = ['https://web-scraping.dev/products']
    
    def parse(self, response):
        for product in response.css('.product'):
            yield {
                'title': product.css('.title::text').get(),
                'price': product.css('.price::text').get(),
                'url': response.urljoin(product.css('a::attr(href)').get())
            }
        
        # 次のページへの自動的な追従
        next_page = response.css('a.next::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)

Scrapyは、分散クローリングや複雑なデータ処理パイプラインが必要な大規模プロジェクトに最適です。

ライブラリ比較表 📊

ライブラリ 主な用途 難易度 パフォーマンス 非同期対応
HTTPX HTTP通信
BeautifulSoup HTML解析
LXML/Parsel HTML解析 非常に高
Selenium ブラウザ自動化
Playwright ブラウザ自動化
JMESPath JSON処理
JSONPath JSON処理
Pydantic データ検証
Cerberus データ検証
Scrapy フレームワーク

まとめ ✨

この記事では、ウェブスクレイピングプロセスのさまざまなステップをカバーする、Pythonのトップ10パッケージを解説しました。

ウェブスクレイピング接続では、優れた機能豊富なHTTPクライアントであるhttpxを紹介しました。一方、seleniumplaywrightは、完全なヘッドレスウェブブラウザを使用するアプローチです。

データ解析では、最も人気のある3つのHTML解析ツール(lxmlparselbeautifulsoup)を見てきました。JSON解析には、ウェブスクレイピング環境で優れた働きをするjmespathjsonpathがあります。

最後に、ウェブスクレイピングプロセスの最終ステップとして、2つの異なるデータ検証ツール(厳格なpydanticと柔軟なcerberus)を紹介しました。さらに、大規模プロジェクト向けの包括的なフレームワークであるScrapyも取り上げました。

これらのライブラリを適切に組み合わせることで、シンプルなスクリプトから企業レベルのスクレイピングシステムまで、あらゆる規模のウェブスクレイピングプロジェクトを効率的に構築できます。2025年11月現在、これらのライブラリはすべて活発にメンテナンスされており、最新のPythonバージョンに対応しています。

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?