requests vs aiohttp vs httpx: Python HTTPクライアントの深い掘り下げ
Daniel Hayes
Full-Stack Engineer · Leapcell

Python HTTPクライアントライブラリの評価: requests, aiohttp, httpx
豊富な種類のPython HTTPクライアントライブラリの中で、最もよく知られているのはrequests、aiohttp、httpxです。他のサードパーティライブラリの助けなしに、requestsは同期リクエストのみを送信できます。aiohttpは非同期リクエストのみを送信できます。一方、httpxは同期リクエストと非同期リクエストの両方を送信する機能を持っています。
同期リクエストと非同期リクエストの概念
- 同期リクエスト: シングルプロセス、シングルスレッドで実行されるコードでは、リクエストを開始した後、結果が返されるまで次のリクエストを開始することはできません。
- 非同期リクエスト: シングルプロセス、シングルスレッドで実行されるコードでは、リクエストを開始した後、ウェブサイトが結果を返すのを待つ間に、より多くのリクエストを送信できます。
浅い評価: 複数のGETリクエストを送信する際のパフォーマンス比較
テスト結果はネットワーク速度に関連していますが、同じ時間帯に同じネットワークでテストすることで、これらのライブラリ間のパフォーマンスの違いを明らかにすることができます。
requestsでリクエストを送信する
import requests url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def main(): res = requests.get(url, headers=headers) print(res.status_code) if __name__ == '__main__': main()
httpxでリクエストを送信する
同期リクエスト
import httpx url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def main(): res = httpx.get(url, headers=headers) print(res.status_code) if __name__ == '__main__': main()
h ttpxの同期モードは、requestsのコードと最大99%の重複率があります。requests
をhttpx
に置き換えるだけで、コードは正常に実行されます。
非同期リクエスト
import httpx import asyncio url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def main(): async with httpx.AsyncClient() as client: resp = await client.get(url, headers=headers) print(resp.status_code) if __name__ == '__main__': asyncio.run(main())
aiohttpでリクエストを送信する
import asyncio import aiohttp url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def main(): async with aiohttp.ClientSession() as client: async with client.get(url, headers=headers) as resp: print(await resp.text()) print(resp.status) if __name__ == '__main__': asyncio.run(main())
aiohttpのコードは、httpxの非同期モードコードと約90%のコード重複率があります。AsyncClient
をClientSession
に置き換えるだけです。
パフォーマンス テスト: 100件のリクエスト送信にかかる時間
requests
接続を維持しない場合
import time import requests url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def make_request(): resp = requests.get(url, headers=headers) print(resp.status_code) def main(): start = time.time() for _ in range(100): make_request() end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
100件のリクエスト送信にかかる時間: 10.295854091644287
接続を維持する場合
import time import requests session = requests.session() url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def make_request(): resp = session.get(url, headers=headers) print(resp.status_code) def main(): start = time.time() for _ in range(100): make_request() end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
100件のリクエスト送信にかかる時間: 4.679062128067017, 明らかに約6秒高速です。
httpx
同期モード
import time import httpx url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } def make_request(): resp = httpx.get(url, headers=headers) print(resp.status_code) def main(): start = time.time() for _ in range(100): make_request() end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
100件のリクエスト送信にかかる時間: 16.60569405555725
非同期モード: httpx.AsyncClient()を一度だけ作成する
import httpx import asyncio import time url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(client): resp = await client.get(url, headers=headers) print(resp.status_code) async def main(): async with httpx.AsyncClient() as client: start = time.time() tasks = [asyncio.create_task(make_request(client)) for _ in range(100)] await asyncio.gather(*tasks) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': asyncio.run(main())
100件のリクエスト送信にかかる時間: 4.359861135482788
非同期モード: httpx.AsyncClient()を毎回作成する
import httpx import asyncio import time url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(): async with httpx.AsyncClient() as client: resp = await client.get(url, headers=headers) print(resp.status_code) async def main(): start = time.time() tasks = [asyncio.create_task(make_request()) for _ in range(100)] await asyncio.gather(*tasks) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': asyncio.run(main())
100件のリクエスト送信にかかる時間: 6.378381013870239
aiohttp
aiohttp.ClientSession()を一度だけ作成する
import time import asyncio import aiohttp url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(client): async with client.get(url, headers=headers) as resp: print(resp.status) async def main(): async with aiohttp.ClientSession() as client: start = time.time() tasks = [asyncio.create_task(make_request(client)) for _ in range(100)] await asyncio.gather(*tasks) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': asyncio.run(main())
100件のリクエスト送信にかかる時間: 2.235464334487915
aiohttp.ClientSession()を毎回作成する
import time import asyncio import aiohttp url = 'https://www.leapcell.io/' headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' } async def make_request(): async with aiohttp.ClientSession() as client: async with client.get(url, headers=headers) as resp: print(resp.status) def main(): start = time.time() tasks = [asyncio.ensure_future(make_request()) for _ in range(100)] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) end = time.time() print(f'sent 100 requests, cost:{end - start}') if __name__ == '__main__': main()
100件のリクエスト送信にかかる時間: 2.6662471294403076
100件のリクエストの速度ランキング
aiohttp (クライアントを一度だけ作成) > aiohttp (クライアントを毎回作成) > httpx 非同期 (クライアントを一度だけ作成) > requests.session > httpx 非同期 (クライアントを毎回作成) > requests
結論
- 少ないリクエスト数: 送信するリクエストが少ない場合は、requestsまたはhttpxの同期モードを使用すると、コードが最も簡単になります。
- requestsの接続管理: requestsが接続を維持するためにセッションを作成するかどうかで、速度に大きな差が出ます。アンチクローリング対策がない場合、速度のみを追求する場合は、
requests.session()
を使用することをお勧めします。 - 混合リクエスト要件: 大量の要求を送信する必要があり、一部は同期要求を必要とし、一部は非同期要求を必要とする場合、httpxを使用するのが最も便利です。
- 高速リクエスト要件: 大量の要求を送信する必要があり、最速の速度を追求する場合は、aiohttpを使用するのが最適です。
Leapcell: 最高のサーバーレスWebホスティング
最後に、Pythonサービスのデプロイに最適なプラットフォーム**Leapcell**をお勧めします。
🚀 お気に入りの言語で構築
JavaScript、Python、Go、またはRustで簡単に開発できます。
🌍 無制限のプロジェクトを無料でデプロイ
使用した分だけお支払いください—リクエストも料金もありません。
⚡ 従量課金制、隠れたコストなし
アイドル料金なし、シームレスなスケーラビリティ。
🔹 Twitterをフォローしてください: @LeapcellHQ