Python requestsのプロキシ: 認証、タイムアウト、エラー
PythonのRequestsをHTTPまたはSOCKS5プロキシ経由で出す方法です。proxiesのdict、ユーザー名とパスワード、環境変数、タイムアウト、そしてProxyError、407、SSLErrorの実際の意味を扱います。
PythonのRequestsをプロキシ経由で出し、プロキシが荒れたときも動き続ける必要がある開発者向けの案内です。例はプレースホルダのホストとダミーの資格情報です。Top ProxyはIPを売りません。無料の一覧も渡しません。売っている供給元を比べます。
スニペットはPyPIのRequests 2.34.2向けです。Python 3.10以上が必要です。以下のプロキシの動きは、Requestsのadvanced usageに従います。主要なケースは2026-10-14に、固定したループバックのフィクスチャ(Python 3.14.6、Requests 2.34.2、urllib3 2.8.0、PySocks 1.7.1、TLS検証オン)で再実行しました。この実験が示すのはプロトコルの動きだけです。供給元の速度、拠点、IPの品質ではありません。
01最小のPython requestsプロキシ例
どのリクエストメソッドも proxies dictを受けます。キーは対象URLのスキーム、値はプロキシURLです。
import requests
proxies = {
"http": "http://203.0.113.10:8080",
"https": "http://203.0.113.10:8080",
}
r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=(3.05, 27))
print(r.status_code, r.json())
つまずきは二つです。第一に、"https" キーはたいてい http:// のプロキシURLを指します。それで正しいです。クライアントはプロキシへ CONNECT トンネルを頼み、TLSはその中で走ります。プロキシのポートで供給元がTLSを終端するときだけ、そこに https:// を使ってください。第二に、プロキシURLには明示的なスキーム(http://、https://、socks5://、socks5h://)を書いて、プロトコルを曖昧にしないでください。Requests 2.34.2は、スキーム無しの普通の host:port の前に http:// を付けます。それは無効なプロキシURLではありません。InvalidProxyURL が上がるのは、解析のあともホストが無いときです。スキームを省略したからではありません。
httpbin.org/ip は origin 欄のあるJSONを返します。サーバーが見たアドレスです。契約で供給元が書いた出口IPまたはレンジと比べ、直接のアドレスは自分のIPで控えてください。アドレスが変わらないことだけでは、プロキシを迂回した証明にはなりません。座っているのと同じ網から出る構成もあります。端点が応答するかどうかだけ知りたいなら、プロキシチェッカーか、長いプロキシが動くかの確認を使ってください。
scheme://hostname のキーは、そのホストだけ別経路にします。
proxies = {
"https": "http://203.0.113.10:8080",
"https://api.internal.example": "http://198.51.100.5:3128",
}
ホストの一致は完全一致です。同じドメインのすべての名前には効きません。
02Sessionのプロキシ設定(と環境の罠)
Session は接続を再利用し、既定を一箇所に置きます。
session = requests.Session()
session.proxies.update(proxies)
session.get("https://httpbin.org/ip", timeout=10)
Requestsの文書は、session.proxies が期待どおりに動かないことがあると警告しています。そこに置いた値は、環境のプロキシに上書きされることがあります(urllib.request.getproxies() が返すもの)。引き継いだ HTTPS_PROXY が、黙って勝ちます。選択を明示する方法は二つです。
# Option 1: pass proxies on every call (the documented fix)
session.get(url, proxies=proxies, timeout=10)
# Option 2: stop the session from reading the environment
session.trust_env = False
session.proxies.update(proxies)
trust_env = False は、セッションが .netrc や REQUESTS_CA_BUNDLE のようなCAバンドル変数を読むのも止めます。
紙の警告ではありません。2026-10-14のフィクスチャでは、Session.proxies が一つのループバックプロキシを指し、HTTP_PROXY / HTTPS_PROXY が別のプロキシを指していました。GETを受けたのは環境のプロキシです。同じセッションで呼び出しに proxies= を渡すと、セッションのプロキシに当たりました。trust_env = False の二番目のセッションは Session.proxies を使い、環境を無視しました。スクリプトが「ときどき」CIのプロキシを使うなら、URLを書き換える前にここを見てください。
03Python requestsのプロキシ環境変数
proxies をまったく渡さないとき、Requestsは標準の http_proxy、https_proxy、no_proxy、all_proxy を読みます。普通のプロセスでは、大文字の名前も動きます。curlのHTTP規則ではありません。curlではHTTP向けの変数は小文字の http_proxy です。CPythonの例外が一つあります。REQUEST_METHOD が付いているとき(CGIプロセス)、urllib.request.getproxies_environment() は HTTP_PROXY 由来のHTTP対応を落とします。クライアントの Proxy: ヘッダーで注入できないようにするためです。小文字の http_proxy はまだ効きます。
export HTTP_PROXY="http://203.0.113.10:8080"
export HTTPS_PROXY="http://203.0.113.10:8080"
export NO_PROXY="localhost,127.0.0.1,.internal.example"
python my_script.py
NO_PROXY が無いと、localhost や内部サービスへの呼び出しが環境プロキシを通り、タイムアウトすることがあります。NO_PROXY が支配するのは、環境から拾ったプロキシだけです。明示的な proxies= dictがそのホストを覆うなら、NO_PROXY に一致してもプロキシ経由になります。
フィクスチャは両方を確認しました。NO_PROXY=127.0.0.1,localhost で proxies= 引数なしのとき、GETはローカルオリジンへ直行し、実験のプロキシはどちらも見ませんでした。同じホストに明示的な proxies= dictを付けると、渡したプロキシを通りました。シェルでは動いてワーカーでは動かないバグが、別ライブラリではなく別の設定経路であることが多い理由です。
| 設定の出所 | 適用範囲 | 使うとき |
|---|---|---|
リクエストの proxies= 引数 | その一回。環境プロキシを上書きする | 特定の出口が必要なスクリプト。例: リクエストごとのローテーション |
Session.proxies | そのセッションのすべての呼び出し。環境が上書きしない限り | 長く動くクライアント。理想は trust_env = False |
HTTP_PROXY / HTTPS_PROXY / ALL_PROXY | 環境をまだ信頼するプロセス内の、すべてのRequests呼び出し | コードを直せない第三者ツールとCI |
NO_PROXY | 環境プロキシを飛ばすホスト(明示的な proxies= はまだ覆える) | localhost、メタデータ端点、内部API |
04Python requestsのプロキシ認証(ユーザー名とパスワード)
有料プロキシの多くはログインが要ります。Requestsは、URLそのものを通してプロキシのHTTP Basic認証に対応します。http://user:***@host:port を proxies dict、またはどの環境変数へも置けます。
import os
from urllib.parse import quote
user = quote(os.environ["PROXY_USER"], safe="")
password = quote(os.environ["PROXY_PASS"], safe="")
host = "gate.example-provider.com:7000"
proxy_url = f"http://{user}:{password}@{host}"
proxies = {"http": proxy_url, "https": proxy_url}
資格情報は実行時にシークレットマネージャから読んでください。Requestsの文書は、環境変数や版管理されたファイルへ置くことをセキュリティリスクと呼んでいます。ユーザー名とパスワードの両方をパーセントエンコードしてください。RequestsはURLから取った両方をアンクォートするので、どちらかに @、:、/、# があるなら quote(..., safe="") を通す必要があります。そうしないとURLの解析がずれ、渡したつもりだった資格情報をプロキシは見ません。デコードのあと、HTTP Basicのuser-idにコロンは入れられません(RFC 7617 第2節)。パスワードには入れられます。ユーザー名のコロンをパーセントエンコードしても合法にはなりません。Requestsがコロンへ戻すからです。userinfoの余分なエンコード無しコロンは、パスワードの開始として解析されます(alice:bob:secret はユーザー alice、パスワード bob:secret になります)。
ユーザー名の国やスティッキーセッションの旗(user-country-us-session-abc123)は供給元の構文であり、Requestsの機能ではありません。それだけで地理や口座は得られません。
古い回答では requests.auth.HTTPProxyAuth も見ます。リクエストオブジェクトへ Proxy-Authorization ヘッダーを足します。ループバック試験では、素のHTTPリクエストは認証できました(200)。HTTPSリクエストは407に触れる ProxyError で失敗しました。ヘッダーが、プロキシが見る CONNECT ではなくリクエストに乗っている動きと合います。資格情報はURLへ入れてください。
Requestsが扱うプロキシ認証はBasicだけです。NTLMやKerberos/Negotiateのプロキシには、第三者の認証ライブラリか、ローカルのヘルパープロキシが要ります。
入力した問いが「407は何か」だけなら、そのステータスには専用ページがあります。407 Proxy Authentication Required。この記事は、Requestsがそれをどう出すかに留まります。
05requestsのSOCKS5プロキシ
SOCKS対応は任意の追加で、PySocksを引きます(執筆時点のPyPIは1.7.1)。
python -m pip install "requests[socks]"
そのあと、同じ proxies dictでSOCKS URLが動きます。資格情報も含みます。
proxies = {
"http": "socks5h://user:***@203.0.113.10:1080",
"https": "socks5h://user:***@203.0.113.10:1080",
}
h に注意してください。socks5:// ではDNS解決は自分のマシンで行われ、できたIPだけがプロキシへ行きます。socks5h:// では、プロキシがホスト名を解決します。curlと同じ分かれです。
フィクスチャは https://example.com/ でそれを見せました。どちらのスキームも200を返しました。SOCKSサーバーは、socks5:// ではATYP 1(IPv4、172.66.147.243)、socks5h:// ではATYP 3(ホスト名 example.com)を記録しました。127.0.0.1 へのHTTP呼び出しでは差は見えません。IPはすでにアドレスだからです。ローカルのリゾルバに照会を見せたくないときは socks5h を使ってください。カタログの言葉でのプロトコル比較は、SOCKS5とHTTPプロキシを見てください。
| プロキシURLのスキーム | 必要な追加 | DNSを解決する側 | 典型的な用途 |
|---|---|---|---|
http:// | なし | プロキシ(要求したホスト名) | ほとんどの有料HTTP(S)ゲートウェイ |
https:// | なし | プロキシ | プロキシのポートでTLSを終端する供給元 |
socks5:// | requests[socks] | 自分のマシン | ローカルDNSでよいSOCKSプロキシ |
socks5h:// | requests[socks] | プロキシ | 照会をプロキシ側に残すSOCKSプロキシ |
端点が何を話すか分からないときは、プロキシチェッカーに通してください。
06Python requestsのプロキシタイムアウト
Requestsには既定のタイムアウトがありません。止まったプロキシは、呼び出しを何分も吊るすことがあります。必ず timeout を渡してください。理想は (connect, read) のタプルです。
r = requests.get(url, proxies=proxies, timeout=(3.05, 27))
connectの値はTCP接続を覆います。プロキシがあるときは、プロキシへの接続です。文書は、TCP再送に合わせるため、3の倍数より少し大きい値を勧めています。readの値は、サーバーからのバイト間の最大間隔であり、ダウンロード全体の上限ではありません。遅延は供給元、出口、対象に依存するので、readは実際の端点で測った応答時間から決めてください。
押さえておくべき点です。プロキシ自身がTCP接続を時間内に受けないとき、Requests 2.34.2はトップレベルの ConnectTimeout ではなく、urllib3の ConnectTimeoutError を包んだ ProxyError を上げました。フィクスチャでは、192.0.2.1:8080 に対する timeout=(1.0, 5) が、その包みを出しました。動くプロキシが接続したあと、遅いオリジンに timeout=(3.05, 1.0) を付けると ReadTimeout が上がりました。一般の ConnectionError より先に ProxyError と ReadTimeout を捕捉し、「プロキシが答えなかった」と「プロキシは答えたが、そのあとサイトが黙った」を分けるなら、メッセージまたは __cause__ を見てください。
一時的な失敗には、手でループを書かず、上限付きの再試行アダプタを載せてください。
from requests.adapters import HTTPAdapter
from urllib3.util import Retry
retry = Retry(total=3, backoff_factor=0.5, status_forcelist=[429, 502, 503, 504])
session.mount("https://", HTTPAdapter(max_retries=retry))
session.mount("http://", HTTPAdapter(max_retries=retry))
ステータスの再試行は allowed_methods に従います。urllib3 2.8.0の既定集合はGET、HEAD、PUT、DELETE、OPTIONS、TRACEです。POSTは足さない限り除外されます。二度送っても安全な操作にだけ、再送を有効にしてください。total=3 が上限にするのは再試行回数であり、壁時計の時間ではありません。応答に Retry-After があり、respect_retry_after_header が真(既定)なら、urllib3はその遅れを待ちます。
再試行では、407も、壊れたCAも、間違ったゲートウェイを指す trust_env も直りません。失敗が本当に一時的なときだけ助けます。
07Python requestsのプロキシエラー: 各例外の意味
except の順に気を付けてください。ProxyError、SSLError、ConnectTimeout はすべて ConnectionError のサブクラスで、ConnectTimeout は Timeout でもあります。具体的なものを先に捕捉します。
from requests.exceptions import (
ProxyError, SSLError, ConnectTimeout, ReadTimeout,
ConnectionError, InvalidProxyURL, RequestException,
)
try:
r = session.get(url, proxies=proxies, timeout=(3.05, 27))
r.raise_for_status()
except ProxyError as e:
... # proxy unreachable, CONNECT refused, or connect-timeout to the proxy; check the message for 407
except SSLError as e:
... # certificate problem; fix trust, don't disable verification
except ConnectTimeout:
... # could not connect in time (more often seen without a proxy)
except ReadTimeout:
... # connected, but the server went quiet
except InvalidProxyURL:
... # malformed proxy URL
except ConnectionError:
... # DNS failure, reset, other network errors
except RequestException:
... # anything else from requests
| 症状 | ありそうな原因 | 試すこと |
|---|---|---|
メッセージに407が無い ProxyError | そのホスト/ポートで接続を受けるものが無い、プロキシ停止、網/許可リストの遮断、またはプロキシへの接続タイムアウト | ホストとポートを確認し、端点をプロキシチェッカーで試す。資格情報は最初の容疑ではない |
HTTPS URLで407に触れる ProxyError | プロキシが受けた CONNECT に、受け入れる資格情報が無かった。未送信、HTTPProxyAuth だけ、エンコード誤り、形式誤り、またはプラン無効 | エンコードした資格情報をプロキシURLへ入れる。ユーザー名の形式とプラン状態を確認する |
| HTTP URLでステータス407の応答 | プロキシが資格情報を求めている。資格情報なしで送った要求では、ただのチャレンジ | プロキシURLへ資格情報を足す。すでに入っているなら、エンコードと形式を見る |
| ステータス401の応答 | プロキシではなく宛先が認証を求めている | サイト自身の認証を直す。プロキシ側は動いた |
Requestsが Session.proxies を無視する | 環境プロキシが上書きしている | 呼び出しごとに proxies= を渡すか、trust_env = False にする |
InvalidSchema: Missing dependencies for SOCKS support | requests[socks] 未導入 | python -m pip install "requests[socks]" |
SSLError: CERTIFICATE_VERIFY_FAILED | 傍受プロキシ、または既定バンドルが信頼しない実験/自己署名証明書 | verify= または REQUESTS_CA_BUNDLE を、そのプロキシのCAファイルへ向ける |
| 無限に止まる | timeout 未設定 | 必ず (connect, read) タプルを渡す |
origin が想定した出口と一致しない | そのスキームにプロキシが当たっていない、環境プロキシ頼みのときに NO_PROXY が一致した、または想定と違う経路 | http と https の両方のキーを置く。環境プロキシなら NO_PROXY を見る。供給元が書いた出口IP/レンジと比べる |
ローカル試験が示したこと

これらの型を、2026-10-14にループバックの試験プロキシへ当てました。Python 3.14.6、Requests 2.34.2、urllib3 2.8.0、certifi 2026.07.22、PySocks 1.7.1、特記がなければ timeout=(3.05, 10)、TLS検証オン。ダミーユーザーは demo。パスワードは句読点を含み、URLではパーセントエンコードし、ログでは伏せました。HTTPSの確認は https://example.com/ と、実験CA付きのローカルサーバーです。下の行は、そのフィクスチャから取った観測であり、自動試験の合格数ではありません。プロトコルの動きだけを示します。
| ケース | HTTP対象 | HTTPS対象 |
|---|---|---|
| プロキシ資格情報なし | 407応答 | 407に触れる ProxyError |
| プロキシURLのパーセントエンコードした資格情報 | 200 | 200(example.com と、verify= を実験CAにした実験TLS) |
HTTPProxyAuth のみ | 200 | 407に触れる ProxyError |
| プロキシのポートが閉じている | ProxyError、407なし | 未試験 |
| 正しいプロキシ認証、サイトが401を返す | サイトからの401応答 | 未試験 |
| 既定CA対実験の自己署名証明書 | 該当なし | SSLError: CERTIFICATE_VERIFY_FAILED。実験CAを信頼したあと200 |
Session.proxies 対 HTTP_PROXY | 環境プロキシがGETを受けた | 未試験 |
呼び出しの proxies=、環境あり | セッション/開いたプロキシがGETを受けた | 未試験 |
trust_env = False | Session.proxies を使用。環境は無視 | 未試験 |
NO_PROXY がホストに一致 | オリジンへ直接。プロキシは未通過 | 未試験 |
NO_PROXY ホストへの明示的な proxies= | それでもプロキシ経由 | 未試験 |
| プロキシへの接続タイムアウト | ConnectTimeoutError を包む ProxyError | 未試験 |
| 動くプロキシ越しの読み取りタイムアウト | ReadTimeout | 未試験 |
エンコードした資格情報付きのSOCKS5は、HTTPと https://example.com/ の両方で200を返しました。DNSの分かれ: socks5:// はIPv4アドレスをプロキシへ渡し、socks5h:// はホスト名を渡しました。
証明書、傍受プロキシ、verify
法人のTLS検査ゲートウェイや、ローカルの傍受プロキシは、HTTPSを自前の認証局で再署名します。Requestsはそれを拒みます。検証を切るのではなく、そのCAを明示的に信頼してください。
r = requests.get(
url,
proxies={"https": "http://127.0.0.1:8080"},
verify="/path/to/proxy-ca.pem",
timeout=10,
)
またはプロセス全体なら export REQUESTS_CA_BUNDLE=/path/to/ca.pem。DERの書き出しは先にPEMへ変換します。実験の自己署名オリジンも、同じ種類の失敗を再現しました。既定の verify=True は SSLError(certificate verify failed: self-signed certificate)を上げました。同じ要求で verify= を実験CAへ向けると200が返りました。verify=False は、Requestsに任意の証明書を受けさせ、ホスト名の不一致も無視させます。そのクライアントが送るすべてのTLSを無効にします。「動かない」プロキシの普通の直しではありません。
08Pythonでのローテーションプロキシ
商用供給元の多くは、一つのゲートウェイホストの裏で回してくれます。料金によっては、出口はリクエストごと、またはセッション間隔で変わります。ユーザー名のセッションIDは、たいていしばらく一つの出口を固定し、毎回新しい出口を渡すわけではありません。規則は供給元の設定なので、文書を見てください。製品の言葉はスティッキーとローテーションのプロキシにあります。端点の一覧を自分で持つなら、リクエストごとに一つ選び、proxies= で渡してください。
import itertools
pool = itertools.cycle(
[
"http://user:***@203.0.113.10:8080",
"http://user:***@203.0.113.11:8080",
]
)
for url in urls:
p = next(pool)
session.get(url, proxies={"http": p, "https": p}, timeout=(3.05, 27))
プロキシは呼び出しごとに渡してください。環境プロキシは Session.proxies を上書きできます。出口の種類は別の選択です。データセンター、レジデンシャル、モバイル。価格と、対象サイトがトラフィックをどう扱うかは、料金、対象、IPの評判に依存します。種類のラベルだけでは決まりません。プロキシは、それだけで地理や口座の資格を与えません。
買う前に、選ぶプランがコードに必要なプロトコル(HTTPまたはSOCKS5)と認証方式(ログインまたはIP許可リスト)に対応していることを確認してください。ブラウザ自動化は別のスタックです。PlaywrightのコンテキストはPlaywrightのプロキシを見てください。カタログでプロキシゲートウェイがある供給元です。

Bright Dataはデータ収集向けの大規模プロキシ網です。レジデンシャル、モバイル、ISP、データセンターのIPが約195か国にあります。レジデンシャルトラフィックは定期契約なしの従量払いができ、データセンターとISPアドレスは10 IPからのパックです。レジデンシャルとモバイルの利用には本人確認が必要です。

Oxylabsはレジデンシャル、モバイル、ISP、データセンタープロキシを、月$30からのひとつの月次契約で売っています。支払いはカード、電信送金、AliPay、PayPalです。
Pythonのrequestsでプロキシを使うには?
requestsのプロキシへユーザー名とパスワードを足すには?
Pythonのrequestsが407 Proxy Authentication Requiredを返すのはなぜ?
requestsはSOCKS5プロキシに対応しますか?
requestsはHTTP_PROXY環境変数を使いますか?
プロキシ経由のrequestsには、どのタイムアウトを設定すべきですか?
プロキシがHTTPSを壊すならverify=Falseにすべきですか?
関連記事
レジデンシャルプロキシとは何か、どう動くか
レジデンシャルプロキシは一般向けISPのアドレスから出ます。プール、スティッキーセッション、サイトから見えるもの、購入前に供給元へ聞くことを説明します。
4分2026年のスクレイピング向けプロキシ: 購入チェックリスト
2026年のスクレイピング購入は、供給元ではなく相手から始めます。出自、セッション、地理、課金、本番前の実地試験のチェックリストです。
5分スティッキーとローテーション: セッション制御の仕組み
スティッキーとローテーション: リクエストごととタイマーのローテーションの動き、スティッキーが新しいIPに勝つとき、CookieとIP変更の関係、セッションIDの自分での試験。
8分



