Proxy w Python Requests: uwierzytelnianie, limity czasu i błędy

11 min

Jak puścić Python Requests przez proxy HTTP albo SOCKS5: słownik proxies, logowanie użytkownik/hasło, zmienne środowiska, limity czasu oraz co naprawdę znaczą ProxyError, 407 i SSLError.

Ten poradnik jest dla programistów, którzy potrzebują, żeby Python Requests szedł przez proxy i nadal działał, gdy proxy się źle zachowuje. Przykłady używają zastępczych hostów i atrap danych logowania. Top Proxy nie sprzedaje adresów IP i nie rozdaje darmowych list; porównujemy usługi, które to robią.

Fragmenty celują w Requests 2.34.2 na PyPI, który potrzebuje Pythona 3.10 albo nowszego. Zachowanie proxy poniżej idzie za dokumentacją zaawansowanego użycia Requests. Kluczowe przypadki ponownie odpaliliśmy 2026-10-14 wobec przypiętej atrapy na loopback (Python 3.14.6, Requests 2.34.2, urllib3 2.8.0, PySocks 1.7.1, weryfikacja TLS włączona). To laboratorium pokazuje wyłącznie zachowanie protokołu, nie prędkość, lokalizacje ani jakość IP dostawcy.

01Minimalny przykład proxy w Python requests

Każda metoda żądania przyjmuje słownik proxies. Klucze to schemat URL celu; wartości to URL proxy:

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())

Na dwóch szczegółach ludzie się najczęściej potykają. Po pierwsze, klucz "https" zwykle wskazuje URL proxy http://. To poprawne: klient prosi proxy o tunel CONNECT, a TLS idzie w środku. https:// tam stawiać tylko wtedy, gdy dostawca kończy TLS na porcie proxy. Po drugie, URL proxy pisać z jawnym schematem (http://, https://, socks5:// albo socks5h://), żeby protokół był jednoznaczny. Requests 2.34.2 dopisuje http:// do zwykłego host:port bez schematu; to nie jest niepoprawny URL proxy. InvalidProxyURL jest rzucane, gdy po sparsowaniu ciąg nadal nie ma hosta, nie dlatego, że pominięto schemat.

httpbin.org/ip zwraca JSON z polem origin, które jest adresem, jaki zobaczył serwer. Porównać to z IP wyjścia albo zakresem, który dostawca dokumentuje dla planu, i zanotować bezpośredni adres na Jaki jest mój adres IP. Sam niezmieniony adres nie dowodzi, że proxy zostało ominięte. Część konfiguracji wychodzi tą samą siecią, w której siedzicie. Jeśli trzeba tylko wiedzieć, czy punkt końcowy odpowiada, użyć sprawdzania proxy albo dłuższego opisu jak sprawdzić, czy proxy działa.

Klucz scheme://hostname kieruje jeden dokładny host inaczej:

proxies = {
    "https": "http://203.0.113.10:8080",
    "https://api.internal.example": "http://198.51.100.5:3128",
}

To dopasowanie hosta jest dokładne. Nie dotyczy każdej nazwy pod tą samą domeną.

02Ustawienia proxy na Session (i pułapka środowiska)

Session ponownie używa połączeń i trzyma domyślne w jednym miejscu:

session = requests.Session()
session.proxies.update(proxies)
session.get("https://httpbin.org/ip", timeout=10)

Dokumentacja Requests ostrzega, że session.proxies może nie zachowywać się tak, jak byście oczekiwali. Wartości tam ustawione mogą być nadpisane przez proxy ze środowiska (cokolwiek zwraca urllib.request.getproxies()). Odziedziczone HTTPS_PROXY potrafi cicho wygrać. Dwa sposoby, żeby wybór był jawny:

# 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 zatrzymuje też czytanie .netrc i zmiennych pakietu CA takich jak REQUESTS_CA_BUNDLE.

To nie teoretyczne ostrzeżenie. W atrapie z 2026-10-14 Session.proxies wskazywało jedno proxy na loopback, a HTTP_PROXY / HTTPS_PROXY inne. Proxy ze środowiska dostało GET. Ta sama sesja, z proxies= przekazanym na wywołaniu, trafiła w proxy sesji. Druga sesja z trust_env = False użyła Session.proxies i zignorowała środowisko. Jeśli skrypt „losowo” używa proxy CI, patrzeć tutaj, zanim przepiszecie URL.

03Zmienne środowiska proxy w Python requests

Jeśli w ogóle nie przekażecie proxies, Requests czyta standardowe zmienne http_proxy, https_proxy, no_proxy i all_proxy. W zwykłym procesie wielkie nazwy też działają. To nie reguła HTTP curl, gdzie http_proxy jest małą zmienną dla HTTP. Jeden wyjątek CPython: jeśli ustawione jest REQUEST_METHOD (proces CGI), urllib.request.getproxies_environment() odrzuca mapowanie HTTP, które przyszło z HTTP_PROXY, żeby nagłówek klienta Proxy: nie mógł go wstrzyknąć. Małe http_proxy nadal może zadziałać.

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

Bez NO_PROXY wywołania do localhost albo usług wewnętrznych mogą iść przez proxy ze środowiska i wisić na limicie czasu. NO_PROXY rządzi tylko proxy zebranymi ze środowiska. Host pasujący do NO_PROXY nadal może iść przez proxy, jeśli przekażecie jawny słownik proxies=, który go pokrywa.

Atrapa potwierdziła obie strony. Przy NO_PROXY=127.0.0.1,localhost i bez argumentu proxies= GET poszedł prosto do lokalnego origin; żadne laboratoryjne proxy go nie zobaczyło. Ten sam host, z jawnym słownikiem proxies=, poszedł przez proxy, które przekazaliśmy. Dlatego błąd „działa w powłoce, nie w workerze” to często dwie różne ścieżki konfiguracji, nie dwie różne biblioteki.

Skąd pochodzi ustawienieDotyczyKiedy tego użyć
Argument proxies= na żądaniuTego jednego wywołania, nadpisując proxy ze środowiskaSkrypty, które muszą użyć konkretnego wyjścia, np. rotacja per żądanie
Session.proxiesKażdego wywołania na tej sesji, chyba że środowisko je nadpiszeDługo żyjące klienty HTTP, najlepiej z trust_env = False
HTTP_PROXY / HTTPS_PROXY / ALL_PROXYKażdego wywołania Requests w procesie, które nadal ufa środowiskuNarzędzia trzecie i CI, gdzie nie da się edytować kodu
NO_PROXYHostów, które pomijają proxy ze środowiska (jawne proxies= nadal może je pokryć)Localhost, endpointy metadanych, wewnętrzne API

04Uwierzytelnianie proxy w Python requests (nazwa użytkownika i hasło)

Większość płatnych proxy potrzebuje logowania. Requests obsługuje HTTP Basic dla proxy przez sam URL, http://user:***@host:port, w słowniku proxies albo w dowolnej ze zmiennych środowiska:

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}

Dane logowania ładować z menedżera sekretów w runtime. Dokumentacja Requests nazywa trzymanie ich w zmiennych środowiska albo w wersjonowanych plikach ryzykiem bezpieczeństwa. Percent-encode zarówno nazwę użytkownika, jak i hasło. Requests odkodowuje obie części wyciągnięte z URL, więc każde @, :, / albo # w którejkolwiek musi przejść przez quote(..., safe=""). Inaczej URL może się źle sparsować, a proxy nigdy nie zobaczy danych, które chcieliście wysłać. Po dekodowaniu HTTP Basic user-id nie może zawierać dwukropka (RFC 7617 sekcja 2); hasło może. Percent-encoding dwukropka w nazwie użytkownika nie czyni tego legalnym: Requests odkodowuje go z powrotem do dwukropka. Dodatkowy niezakodowany dwukropek w userinfo jest parsowany jako początek hasła (alice:bob:secret staje się użytkownikiem alice i hasłem bob:secret).

Flagi kraju albo sticky-session w nazwie użytkownika (user-country-us-session-abc123) to składnia dostawcy, nie cecha Requests. Same z siebie nie dają geografii ani konta.

W starszych odpowiedziach bywa też requests.auth.HTTPProxyAuth. Dokłada nagłówek Proxy-Authorization do obiektu żądania. W teście na loopback uwierzytelnił zwykłe żądania HTTP (200), ale żądanie HTTPS padło z ProxyError wspominającym 407. To pasuje do nagłówka jadącego na żądaniu, a nie na CONNECT, które proxy sprawdza. Preferować dane logowania w URL.

Requests obsługuje wyłącznie Basic auth proxy. Proxy NTLM albo Kerberos/Negotiate potrzebują biblioteki uwierzytelniania trzeciej strony albo lokalnego proxy-pomocnika.

Jeśli pytanie, które wpisaliście, brzmiało tylko „co znaczy 407?”, ten status ma własną stronę: 407 Proxy Authentication Required. Ten artykuł zostaje przy tym, jak Requests to pokazuje.

05Proxy SOCKS5 w requests

Obsługa SOCKS to opcjonalny dodatek, który ciągnie PySocks (1.7.1 na PyPI w momencie pisania):

python -m pip install "requests[socks]"

Potem URL SOCKS działają w tym samym słowniku proxies, razem z danymi logowania:

proxies = {
    "http": "socks5h://user:***@203.0.113.10:1080",
    "https": "socks5h://user:***@203.0.113.10:1080",
}

Zwracać uwagę na h. Przy socks5:// rozwiązywanie DNS dzieje się na waszej maszynie i do proxy idzie tylko wynikowy IP. Przy socks5h:// proxy rozwiązuje nazwę hosta. To ten sam podział, którego używa curl.

Atrapa uczyniła to widocznym na https://example.com/. Oba schematy zwróciły 200. Serwer SOCKS zapisał ATYP 1 (IPv4, 172.66.147.243) dla socks5:// i ATYP 3 (nazwa hosta example.com) dla socks5h://. Wywołania HTTP do 127.0.0.1 tej różnicy nie pokazują, bo IP już jest adresem. Używać socks5h, gdy nie chcecie, żeby lokalny resolver widział lookupy. Porównanie protokołów w języku katalogu: SOCKS5 a HTTP.

Schemat URL proxyPotrzebny dodatekKto rozwiązuje DNSTypowe użycie
http://BrakProxy, dla nazwy hosta, o którą prosicieWiększość płatnych bram HTTP(S)
https://BrakProxyDostawcy, którzy kończą TLS na porcie proxy
socks5://requests[socks]Wasza maszynaProxy SOCKS, gdzie lokalny DNS jest akceptowalny
socks5h://requests[socks]ProxyProxy SOCKS, lookupy DNS zostają po stronie proxy

Niepewność, jakim protokołem mówi punkt końcowy? Puścić go przez sprawdzanie proxy.

06Limit czasu proxy w Python requests

Requests nie ma domyślnego limitu czasu, więc zacięte proxy może wisieć na wywołaniu minutami. Zawsze przekazywać timeout, najlepiej jako krotkę (connect, read):

r = requests.get(url, proxies=proxies, timeout=(3.05, 27))

Wartość connect pokrywa połączenie TCP, co przy proxy znaczy połączenie do proxy. Dokumentacja sugeruje wartość nieco powyżej wielokrotności 3, żeby zgrać się z retransmisją TCP. Wartość read to maksymalna przerwa między bajtami od serwera, nie pułap całkowitego czasu pobrania. Opóźnienie zależy od dostawcy, wyjścia i celu, więc wartość read ustawiać z czasów odpowiedzi zmierzonych na rzeczywistym punkcie końcowym.

Przydatna pułapka: gdy samo proxy nie przyjmuje połączenia TCP na czas, Requests 2.34.2 rzuciło ProxyError opakowujące ConnectTimeoutError urllib3, nie najwyższego poziomu ConnectTimeout. W atrapie timeout=(1.0, 5) wobec 192.0.2.1:8080 dało ten wrapper. Po połączeniu z działającym proxy wolny origin z timeout=(3.05, 1.0) rzucił ReadTimeout. Łapać ProxyError i ReadTimeout przed ogólnym ConnectionError i oglądać komunikat albo __cause__, jeśli trzeba odróżnić „proxy nigdy nie odpowiedziało” od „proxy odpowiedziało, a potem strona umilkła”.

Dla przejściowych awarii montować adapter z ograniczonymi ponowieniami, zamiast pisać pętlę ręcznie:

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))

Ponowienia kodów statusu podążają za allowed_methods. Domyślny zbiór urllib3 2.8.0 to GET, HEAD, PUT, DELETE, OPTIONS i TRACE; POST jest wyłączony, dopóki go nie dodacie. Włączać ponowne wysłanie tylko dla operacji, które wolno wysłać dwa razy. total=3 ogranicza próby ponowienia, nie czas zegarowy. Gdy odpowiedź ma Retry-After, urllib3 czeka na to opóźnienie, jeśli respect_retry_after_header jest true (domyślnie).

Ponowienia nie naprawią 407, złego CA ani trust_env wskazującego złą bramę. Pomagają tylko wtedy, gdy awaria naprawdę jest przejściowa.

07Błędy proxy w Python requests: co znaczy każdy wyjątek

Kolejność bloków except ustawiać ostrożnie. ProxyError, SSLError i ConnectTimeout wszystkie dziedziczą po ConnectionError, a ConnectTimeout jest też Timeout. Najpierw łapać te konkretne:

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
ObjawPrawdopodobna przyczynaCo spróbować
ProxyError bez 407 w komunikacieNic nie przyjmuje połączeń na tym hoście/porcie, proxy leży, blokada sieci/listy dozwolonych albo connect timeout do proxySprawdzić host i port, potem przetestować punkt końcowy w sprawdzaniu proxy; dane logowania nie są pierwszym podejrzanym
ProxyError wspominający 407 na URL HTTPSCONNECT nie niósł danych, które proxy przyjęło: nic nie wysłano, ustawiono tylko przez HTTPProxyAuth, źle zakodowano, zły format albo plan nieaktywnyWstawić zakodowane dane do URL proxy; potwierdzić format nazwy użytkownika i status planu
Odpowiedź ze statusem 407 na URL HTTPProxy prosi o dane logowania; na żądaniu wysłanym bez nich to po prostu wyzwanieDodać dane do URL proxy; jeśli już tam były, sprawdzić kodowanie i format
Odpowiedź ze statusem 401Cel, nie proxy, chce uwierzytelnianiaNaprawić własne auth witryny; część proxy zadziałała
Requests ignoruje wasze Session.proxiesProxy ze środowiska je nadpisująPrzekazywać proxies= per wywołanie albo ustawić trust_env = False
InvalidSchema: Missing dependencies for SOCKS supportNie zainstalowano requests[socks]python -m pip install "requests[socks]"
SSLError: CERTIFICATE_VERIFY_FAILEDProxy przechwytujące albo laboratoryjny/self-signed certyfikat, któremu domyślny pakiet nie ufaWskazać verify= albo REQUESTS_CA_BUNDLE na plik CA tego proxy
Wisi w nieskończonośćNie ustawiono timeoutZawsze przekazywać krotkę (connect, read)
origin nie zgadza się z oczekiwanym wyjściemProxy nie zastosowane dla tego schematu, NO_PROXY pasowało przy poleganiu na proxy ze środowiska, albo inna trasa niż zakładaliścieUstawić oba klucze http i https; przy proxy ze środowiska sprawdzić NO_PROXY; porównać z udokumentowanym IP/zakresem wyjścia dostawcy

Co pokazał lokalny test

Zaobserwowane wyniki testów Requests z kontrolowanej lokalnej atrapy proxy

Te wzorce odpaliliśmy wobec testowego proxy na loopback 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) o ile nie zaznaczono inaczej, weryfikacja TLS włączona. Atrapa użytkownika demo; hasło zawierało interpunkcję i było percent-encoded w URL, potem zredagowane w logach. Sprawdzenia HTTPS używały https://example.com/ plus lokalnego serwera z laboratoryjnym CA. Wiersze poniżej to zapisane obserwacje z tej atrapy, nie liczba zaliczonych testów automatycznych. To pokazuje wyłącznie zachowanie protokołu.

PrzypadekCel HTTPCel HTTPS
Brak danych logowania proxyodpowiedź 407ProxyError wspominający 407
Percent-encoded dane w URL proxy200200 (example.com i laboratoryjny TLS z verify= ustawionym na laboratoryjne CA)
Tylko HTTPProxyAuth200ProxyError wspominający 407
Port proxy zamkniętyProxyError, bez 407nie testowane
Poprawne auth proxy, witryna zwraca 401odpowiedź 401 od witrynynie testowane
Domyślne CA kontra laboratoryjny samopodpisany certyfikatn/dSSLError: CERTIFICATE_VERIFY_FAILED; 200 po zaufaniu laboratoryjnemu CA
Session.proxies kontra HTTP_PROXYProxy ze środowiska dostało GETnie testowane
proxies= na wywołaniu, środowisko ustawioneSesja/otwarte proxy dostało GETnie testowane
trust_env = Falseużyte Session.proxies; środowisko zignorowanenie testowane
NO_PROXY pasuje do hostaProsto do origin; brak trafienia proxynie testowane
Jawne proxies= na hoście z NO_PROXYNadal przez proxynie testowane
Connect timeout do proxyProxyError opakowujące ConnectTimeoutErrornie testowane
Read timeout przez działające proxyReadTimeoutnie testowane

SOCKS5 z zakodowanymi danymi zwróciło 200 dla HTTP i dla https://example.com/. Podział DNS: socks5:// dostarczyło do proxy adres IPv4; socks5h:// dostarczyło nazwę hosta.

Certyfikaty, proxy przechwytujące i verify

Korporacyjna brama inspekcji TLS albo lokalne proxy przechwytujące podpisuje HTTPS własnym urzędem certyfikacji, którego Requests odrzuca. Zaufać temu CA jawnie, zamiast wyłączać weryfikację:

r = requests.get(
    url,
    proxies={"https": "http://127.0.0.1:8080"},
    verify="/path/to/proxy-ca.pem",
    timeout=10,
)

albo export REQUESTS_CA_BUNDLE=/path/to/ca.pem dla całego procesu. Eksport DER najpierw przekonwertować do PEM. Laboratoryjny samopodpisany origin odtworzył tę samą klasę awarii: domyślne verify=True rzuciło SSLError (certificate verify failed: self-signed certificate); to samo żądanie z verify= wskazującym laboratoryjne CA zwróciło 200. verify=False sprawia, że Requests przyjmuje dowolny certyfikat i ignoruje niezgodność nazwy hosta, co rozbraja TLS dla wszystkiego, co ten klient wysyła. To nie jest normalna naprawa proxy, które „nie działa”.

08Rotacyjne proxy w Pythonie

Wielu komercyjnych dostawców rotuje wyjście za jednym hostem bramy. Zależnie od taryfy wyjście może zmieniać się per żądanie albo w interwale sesji, a identyfikator sesji w nazwie użytkownika zwykle przypina jedno wyjście na jakiś czas, zamiast dawać każdemu wywołaniu nowe. Te reguły to ustawienia dostawcy, więc sprawdzić ich dokumentację. Sticky a rotacyjne proxy opisuje język produktu. Jeśli sami zarządzacie listą punktów końcowych, wybierać jeden per żądanie i przekazywać go przez 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))

Przekazywać proxy per wywołanie, bo proxy ze środowiska mogą nadpisać Session.proxies. Typ wyjścia to osobny wybór: datacenter, rezydenckie albo mobilne. Cena i to, jak witryna celu traktuje ruch, zależą od taryfy, celu i reputacji IP, nie od samej etykiety typu. Proxy samo z siebie nie nadaje geografii ani uprawnienia do konta.

Zanim kupicie, potwierdzić, że wybrany plan obsługuje protokół (HTTP albo SOCKS5) i metodę auth (login albo lista dozwolonych IP), których potrzebuje kod. Automatyzacja przeglądarki to inny stos; konteksty Playwright są w Proxy w Playwright. Dostawcy w naszym katalogu z bramami proxy:

Bright Data — proxy rezydenckie i datacenter
Bright Data — proxy rezydenckie i datacenter4.41442

Bright Data to duża sieć proxy do zbierania danych: IP rezydenckie, mobilne, ISP i datacenter w około 195 krajach. Ruch rezydencki można płacić na bieżąco bez subskrypcji, a adresy datacenter i ISP przychodzą w pakietach od 10 IP. Dostęp rezydencki i mobilny wymaga weryfikacji tożsamości.

10 krajów
5,00 USD
za 1 GB
Oxylabs — proxy rezydenckie i datacenter
Oxylabs — proxy rezydenckie i datacenter4.0771

Oxylabs sprzedaje proxy rezydenckie, mobilne, ISP i datacenter w jednej subskrypcji miesięcznej od $30. Płatności: karty, przelew, AliPay, PayPal.

10 krajów
0,45 USD
za 1 GB
SOAX — proxy rezydenckie i mobilne
SOAX — proxy rezydenckie i mobilne3.8218

SOAX sprzedaje rotacyjne proxy rezydenckie i mobilne na wspólnej puli kredytów, z datacenter i ISP w tych samych planach. Builder od $200/mies. + VAT (200 kredytów); ruch Tier 1 to $3/GB na Builderze.

85 krajów
3,00 USD
za 1 GB
Decodo (Smartproxy) — proxy rezydenckie i datacenter
Decodo (Smartproxy) — proxy rezydenckie i datacenter4.22118

Decodo (dawniej Smartproxy) sprzedaje proxy rezydenckie i datacenter. Rezydenckie: $4/GB bez planu miesięcznego albo pakiety miesięczne od $3.75/GB za 3 GB. Płatności: karty, PayPal, Alipay, Google/Apple Pay, krypto (z ograniczeniami).

83 kraje
0,38 USD
za 1 GB

Jak użyć proxy z Python requests?

Przekazać słownik taki jak {"http": "http://host:port", "https": "http://host:port"} jako argument proxies. Klucze to schemat URL celu; wartości to URL proxy. Na tych wartościach preferować jawny schemat, żeby nie pomieszać HTTP i SOCKS. Zwykły host:port bez schematu w Requests 2.34.2 dostaje http:// z przodu; nie jest odrzucany jako InvalidProxyURL.

Jak dodać nazwę użytkownika i hasło do proxy requests?

Wstawić je do URL proxy (http://user:***@host:port), percent-encoding obu części przez urllib.parse.quote(value, safe=""), i ładować je z menedżera sekretów zamiast hardcodować. Po dekodowaniu HTTP Basic user-id nie może zawierać dwukropka (RFC 7617); hasło może. Nie polegać na percent-encoded dwukropku, żeby wstawić dwukropek do nazwy użytkownika.

Dlaczego Python requests zwraca 407 Proxy Authentication Required?

Proxy chce danych, których nie dostało albo nie przyjęło. Na żądaniu wysłanym bez danych 407 to po prostu wyzwanie. W przeciwnym razie sprawdzić kodowanie, format nazwy użytkownika i status planu. Cele HTTPS rzucają ProxyError wspominający 407; cele HTTP zwracają odpowiedź 407. ProxyError bez 407, na przykład z zamkniętego portu, wskazuje na łączność. HTTPProxyAuth w naszym laboratorium uwierzytelnił HTTP, ale nie HTTPS CONNECT.

Czy requests obsługuje proxy SOCKS5?

Tak, po python -m pip install "requests[socks]". Użyć socks5h://, żeby proxy rozwiązywało nazwy hostów, albo socks5://, żeby rozwiązywać je lokalnie. W laboratorium socks5 dostarczyło adres IPv4 dla example.com, a socks5h dostarczyło nazwę hosta.

Czy requests używa zmiennej środowiska HTTP_PROXY?

Tak, gdy nie przekażecie proxies: czyta http_proxy, https_proxy, all_proxy i no_proxy. W zwykłym procesie wielkie nazwy też działają. Jeśli ustawione jest REQUEST_METHOD (CGI), urllib ignoruje HTTP_PROXY dla HTTP, żeby nagłówek Proxy nie mógł go wstrzyknąć; małe http_proxy nadal może zadziałać. To nie reguła curl wyłącznie z małymi literami dla HTTP. Proxy ze środowiska mogą nadpisać Session.proxies, więc przekazywać proxies per wywołanie albo ustawić session.trust_env = False. NO_PROXY pomija tylko proxy ze środowiska; jawny słownik proxies= nadal może pokryć te hosty.

Jaki timeout ustawić dla requests przez proxy?

Zawsze ustawić jakiś; Requests nie ma domyślnego. Zacząć od krotki takiej jak (3.05, 27) i dopasować po zmierzeniu czasów odpowiedzi przez rzeczywisty punkt końcowy proxy. Connect timeout do proxy może wyjść jako ProxyError opakowujące ConnectTimeoutError; cichy origin po połączeniu to ReadTimeout.

Czy ustawić verify=False, jeśli proxy psuje HTTPS?

Nie. Zaufać CA przechwytującego proxy przez verify= albo REQUESTS_CA_BUNDLE. verify=False przyjmuje dowolny certyfikat i ignoruje niezgodność nazwy hosta. W laboratorium samopodpisany origin oblał domyślną weryfikację i przeszedł dopiero po przekazaniu laboratoryjnego CA do verify=.