はじめに
先日、Qiitaで「Python Webスクレイピング厳選10ライブラリ」という記事を読んでいたところ、httpxという見慣れないライブラリを見つけました。
PythonでHTTPリクエストを投げるといえば、requestsライブラリを思い浮かべる人も少なくはないでしょう。私もその一人でした。
しかし、Webの世界は日進月歩。asyncioを使った非同期処理や、高速なプロトコルであるHTTP/2が当たり前になってきた現代において、requestsだけでは少し物足りなさを感じる場面が増えてきました。
気になってhttpxを調べてみたところ、これがrequestsの使いやすさを引き継ぎつつ、現代的なWeb開発のニーズに応える素晴らしいライブラリだと分かりました。
そこでこの記事では、requestsに慣れ親しんだ方に向けて、httpxがなぜ「次世代HTTPクライアント」なのか、その魅力とrequestsとの違いを、具体的なコードを交えながら徹底解説します。
httpxとは?
httpxは、一言で言えば 「requestsの使いやすさを引き継いだ、モダンで強力なHTTPクライアント」 です。
公式サイト
requestsと非常に似たAPIを持っているため、requestsユーザーなら学習コストはほとんどかかりません。それでいて、現代のWeb開発に不可欠な機能を網羅しています。
httpxのここがスゴい!ベスト5
数あるhttpxの魅力の中から、特に「これはrequestsよりイケてる!」と感じる点を5つ厳選してご紹介します。
1. 同期・非同期どっちもOK! async/awaitにネイティブ対応 ✨
これがhttpx最大の目玉機能です。
requestsは同期処理にしか対応していませんが、httpxは同期APIと非同期APIの両方を提供しています。
▼ 同期リクエスト (requestsとほぼ同じ!)
import httpx
r = httpx.get('https://www.example.com/')
print(r.status_code)
# 200
▼ 非同期リクエスト (async/awaitが使える!)
import httpx
import asyncio
async def main():
async with httpx.AsyncClient() as client:
r = await client.get('https://www.example.com/')
print(r.status_code)
asyncio.run(main())
# 200
FastAPIなどの非同期Webフレームワークを使っている場合、requestsをそのまま使うとイベントループをブロックしてしまい、非同期のメリットを殺してしまいます。
httpxなら、AsyncClientを使うだけで、他の処理をブロックしない効率的な非同期HTTPリクエストを簡単に実装できます。
2. HTTP/2に標準対応で高速化 🚀
httpxはHTTP/1.1だけでなく、HTTP/2もサポートしています。
HTTP/2は、1つのTCP接続で複数のリクエストを同時に処理できる「多重化」という仕組みにより、多数のリソースをやり取りする際のパフォーマンスを大幅に向上させます。
有効にするのも簡単。追加パッケージをインストールするだけです。
pip install httpx[http2]
あとはClientやAsyncClientを使えば、サーバーが対応している場合に自動的にHTTP/2が利用されます。
# Clientを使えば、裏側で自動的にHTTP/2が使われる(サーバーが対応していれば)
with httpx.Client(http2=True) as client:
r = client.get("https://www.python-httpx.org/")
print(r.http_version)
# "HTTP/2"
3. タイムアウトがデフォルトで設定されていて安全 ✅
requestsを使ったことがある人なら、リクエストが返ってこずにプログラムが固まってしまった経験があるかもしれません。requestsはデフォルトでタイムアウトが設定されていないためです。
一方、httpxはすべてのネットワーク操作にデフォルトで5秒のタイムアウトが設定されています。
import httpx
try:
# このURLはレスポンスが非常に遅い
response = httpx.get("http://httpbin.org/delay/10")
except httpx.ReadTimeout:
print("タイムアウトしました!`requests`なら永遠に待ってたかも…")
この「フェイルセーフ」な設計思想により、意図しない無限待機を防ぎ、より堅牢なアプリケーションを構築できます。もちろん、タイムアウト値は柔軟にカスタマイズ可能です。
4. テストがめちゃくちゃ書きやすい 🧪
httpxは、FlaskやDjangoのようなWSGIアプリケーション、FastAPIやStarletteのようなASGIアプリケーションに対して、ネットワークを介さずに直接リクエストを送ることができます。
これがテストを書くときに絶大な威力を発揮します。
from fastapi import FastAPI
import httpx
# テスト対象のFastAPIアプリ
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
# テストコード
def test_app():
# ASGIトランスポートを使ってアプリに直接リクエスト
with httpx.Client(app=app, base_url="http://testserver") as client:
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"Hello": "World"}
test_app()
実際のサーバーを起動する必要がないため、テストの実行が高速かつシンプルになります。
5. 完全な型アノテーションで開発体験が最高 💯
httpxのコードベースは、すべて型ヒント(Type Annotation)で注釈されています。
これにより、VSCodeなどのIDEで強力なコード補完や型チェックの恩恵を受けることができ、開発効率とコードの品質が格段に向上します。
requestsからの移行ガイド (APIの違い)
httpxはrequestsと非常によく似ていますが、より安全で明確な設計思想に基づいたいくつかの違いがあります。移行の際に押さえておきたい主なポイントをまとめました。
Clientオブジェクトを使おう (requests.Session)
requestsで接続の再利用やCookieの永続化のためにSessionオブジェクトを使ったように、httpxではClient(非同期の場合はAsyncClient)を使います。
httpx.get()のようなトップレベル関数はリクエストごとに新しい接続を確立するため、効率が悪くなります。パフォーマンス向上のためにも、Clientを使うことを強く推奨します。
# requests
session = requests.Session()
session.headers.update({'x-foo': 'bar'})
session.get(url1)
session.get(url2)
# httpx
with httpx.Client() as client:
client.headers.update({'x-foo': 'bar'})
client.get(url1)
client.get(url2)
リダイレクトは自動で追跡されない ⚠️
requestsはデフォルトでリダイレクトを追跡しますが、httpxは追跡しません。これは、意図しないネットワーク呼び出しを防ぐための設計です。
リダイレクトを許可する場合は、明示的にfollow_redirects=Trueを指定します。
# requests (デフォルトでリダイレクトされる)
r = requests.get("http://github.com")
print(r.url) # "https://github.com/"
# httpx (デフォルトではリダイレクトされない)
r = httpx.get("http://github.com")
print(r.status_code) # 301
print(r.headers['location']) # "https://github.com/"
# リダイレクトを許可する場合
r = httpx.get("http://github.com", follow_redirects=True)
print(r.url) # "https://github.com/"
ストリーミングレスポンスの扱い
requestsではstream=Trueを使いましたが、httpxではwith httpx.stream(...)というコンテキストマネージャを使います。これにより、リソースのクローズが確実に行われ、コードが視覚的にも分かりやすくなります。
# requests
with requests.get(url, stream=True) as r:
for chunk in r.iter_content():
...
# httpx
with httpx.stream("GET", url) as r:
for chunk in r.iter_bytes():
...
その他の主な違い
| 機能 | requests |
httpx |
備考 |
|---|---|---|---|
| リクエストボディ |
data / json
|
data / json / content
|
生のbytes/strはcontentが推奨 |
| 成功チェック |
r.is_ok (200 OK) |
r.is_success (2xx全般) |
is_okの曖昧さを解消 |
| エンコーディング | latin1 |
utf-8 |
httpxの方がモダンな標準 |
| 内部ライブラリ | urllib3 |
httpcore |
httpxは独自の非同期対応ライブラリ |
まとめ: httpxはこんな人におすすめ!
httpxは、requestsの優れた点を継承しつつ、現代的な開発要件に応えるための強力な武器となります。
特に、以下のような方にはhttpxへの移行を強くおすすめします。
- FastAPIなどの非同期フレームワークを使っている人
- 大量のI/Oバウンドな処理を高速化したい人
- HTTP/2の恩恵を受けたい人
- タイムアウトなどでより堅牢なコードを書きたい人
requestsに慣れているが、次のステップに進みたい人
requestsが今すぐ不要になるわけではありません。しかし、新しいプロジェクトを始めるなら、httpxを第一候補として検討する価値は間違いなくあります。
インストール
最後にインストール方法です。pipで簡単にインストールできます。
# 基本インストール
pip install httpx
# HTTP/2, CLIなど全部入りでインストール
pip install httpx[http2,cli]
ぜひhttpxを試して、快適なHTTPクライアントライフを送ってください!