Python でプロキシをローテーション:requests、httpx、aiohttp(2026 年ガイド)

2026年6月2日公開 · 約10分で読めます

Python で大規模にスクレイピング、クロール、または自動化を行うと、遅かれ早かれ、ターゲットサイトはすべてのリクエストが 1 つの IP から来ていることに気づき、あなたを締め出します。Python でのプロキシローテーションは、トラフィックを多数の IP アドレスに分散させ、どの 1 つの IP もレート制限に引っかかったり BAN を食らったりしないようにします。本ガイドでは、requestshttpxaiohttp の正確なコードと、ローテーションゲートウェイとマネージド IP プールのどちらを選ぶべきかを示します。

以下のすべてを左右する横断的な判断が 2 つあります。1 つ目:ローテーション vs スティッキーセッション — 1 リクエストごとに新しい IP にするか、複数ステップのフローのために 1 つの IP を保持するか。2 つ目:residential vs datacenter IP — プロキシタイプの判断マトリクスを参照してください。この 2 つを正しく押さえれば、コードは簡単な部分です。

ローテーションの 2 つの方法

1. ゲートウェイローテーション(推奨)。 単一のエンドポイントに接続すると、新しい接続ごとにプロバイダーが新鮮な出口 IP を渡してくれます。管理すべきリストもなく、削除すべき死んだ IP もありません。JIBAO のダイナミック residential プールはこの方式で動作します:同じホストとポートで、リクエストごとに新しい IP です。

2. 自己管理の IP リスト。 host:port エントリのリストを保持し、リクエストごとに 1 つを選びます。コントロールは増えますが、ヘルスチェック、リトライ、BAN 追跡を自分で担うことになります。既知の安定したアドレスが必要なときに専用 datacenter IP と組み合わせて役立ちます。

requests でのローテーション

最もシンプルなケース — あなたの代わりにローテーションしてくれるゲートウェイ経由で 1 つのリクエストをルーティングします。socks5h:// を使ってください(末尾の h は DNS がプロキシ側で解決されることを意味し、名前解決の漏洩を防ぎます):

import requests

# JIBAO rotating residential gateway: a new exit IP per connection
PROXY = "socks5h://USERNAME:[email protected]:10001"

proxies = {"http": PROXY, "https": PROXY}

for _ in range(5):
    r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)
    print(r.json()["origin"])   # a different IP each loop

requests に SOCKS5 を話させる必要がありますか?エクストラをインストールしてください:pip install "requests[socks]"。HTTP プロキシエンドポイントを好む場合は、スキームを http:// に切り替えてください — 残りは同一です。

自分の IP リストからのローテーション

import random
import requests

PROXY_POOL = [
    "socks5h://USERNAME-country-us:[email protected]:10001",
    "socks5h://USERNAME-country-uk:[email protected]:10001",
    "socks5h://USERNAME-country-de:[email protected]:10001",
]

def fetch(url):
    proxy = random.choice(PROXY_POOL)
    return requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)

resp = fetch("https://example.com")
print(resp.status_code)

1 つの IP を保持しなければならないときのスティッキーセッション

ログインフロー、カート、ページネーション結果は、タスクの途中で IP が変わると壊れます。ユーザー名にセッショントークンを追加して IP を固定し、同じトークンを再利用することで、その寿命の間は同じ出口 IP を保ちます:

import requests

SESSION_ID = "task-0001"
PROXY = f"socks5h://USERNAME-session-{SESSION_ID}:[email protected]:10001"

s = requests.Session()
s.proxies = {"http": PROXY, "https": PROXY}

s.post("https://example.com/login", data={"u": "me", "p": "secret"})
s.get("https://example.com/dashboard")   # same IP, session intact

httpx でのローテーション

httpx は HTTP/2 とネイティブ async を備えたモダンなクライアントを提供します。新しいバージョンでは単一の proxy= 引数を取ることに注意してください:

import httpx

PROXY = "socks5h://USERNAME:[email protected]:10001"

with httpx.Client(proxy=PROXY, timeout=30) as client:
    for _ in range(5):
        print(client.get("https://httpbin.org/ip").json()["origin"])

httpx での SOCKS サポートには pip install "httpx[socks]" が必要です。HTTP/2 を使うには、クライアントに http2=True を追加してください — これによりトラフィックが本物のブラウザにより近く見えるようになり、TLS フィンガープリントの一致とよく組み合わさります。

aiohttp での並行ローテーション

高スループットには、多数のリクエストを一度に発射します。ゲートウェイを通る各接続が独自の出口 IP を得るため、並行性とローテーションが同時に実現します:

import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector

PROXY = "socks5://USERNAME:[email protected]:10001"

async def fetch(url):
    connector = ProxyConnector.from_url(PROXY)
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as r:
            return await r.text()

async def main():
    urls = ["https://httpbin.org/ip"] * 20
    results = await asyncio.gather(*(fetch(u) for u in urls))
    print(f"fetched {len(results)} pages")

asyncio.run(main())

SOCKS コネクタは pip install aiohttp_socks でインストールします。各リクエストが新しいプロキシ接続を開くように、タスクごとに新鮮なコネクタを作ってください。

本当に役立つリトライロジック

ローテーションは、失敗を新鮮な IP でリトライしてこそ報われます。指数的にバックオフし、試行ごとにセッショントークンをローテーションしてください:

import requests
from time import sleep

def fetch_with_retry(url, max_retries=4):
    for attempt in range(max_retries):
        proxy = f"socks5h://USERNAME-session-r{attempt}:[email protected]:10001"
        try:
            r = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)
            if r.status_code in (403, 429):
                raise requests.HTTPError(f"blocked: {r.status_code}")
            r.raise_for_status()
            return r.text
        except requests.RequestException:
            sleep(2 ** attempt)        # 1s, 2s, 4s, 8s
    raise RuntimeError(f"failed after {max_retries} tries: {url}")

ローテーションが機能していることを検証する

大きな実行の前に、IP が実際に変わっていることを確認してください。echo エンドポイントを数回叩いて、IP が異なることをチェックします。TLS フィンガープリントが正体を暴いていないことも確認するには、JIBAO の無料の JA3/TLS フィンガープリントチェッカーに対してリクエストを実行してください — ローテーションする IP でも、Python のフィンガープリントが丸わかりであれば依然としてブロックされます。

ベストプラクティス

ローテーションが盤石になると、次にぶつかる壁はたいてい IP ではなくフィンガープリントです。クリーンな residential IP でも依然として 403 が返るなら、curl_cffi で TLS フィンガープリントを回避する方法と、完全な Cloudflare 回避レシピを読んでください。

ローテーション residential プロキシを手に入れる

500MB の無料トラフィックと、リクエストごとに新しい IP を渡すローテーション residential ゲートウェイを手に入れましょう。

無料トライアルを始める

すべてのIP製品に対応 · 膨大なノードプールをいつでも利用可能

今すぐ登録して、チャージ額の最大 100% をキャッシュバック

新規ユーザーは登録時に500MBを獲得、さらに初回チャージにボーナスが付きます。期間限定オファーです。