Webスクレイピングに最適なPython HTTP クライアント

最も人気のあるPython HTTP クライアントとその機能、そして2024年におけるWebスクレイピングの最適な使用例について知ることができます。
4 min read
Best Python HTTP Clients blog image

HTTP クライアントは、コードによるWebサーバー・API へのリクエスト送信や、レスポンスの受け取りを可能にする便利な Python ライブラリです。さまざまなタイプの HTTP リクエスト (GET、POST、PUT、DELETE など) の送信や、データの取得・送信だけでなく、 ウェブサイトや API でのアクションの実行を簡単に行うことができます。

Web スクレイピングの場合、一般的にこれらのクライアントは  Beautiful Soup  や html5lib などのHTML 解析ライブラリと共に使用されます。

この記事では、 Requests、 urllib3、 Uplink、 GRequests、 HTTPX、 aiohttp など、最も優れた Python HTTP クライアントをいくつか紹介します。機能や使いやすさ、ドキュメンテーションとサポート、そして人気度に基づき、それぞれのクライアントを評価していきましょう。記事を読み終える頃には、ご自分のユースケースに最適なライブラリが明らかになっていることでしょう。

Requests

まずは最も人気のあるPython HTTP クライアント、 Requests から始めましょう。このライブラリは、なんと週3,000万件という驚異的なダウンロードデータを誇ります。

こちらがRequests を使用した HTTP リクエストとレスポンスの処理例です。

import requests

print("Testing `requests` library...")
resp = requests.get('https://httpbin.org/get', params={"foo": "bar"})
if resp.status_code == 200:     # success
    print(f"Response Text: {resp.text} (HTTP-{resp.status_code})")
else:   # error
    print(f"Error: HTTP-{resp.status_code}")

 httpbin.org にて、さまざまな HTTP メソッドをテストするためのサンプルレスポンスを見ることができます。

このコード スニペットでは、 requests.get(...) メソッドは目的の URL および単一のクエリパラメータ、 fooを受け取ります。 params 引数を使用することにより、任意のクエリパラメータを渡すことができます。

Requests やその他の HTTP クライアントでは、URL にクエリ文字列を手動で追加したり、データをエンコードしたりする必要はありません。これらはライブラリにて自動的に処理されます。JSON データを送信するには、 data 引数を使用して Python 辞書を渡すことにより、 resp.json()でJSON レスポンスを直接受け取ることができます。

Requests ライブラリは、デフォルトで HTTP リダイレクト (3xx) を自動処理するため、Webスクレイピングでリダイレクトされた URL からコンテンツにアクセスする際に役立ちます。また、Secure Sockets Layer (SSL) 接続もサポートされています。

Requests は、 urllib3 を使用してコネクションプーリングや SSL 検証など低レベルの HTTP タスクを内部管理し、開発者には高レベルでPythonらしい API を提供します。

また、Requests は セッション管理をサポートしているため、Cookieやヘッダー、認証トークンなどのパラメータを複数のリクエストにわたって保持することができます。制限コンテンツへのアクセス時にこれらのパラメータの維持が必須となるWeb スクレイピングタスクにおいて、この機能は特に役立ちます。

Requests ライブラリはストリーミングもサポートしているため、ファイルのダウンロードや API からのストリーミングデータの処理など、大規模なレスポンスを伴うWebスクレイピングタスクにも役立ちます。

すべてのレスポンスデータをメモリに読み込むことなく効率的に処理するには、 iter_content() や iter_lines():などのメソッドを使用できます。

import requests

print("Testing `requests` library with streaming...")
resp = requests.get('https://httpbin.org/stream/10', stream=True)
for chunk in resp.iter_content(chunk_size=1024):
    print(chunk.decode('utf-8'))

Requests ライブラリには、ビルトインの非同期処理機能やキャッシュサポートはありません( requests-cacheにて利用可能)。また、Requests は HTTP/2 をサポートしておらず、 このディスカッションにて確認できる通り、現時点で追加の予定はありません。

注: HTTP/2 は HTTP プロトコルの新しいバージョンで、HTTP/1.1 より高速かつ効率的になるように設計されています。単一の伝送制御プロトコル (TCP) 接続における多重化により、複数のリクエストとレスポンスが可能となり、クライアント・サーバー間の接続減少によってページの読み込み速度が向上します。ただし、現時点でのHTTP/2 のサポートは限定的です。

Requests ライブラリは、Python の HTTP インタラクションを簡素化します。シンプルなメソッドや簡潔な構文、効率的な自動コネクションプーリング、そしてビルトインの JSON デコード などの優れた機能を備えています。その使いやすさやセッション管理、ストリーミング機能、そして内容豊富な ドキュメンテーション により、開発者からの支持を得ています。

urllib3

urllib3 は、開発者だけでなく、他の HTTP クライアントにも広く使用されており、十分にテストされているHTTP リクエスト用ライブラリです。Web スクレイピングにおける低レベルの HTTP リクエスト処理に便利な機能や、カスタマイズオプションを提供します。

urllib3 を使用して HTTP リクエストを行う一般的な例として、次のようなものがあります。

import urllib3

print("Testing `urllib3` library...")
http = urllib3.PoolManager()    # PoolManager for connection pooling
resp = http.request('GET', 'https://httpbin.org/get', fields={"foo": "bar"})

if resp.status == 200:     # success
    print(f"Response: {resp.data.decode('utf-8')} (HTTP-{resp.status})")
else:    # error
    print(f"Error: HTTP-{resp.status}")

このコード スニペットで、 urllib3.PoolManager() は複数のリクエストに対し再利用可能なコネクションプールを作成し、リクエストごとに新しい接続を確立する手間を回避することにより、パフォーマンスを向上させます。 fields 引数を使用して、URLと共に必要なクエリパラメータを渡すことができます。

urllib3 の最も注目すべき点は、ストリーミングレスポンスの処理機能です。これにより、大量のデータをすべてメモリに読み込むことなく効率的に処理できます。この機能は、Webスクレイピング中に大規模なファイルのダウンロードを行ったり、ストリーミング API を利用したりする場合に便利です。

urllib3 はデフォルトで自動リダイレクトをサポートしており、SSL サポートが組み込まれています。ただし、ビルトインの非同期処理機能やキャッシュサポート、セッション管理 (Cookie など) がなく、HTTP/2 もサポートされていません。

urllib3 におけるコネクションプーリングの処理は Requests ライブラリほど便利ではないものの、クラスベースのアプローチやデコレータを必要とする一部のクライアントとは異なり、urllib3 ではシンプルなスクリプト構文が使用されているため、基本的な HTTP インタラクションには非常に役立ちます。また、urllib3 はよく管理された ドキュメンテーションを提供しています。

有力なライブラリをお探しで、セッション管理は必要がない場合など、urllib3 はシンプルな Web スクレイピングタスクに最適です。

Uplink

Uplink は、機能の割に知名度の低い Python HTTP クライアントです。クラスベースのインターフェースを使用して RESTful API とのインタラクションを簡素化できるため、特に API 呼び出しを伴うWebスクレイピングに役立ちます。

API エンドポイントの呼び出しにUplinkを使用したサンプルコードをご覧ください。

import uplink

@uplink.json
class JSONPlaceholderAPI(uplink.Consumer):
    @uplink.get("/posts/{post_id}")
    def get_post(self, post_id):
        pass


def demo_uplink():
    print("Testing `uplink` library...")
    api = JSONPlaceholderAPI(base_url="https://jsonplaceholder.typicode.com")
    resp = api.get_post(post_id=1)
    if resp.status_code == 200:     # success
        print(f"Response: {resp.json()} (HTTP-{resp.status_code})")
    else:   # error
        print(f"Error:HTTP-{resp.status_code}")

このコード スニペットは、 uplink.Consumerから継承する JSONPlaceholderAPI クラスを定義しています。 @uplink.get デコレータ を使用してHTTP GET リクエストを作成し、JSONPlaceholder API により特定の投稿が取得されます。 post_id パラメータは、次のデコレータでエンドポイントに動的に含まれます: @uplink.get("/posts/{post_id}") https://jsonplaceholder.typicode.com のサイトは REST API をシミュレートしており、テストおよび開発のための JSON レスポンスを提供しています。

Uplink は SSL をサポートし、最終レスポンス取得のためにリダイレクトの自動処理を行います。また、 Bring Your Own HTTP Library(自前のHTTPライブラリ利用)などの高度な機能も提供しています。

ただし、Uplinkにはストリーミングレスポンスや非同期リクエスト、キャッシュ( requests-cacheが利用可能)、そしてHTTP/2 のビルトインサポートがありません。

Uplinkは、前述のさまざまな機能について適切な ドキュメンテーション を提供してはいるものの、定期更新は行っておらず(2022年3月の0.9.7が最終版)、利用者は少数にとどまっています。クラスベースのアプローチとデコレータ構文はオブジェクト指向の開発者には魅力的かもしれませんが、Python のスクリプトスタイルを好む開発者からすると、使いやすさの面では中級程度と言えるでしょう。

多くのユーザーは、主にHTML ページではなく、RESTful API エンドポイントからのデータ収集が必要な場合に、Uplinkを利用しています。

GRequests

GRequests はおなじみの Requests ライブラリを拡張し、非同期リクエストのサポートを追加したものです。複数のウェブサイトまたは API からデータを同時に取得することができます。

各レスポンスを待ってから次のレスポンスを送信するシーケンシャルリクエストとは異なり、GRequestsはリクエストを同時に送信することで効率を向上させます。この機能は、特に複数のウェブサイトや API からデータを取得する必要がある場合に役に立ちます。

こちらの例をご覧ください。

import grequests

print("Testing `grequests` library...")
# Fetching data from multiple URLs
urls = [
    'https://www.python.org/',
    'http://httpbin.org/get',
    'http://httpbin.org/ip',
]

responses = grequests.map((grequests.get(url) for url in urls))
for resp in responses:
    print(f"Response for: {resp.url} ==> HTTP-{resp.status_code}")

このコードでは、GRequestsは grequests.map(...) を使用して3つの GET リクエストを異なる URL に同時送信し、レスポンスを responsesという名前のリストで収集します。次に、レスポンスを反復処理して出力します。非同期 HTTP リクエストのために、GRequestsはコルーチンベースのネットワークライブラリである geventを内部で使用します。これにより、複雑な同時実行を管理することなく、複数の HTTP リクエストを同時に送信することができます。この機能の応用例として、複数のウェブサイトにおける特定のトピックやカテゴリでのニュースのスクレイピングが挙げられます。

GRequestsは、リダイレクトの自動処理やSSL、そしてすべてをメモリに読み込まずにストリーミングレスポンスを処理する機能などもサポートしています。ただし、GRequestsでは requests-cacheの使用は可能であるものの、ビルトインのHTTP/2サポートやキャッシュ機能はありませんのでご注意ください。

GRequestsは、ベースライブラリである Requests に似た直感的なメソッドを使用し、非同期 HTTP リクエストを簡素化します。同時実行を処理するための複雑な async/await 構築が不要なため、きわめて使いやすくなっています。ただし、コードベースが小さく(0.7.0バージョンで213行)開発アクティビティが少ないため、提供される ドキュメンテーション は最小限となっています。これらの要因が知名度の低さにつながっていると言えるでしょう。

複数の情報源から同時にデータを収集する必要がある場合、GRequestsの便利な非同期処理機能を検討しましょう。

HTTPX

HTTPX は 、Python のためのモダンかつ機能豊富な HTTP クライアントで、あらゆる種類のWebスクレイピングプロジェクトに広く使用されています。Python の Requests ライブラリに取って代わるだけでなく、非同期処理サポートとより優れたパフォーマンスを提供するように設計されています。

こちらの例は、HTTPX を使用した非同期 HTTP GET リクエストを表しています。

import httpx
import asyncio

async def fetch_posts():
    async with httpx.AsyncClient() as client:
        response = await client.get('https://jsonplaceholder.typicode.com/posts')
        return response.json()

async def httpx_demo():
    print("Testing `httpx` library...")
    posts = await fetch_posts()
    for idx, post in enumerate(posts):
        print(f"Post #{idx+1}: {post['title']}")

# async entry point to execute the code
asyncio.run(httpx_demo())

このコードは fetch_posts()という非同期関数を定義しています。この関数は httpx.AsyncClient()を使用して https://jsonplaceholder.typicode.com/posts API からダミーのブログ投稿を取得します。別の非同期関数としては、 httpx_demo()があります。これは fetch_posts() が投稿を返すのを待ってから、タイトルをループで出力します。最後に、 asyncio.run(httpx_demo()) は、 httpx_demo() を非同期で実行するためのエントリポイントとして機能します。

非同期 HTTP クライアントのビルトインサポートの他に、HTTPX は HTTP/2 のビルトインサポートも提供しています。これにより、単一の TCP 接続で複数のリソースを高速かつ同時に読み込むことが可能になるため、Web スクレイピング中、ウェブサイトによるブラウザのフィンガープリント追跡を受けにくくなります。

HTTPX クライアントの作成時に http2=True パラメータを設定するだけで、HTTP/2 リクエストの送信が完了します。

import httpx

client = httpx.Client(http2=True)
response = client.get("https://http2.github.io/")
print(response)

HTTP/2 を使用するには、 http2 がサポートされているHTTPX をインストールする必要がありますのでご注意ください。

pip install httpx[http2]

また、HTTPX におけるストリーミングレスポンスのサポートは非常に優れており、レスポンス全体をメモリに読み込まずに大規模なレスポンスやデータストリームを効率的に処理することができます。

こちらは、HTTPX を使用したテキストレスポンスのストリーミング例です。

with httpx.stream("GET", "https://httpbin.org/stream/10") as resp:
   for text in resp.iter_text():
       print(text)

HTTPX にはビルトインのキャッシュ機能はありませんが、 Hishel を併用することができます。

HTTPX は、デフォルトでは HTTP リダイレクトに従いませんが、 follow_redirects パラメータを使用してこれを有効にすることができます。

import httpx

# test http --> https redirect
response = httpx.get('http://github.com/', follow_redirects=True)

非同期処理機能はやや複雑ですが、HTTPX は、 HTTP 通信のためのシンプルなメソッドを提供し、使いやすい同期リクエストのサポートを備えています。このため、初心者にも経験豊富な開発者にも便利なツールと言えるでしょう。また、 内容豊富なドキュメンテーション と、HTTPX 統合用ツールの構築を続ける開発者たちによる活発なコミュニティのおかげで、利用者は増えています。

機能豊富な非同期 HTTP クライアントをお探しの場合は、HTTPX を検討しましょう。

aiohttp

HTTPX と同様に、 aiohttp には HTTP リクエスト用のビルトイン非同期処理サポートがあります。ただし、aiohttp は非同期プログラミング専用に設計されているため、同時およびノンブロッキングのリクエストが必要な場合に能力を発揮します。高パフォーマンスのWebスクレイピングプロジェクトに最適であり、 プロキシで簡単に使用できます

aiohttp を使用して複数の URL を同時にスクレイピングする方法は、こちらをご覧ください。

import asyncio
import aiohttp

async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()    

async def demo_aiohttp():
    print("Testing `aiohttp` library...")
    urls = [
        'https://www.python.org/',
        'http://httpbin.org/get',
        'http://httpbin.org/ip',
    ]
    tasks = [fetch_data(url) for url in urls]
    responses = await asyncio.gather(*tasks)
    for resp_text in responses:
        print(f"Response: {resp_text}")

# async entry point to execute the code      
asyncio.run(demo_aiohttp())

非同期関数 fetch_data(...) は aiohttp.ClientSession() を作成し、指定された URL に GET リクエストを送信します。次に、各 URL のタスクリストを作成し、 asyncio.gather(...)と同時に実行します。すべてのタスクが完了すると、スクレイピングされたデータ(この場合ではレスポンステキスト)が収集され、出力されます。実行は asyncio.run(demo_aiohttp())により開始します。

aiohttp は HTTP リダイレクトを自動処理し、ストリーミングレスポンスをサポートしているため、過剰にメモリを使用せずに大量のファイルやデータストリームを効率的に管理できます。また、優れた柔軟性により、さまざまなサードパーティミドルウェアや拡張機能などとの併用が可能です。

この記事では HTTP クライアント機能のみに焦点を当てていますが、必要に応じ、aiohttp は 開発サーバー としても機能します。

ただし、aiohttp には HTTP/2 のサポートやビルトインのキャッシュ機能はありません。必要に応じ、 aiohttp-client-cache などのライブラリを使用してキャッシュを統合することができます。

aiohttp は、特に初心者にとって、Requests などのシンプルな HTTP クライアントより使いにくく感じられる部分があります。非同期性と追加機能を活用するには、Python の非同期プログラミングを十分に理解する必要があります。人気の面では、GitHubで1.47万のスターを誇り、無数の サードパーティライブラリ がaiohttp のために構築されています。また、開発者向けの包括的な ドキュメンテーション も提供されています。

本格的な非同期サポートをお求めの場合は、aiohttp を検討しましょう。その非同期処理機能は、株価の監視や、選挙などの進行中ライブイベントの追跡など、リアルタイムのデータスクレイピングタスクに最適です。

トップの Python HTTP クライアントの概要については、以下の表をご覧ください。

Requests urllib3 Uplink GRequests HTTPX aiohttp
使いやすさ 初級 初級から中級 中級 初級 中級 中級
自動リダイレクト はい はい はい はい 有効にする必要あり はい
SSLサポート はい はい はい はい はい はい
非同期処理機能 いいえ いいえ いいえ はい はい はい
ストリーミングレスポンス はい はい いいえ はい はい はい
HTTP/2 サポート いいえ いいえ いいえ いいえ はい いいえ
キャッシュサポート 次を経由: requests-cache いいえ 次を経由:requests-cache 次を経由:requests-cache 次を経由: Hishel 次を経由: aiohttp-client-cache

まとめ

この記事では、Requests、urllib3、Uplink、GRequests、HTTPX、aiohttp などの人気 Python HTTP クライアントについて学びました。それぞれのクライアントは、シンプルさや非同期サポート、ストリーミング、そしてHTTP/2 など、独自の機能を備えています。

Requests、Uplink、およびGRequestsはそのシンプルさで知られており、aiohttpやHTTPX は優れた非同期処理機能を提供します。やはり最大の人気を誇るのは Requests ですが、aiohttpとHTTPXも優れた非同期機能により知名度を上げています。それぞれの機能を考慮し、ニーズに合ったものをお選びください。

Webスクレイピングに際しては、アンチボットのバイパスやプロキシの使用など、HTTP クライアント以外にも考慮すべき点が多々あります。 Bright Data を使用することにより、これらの課題を乗り越えることができます。

Bright Dataは、既製のJavaScript関数とテンプレートを提供する Web Scraper IDEや、CAPTCHAやアンチボットをバイパスする機能を備えた Web Unlockerなどのツールにより、Webスクレイピングを非常に簡単にします。Bright Data スクレイピングブラウザ は、 Puppeteerや Playwright、そして Selenium と統合し、多段階のデータ収集を実現します。また、Bright Dataの プロキシネットワーク とサービスでは、さまざまな場所からのアクセスが可能です。これらのツールにより、プロキシの管理やCAPTCHA解決などの複雑なタスクが処理されるため、必要なデータの取得に集中することができます。

今すぐ 無料トライアル を開始して、Bright Dataの機能のすべてを体験しましょう。

クレジットカードは必要ありません