Python Requests のプロキシ設定・認証・ローテーション完全ガイド
python requests proxy の設定は、ほぼすべてのスクレイピングや監視の仕事における最初の実質的なステップであり、リクエストが黙って自分の IP を返したり、説明のつかない認証エラーを出したりするまでは簡単に見える類のタスクです。このガイドはそれを解決します。読み終えるころには、requests ライブラリを HTTP・HTTPS・SOCKS5 でプロキシ経由に切り替えるコピペ用コード、認証の追加、セッションによる接続の再利用、タイムアウトとリトライの設定、プール経由でのローテーション、IP が実際に変わったかの検証、そして実際に遭遇するエラーの処理まで手に入ります。本記事を通じての誠実なユースケースは正当な業務です。つまり公開データのスクレイピング、価格や SERP のモニタリング、SEO リサーチであって、ログインの向こう側にあるものではありません。
最終更新: 2026年8月24日。この記事にはアフィリエイトリンクが含まれます。アフィリエイト開示 をご覧ください。プロバイダーのプランやエンドポイントは変わるため、依拠する前に必ずプロバイダー自身のサイトで数値を確認してください。
Python requests でプロキシを設定する方法
最小の動作例は、http と https のキーを持つ辞書で、任意のリクエストメソッドの proxies 引数に渡します。
import requests
proxies = {
"http": "http://198.51.100.10:8080",
"https": "http://198.51.100.10:8080",
}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
ここで多くの人がつまずく点が二つあります。第一に、値は素の IP ではなく完全なプロキシ URL です。スキーム (http://)、ホスト、ポートが必要です。第二に、辞書のキーはプロキシのプロトコルではありません。宛先 URL のスキームに基づいてどのプロキシを使うかを選ぶものです。https:// のサイトへのリクエストは https キーを使います。この区別は次のセクションで重要になり、プロキシが「動かない」最も一般的な原因でもあります。
上記のように、必ず timeout を渡してください。プロキシはあなたと対象の間に立つため、死んだプロキシや遅いプロキシは、これがないとスクリプトを永遠にハングさせます。
HTTP・HTTPS・SOCKS5 プロキシ
proxies 辞書のキーは宛先スキームでルーティングし、値のスキームはプロキシ自身が話す言葉です。したがって、HTTPS トラフィックをトンネルできる単一の HTTP プロキシは、両方のキーの下に http:// の値で書きます。これはほとんどのデータセンター系や住宅用の HTTP プロキシがまさにそうです。HTTPS サイトをスクレイピングしているからといって、https:// の値は必要ありません。
SOCKS5 は別です。追加の依存関係が必要です。
pip install "requests[socks]"
そのうえで socks5h:// スキームを使います。末尾の h が重要です。ホスト名をローカルで解決する代わりに DNS 解決をプロキシ経由で行うため、スクレイピングでは自分のマシンの DNS が対象を漏らさないよう、ほぼ常にこれが望ましいのです。
proxies = {
"http": "socks5h://user:pass@proxy-host:1080",
"https": "socks5h://user:pass@proxy-host:1080",
}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
| スキームの接頭辞 | その働き |
|---|---|
http:// | HTTP プロキシ経由でルーティング。HTTPS 対象は CONNECT でトンネルします。ほとんどのプロキシの既定です。 |
socks5:// | SOCKS5 経由でルーティングしますが、DNS は自分のマシン上でローカルに解決します。 |
socks5h:// | SOCKS5 経由でルーティングし、DNS をプロキシ側で解決します (h の意味)。スクレイピングに推奨。 |
Python でのプロキシ認証
ほとんどの有料プロキシはユーザー名とパスワードを要求します。requests では、認証情報は http://user:pass@host:port のようにプロキシ URL へ直接入れます。
proxy_url = "http://my-username:my-password@proxy-host:8080"
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())
ここに、人々の午後をまるごと奪うバグがあります。パスワードに @、:、#、/ のような文字が含まれると、URL のパースが壊れ、明白な理由もなく認証が失敗します。URL を組み立てる前に、urllib.parse.quote でユーザー名とパスワードを URL エンコードしてください。
from urllib.parse import quote
user = "my-username"
password = "p@ss:w#rd" # contains reserved characters
host, port = "proxy-host", 8080
proxy_url = f"http://{quote(user, safe='')}:{quote(password, safe='')}@{host}:{port}"
proxies = {"http": proxy_url, "https": proxy_url}
safe='' 引数は、一部をそのまま残すのではなく、すべての予約文字をエンコードするよう quote に指示します。最初からこうしておけば、「理由もなく認証が失敗する」という幻のバグを追いかけることは二度とありません。それでもプロキシに拒否される場合、注目すべきステータスコードは 407 Proxy Authentication Required です。下のエラーのセクションで扱います。
requests.Session で接続を再利用する
一回きりのリクエストを超えるものには Session を使いましょう。セッションにプロキシを一度設定すれば、そこを通るすべてのリクエストがプロキシ、クッキージャー、下層の TCP 接続を再利用します。
session = requests.Session()
session.proxies = {
"http": proxy_url,
"https": proxy_url,
}
session.get("https://httpbin.org/ip", timeout=10)
session.get("https://httpbin.org/headers", timeout=10) # same proxy, same cookies
これはスクレイピングにおいて二つの意味で重要です。クッキーが保持されるため、ログインやセッション状態がリクエストをまたいで引き継がれます。また接続の再利用は呼び出しごとのハンドシェイクのオーバーヘッドを削り、同じプロキシで何千ものリクエストを行うときには実質的な速度の勝利になります。
環境変数でプロキシを設定する
requests は環境からプロキシ設定を自動で読み取るため、認証情報をコードから完全に切り離しておけます。
export HTTP_PROXY="http://user:pass@proxy-host:8080"
export HTTPS_PROXY="http://user:pass@proxy-host:8080"
大文字と小文字の両方の名前 (http_proxy、https_proxy) が拾われます。これがすっきりする場面についていくつか。
- コードに触れずに環境ごと (dev、staging、production) にプロキシを切り替えるのに向いています。
- 秘密情報をリポジトリではなく
.envファイルや CI のシークレットストアに置いておくのに向いています。 - あるセッションで環境プロキシを無視するには
session.trust_env = Falseを設定します。マシン全体のプロキシが設定されていても、特定のスクリプトだけ直接接続させたり独自のリストを使わせたりしたいときに便利です。
タイムアウトとリトライを追加する
これはほとんどのチュートリアルが飛ばす部分であり、午前3時に落ちるスクリプトと最後まで走りきるスクリプトの違いになります。プロキシは直接接続よりも不安定で、IP は一時的に過負荷になったりレート制限を受けたりするため、ここではリトライが普段以上に重要です。
まずは本物の timeout から始めます。タプルを渡すと接続用と読み取り用のタイムアウトに分かれるので、遅いプロキシは接続で素早く失敗しつつ、遅い応答は最後まで許容されます。
response = requests.get(url, proxies=proxies, timeout=(5, 20)) # (connect, read) seconds
次に、urllib3 の Retry と HTTPAdapter を使ってセッションにリトライ戦略をマウントします。backoff_factor は試行の間隔を空けて、苦しんでいるエンドポイントを叩き続けないようにし、status_forcelist は一時的なサーバーエラーとレート制限のコードでリトライします。
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(
total=5,
backoff_factor=1, # waits 0s, 2s, 4s, 8s... between tries
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST"],
)
session = requests.Session()
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)
session.proxies = {"http": proxy_url, "https": proxy_url}
response = session.get("https://httpbin.org/ip", timeout=(5, 20))
print(response.json())
古い urllib3 のリリースでは、引数名が allowed_methods ではなく method_whitelist です。これに当たったらライブラリを更新してください。Retry は接続エラーと、あなたが列挙したステータスコードを扱う点に注意してください。単にブロックページを返しただけのきれいな 200 はリトライしません。だからこそ、下のローテーションとエラーのセクションが依然として重要なのです。
プールでプロキシをローテーションする
すべてのリクエストを一つの IP から送るのは、レート制限やブロックを受ける最速の方法です。ローテーションはリクエストを多数の IP に分散させます。誠実なアプローチは二つあり、それぞれまったく異なる規模で労力に見合います。まず概念を知りたい場合は、ローテーティングプロキシの仕組み についての解説をご覧ください。
方法 A - random.choice を使った手動プール
静的な IP がひとつかみあるなら、それらをリストに入れてリクエストごとに一つ選びます。random.choice はシンプルなランダム選択を提供します。
import random
import requests
proxy_pool = [
"http://user:pass@ip-1:8080",
"http://user:pass@ip-2:8080",
"http://user:pass@ip-3:8080",
]
targets = ["https://httpbin.org/ip"] * 6
for url in targets:
proxy = random.choice(proxy_pool)
proxies = {"http": proxy, "https": proxy}
try:
r = requests.get(url, proxies=proxies, timeout=10)
print(proxy, "->", r.json()["origin"])
except requests.exceptions.RequestException as exc:
print(f"failed via {proxy}: {exc}")
ランダムではなく厳密なラウンドロビンにしたい場合は、itertools.cycle を使い、毎回 next(proxy_cycle) を呼び出します。方法 A は、すでに所有している小さく固定された IP のセットには問題ありません。その代償として、あなた がリストを保守し、死んだ IP を取り除き、どれが対象にブロックされ始めたかを追跡することになります。
方法 B - プロバイダーのローテーティングエンドポイント
規模が大きくなると、リストの保守をやめて、すべてのリクエストを一つのバックボーンエンドポイントに向け、出口 IP の入れ替えをプロバイダーに任せます。Webshare の実際のローテーティングエンドポイント形式では、ユーザー名に -rotate を付け、すべてをポート80の p.webshare.io へ送ります。
import requests
# One endpoint; the provider hands you a fresh exit IP per request.
proxy = "http://<username>-rotate:<password>@p.webshare.io:80/"
proxies = {"http": proxy, "https": proxy}
for _ in range(6):
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(r.json()["origin"]) # typically a different IP each call
-rotate のサフィックスは呼び出しごとに新しい IP を要求します。複数ステップのフロー (スティッキーセッション) で同じ IP を持続させる必要があるなら、プロバイダーは代わりに数値のセッション ID 形式を用意しています。これらは変わり得るので、依拠する前に正確なエンドポイントとユーザー名の形式を help.webshare.io で確認してください。方法 B の要点は単純です。方法 A の保守の負担をまるごと取り除くことであり、だからこそ数個の IP を超えると勝るのです。
プランに縛られずに上記のスニペットを実際に動かすには、Webshare の無料枠が月あたり10個のプロキシと1GB の帯域幅を提供します (2026年8月時点、サイトで確認を)。ローテーション、認証、リトライのコードを端から端まで試すのに十分です。こちらから無料プロキシを入手 し、上の例に本物の認証情報を貼り付けてください。
自分自身の利用からの小さな正直なメモです。上のスニペットはリクエストごとにローテーションしますが、私のスクレイピングでは実際には毎回新しい IP を取るのではなくスティッキーセッションを固定しており、ジョブが走っている間ずっと同じ出口 IP を保ちました。Webshare のエンドポイント経由でそれを設定するのは簡単で、407 認証エラーや429 レートエラーには当たらなかったため、それらを回避する重いリクエスト間隔は一度も必要ありませんでした。とはいえ結果は対象によって変わるので、ジョブを拡大する前に、自分自身の URL に対して成功率を測ってください。
プロキシの IP を検証する
これらを信頼する前に、プロキシが本当に経路にあることを確認しましょう。IP エコーサービスをプロキシありとなしで叩いて比較します。二つが一致するなら、プロキシは使われていません。
import requests
def show_ip(proxies=None):
r = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=10)
return r.json()["ip"]
print("direct: ", show_ip())
print("via proxy:", show_ip({"http": proxy_url, "https": proxy_url}))
「via proxy」の行が依然として本物の IP を表示する場合、よくある原因は、https:// の URL をリクエストしているのに辞書の https キーが欠けていることです。それでリクエストが静かに直接行ってしまったのです。https のエントリを追加し (設定のセクション参照)、再実行してください。api.ipify.org は https://httpbin.org/ip に差し替えられます。その場合は ip の代わりに origin フィールドを読むだけです。
プロキシのエラーを処理する
リクエストを try/except で包み、特定の例外を捕捉すれば、実行全体をクラッシュさせる代わりに正しく反応できます。
import requests
try:
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
r.raise_for_status()
print(r.json())
except requests.exceptions.ProxyError as exc:
print("proxy dead or blocked:", exc)
except requests.exceptions.ConnectTimeout:
print("proxy did not answer in time")
except requests.exceptions.HTTPError as exc:
print("target returned an error status:", exc.response.status_code)
except requests.exceptions.RequestException as exc:
print("request failed:", exc)
最も具体的なものから最も一般的なものへと捕捉してください。RequestException は基底クラスであり、すべてを受け止める最後に置くべきです。よくある失敗の読み解き方は次のとおりです。
| 症状 | 考えられる原因 | 対処 |
|---|---|---|
| 「Max retries exceeded」/ ProxyError | 死んでいる、間違っている、またはブロックされたプロキシエンドポイント | ホスト/ポートを確認し、別の IP にローテーションし、プロキシが生きているか確かめる |
| HTTP 407 | プロキシ認証が拒否された | ユーザー名/パスワードを修正。quote でパスワードを URL エンコードする |
| HTTP 429 | 対象にレート制限された | 速度を落とし、バックオフを加え、IP をローテーションし、リクエストの間隔を空ける |
| HTTP 403 | 対象がこの IP またはフィンガープリントをブロックした | IP をローテーションし、よりステルス性の高いプロキシ種別を試し、リクエストヘッダーを見直す |
| ConnectTimeout | プロキシは動いているが遅い、または過負荷 | 接続タイムアウトを上げ、リトライし、遅い IP をプールから外す |
責任あるスクレイピング
プロキシは正当な業務のための道具です。公開データのスクレイピング、価格や SERP のモニタリング、広告検証、市場調査、SEO データなどです。きれいに保ちましょう。各サイトの robots.txt と利用規約を尊重し、公開されているデータだけを対象にし、他人のサーバーを劣化させないようリクエスト速度を絞り、ログインの向こう側にあるものからは離れてください。これは一般的な良い慣行であり、法的助言ではありません。自分のプロジェクトと管轄区域に適用される規則を確認してください。これをうまくやるための全体像は、ウェブスクレイピング向けプロキシ のガイドをご覧ください。
よくある質問
requests ライブラリは SOCKS5 に対応していますか?
はい、pip install "requests[socks]" で追加分をインストールすればできます。そのうえで proxies 辞書に socks5h:// の値を使えば、DNS がプロキシ経由で解決されます。
なぜ私のリクエストはまだ本物の IP を表示するのですか?
ほとんどの場合、HTTPS の URL をリクエストしているのに https キーが欠けていて、リクエストが直接行ってしまったからです。http と https の両方のキーが設定されているか確認し、上の検証スニペットを再実行してください。
無料プロキシは Python のスクレイピングに問題ないですか?
コードの学習用なら大丈夫です。実際の仕事では、それらは遅く、短命で、しばしばすでにブロックされていたり安全でなかったりします。有料プロバイダーの本物の無料枠 (限られているが信頼できる IP) のほうが、量に対して支払う前に、まさにそのコードを試すには良い方法です。
リクエストごとに新しい IP を得るにはどうすればいいですか?
random.choice で自分でプールをローテーションする (方法 A) か、<username>[email protected]:80 のようなプロバイダーのローテーティングエンドポイントにすべてのリクエストを向ける (方法 B) かのどちらかで、後者は出口 IP をあなたのために入れ替えます。
同じプロキシ設定を httpx や aiohttp でも使えますか?
概念は引き継がれますが、構文は異なります。httpx と aiohttp は同じ辞書ではなく、プロキシ URL やクライアントごとの設定を受け取ります。コマンドラインについては curl でプロキシを使うガイド を、全体像については ウェブスクレイピング向けプロキシ の概説をご覧ください。
結論
道筋はいつも同じです。proxies 辞書を組み立て、認証を追加し (パスワードを URL エンコードして)、Session を再利用し、タイムアウトと Retry アダプターを設定し、そしてローテーションします。数個の IP なら手動プール、規模が大きくなればプロバイダーのローテーティングエンドポイントです。IP が変わったことを検証し、エラーを捕捉し、各サイトの規則の範囲内で公開データだけをスクレイピングしてください。プロバイダーを選ぶときは、最良のプロキシサービス のまとめが選択肢を正直に比較しています。まず何も使わずに上記すべてを動かすには、Webshare の無料プロキシを入手 し、認証情報をスニペットに落とし込み、規模を拡大する前に各ブロックが自分自身の対象に対して動くことを確認してください。