0
0

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】httpxとasyncioで並列に非同期リクエストを実行する

Posted at

はじめに

Python で HTTP リクエストを送信するライブラリは requests が有名です。

しかし requests は同期 I/O のため、asyncio との相性が悪いです。

デフォルトのトランスポートアダプタが実装されている場合、Requestsは非ブロッキングIOを一切提供しません。Response.content レスポンス全体がダウンロードされるまで、このプロパティはブロックされます。より細かい粒度が必要な場合は、ライブラリのストリーミング機能( ストリーミングリクエストを参照)を使用することで、レスポンスを一度に少量ずつ取得できます。ただし、これらの呼び出しは依然としてブロックされます。

ブロッキングIOの使用に不安がある場合は、RequestsとPythonの非同期フレームワークを組み合わせたプロジェクトが数多くあります。優れた例としては、requests-threads、grequests、requests-futures、httpxなどがあります。

引用元:

この記事では、requests ライクな API を持ちつつ、同期・非同期の両方に対応したモダンな HTTP クライアントである httpx を紹介します。

サンプルコード

以下はコルーチン(async/await)でリクエストを送信する方法です。
エントリーポイントで asyncio.run を使用して async 関数を実行します。
httpx の GET リクエストで await しています。

import asyncio

import httpx

class Fetcher:
    """非同期HTTPリクエストクラス"""

    def __init__(self):
        self.client = self._create_client()

    def _create_client(self):
        """httpxクライアントを作成する"""
        client = httpx.AsyncClient()
        return client

    async def close_connection(self):
        """クライアントの接続を閉じる"""
        await self.client.aclose()

    async def fetch(self, url):
        """指定されたURLにGETリクエストを送信する"""
        response = await self.client.get(url)

        print(f"Status Code: {response.status_code}")

        response.raise_for_status()

async def main():
    url = "https://httpbin.org/get"
    fetcher = Fetcher()

    # GETリクエストを実行
    await fetcher.fetch(url)

    # クライアントの接続を閉じる
    await fetcher.close_connection()

if __name__ == "__main__":
    asyncio.run(main())

※ サンプルコードでは エラーを raise していますがキャッチしていません。以下は例外クラスの参考リンクです。

asyncio と httpx を組み合わせる

以下は 5 つの GET リクエストを並列で行います。/delay/3 にリクエストを送り、ブロッキングが発生していないことを確認します。

import asyncio
import logging

import httpx

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - [%(levelname)s] - %(message)s',
)
logging.getLogger("httpx").setLevel(logging.INFO)
logger = logging.getLogger(__name__)

class Fetcher:
    def __init__(self):
        self.client = self._create_client()

    def _create_client(self):
        """httpxクライアントを作成する"""
        client = httpx.AsyncClient()
        return client

    async def close_connection(self):
        """クライアントの接続を閉じる"""
        await self.client.aclose()

    async def fetch(self, url):
        """指定されたURLにGETリクエストを送信する"""
        response = await self.client.get(url)

        response.raise_for_status()

async def main():
    url = "https://httpbin.org/delay/3"
    fetcher = Fetcher()

    # GETリクエストタスクをスケジューリング
    tasks = [
        asyncio.create_task(fetcher.fetch(url))
        for _ in range(5)
    ]

    # タスクを並列実行
    await asyncio.gather(*tasks)

    await fetcher.close_connection()

if __name__ == "__main__":
    asyncio.run(main())

実行結果

レスポンスを得るまで 3 秒待機するエンドポイントへのリクエストですが、ほぼ同時刻にリクエストが行われており、並列でリクエストが実行されていることが確認できます。

2025-08-09 21:18:52,416 - [INFO] - HTTP Request: GET https://httpbin.org/delay/3 "HTTP/1.1 200 OK"
2025-08-09 21:18:52,540 - [INFO] - HTTP Request: GET https://httpbin.org/delay/3 "HTTP/1.1 200 OK"
2025-08-09 21:18:52,777 - [INFO] - HTTP Request: GET https://httpbin.org/delay/3 "HTTP/1.1 200 OK"
2025-08-09 21:18:52,870 - [INFO] - HTTP Request: GET https://httpbin.org/delay/3 "HTTP/1.1 200 OK"
2025-08-09 21:18:53,083 - [INFO] - HTTP Request: GET https://httpbin.org/delay/3 "HTTP/1.1 200 OK"

クライアント

requests ライブラリには requests.Session() によりセッションを作成できます。httpx では httpx.AsyncClient が相当します。これを利用することでタイムアウトやヘッダーの設定が可能です。

class Fetcher:
    def __init__(self):
        self.headers = {
            "User-Agent": (
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/58.0.3029.110 Safari/537.3"
            )
        }
        self.client = self._create_client()

    def _create_client(self):
        client = httpx.AsyncClient(
            headers=self.headers,
            timeout=httpx.Timeout(5.0, 10.0)
        )
        return client

参考

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?