This Python Requests proxy guide covers requests proxy authentication, a reusable Python proxy session, proxy timeout handling in Python, SOCKS5 DNS behavior, and a controlled way to test a proxy in Python. For browser-driven workflows, see the Playwright proxy guide. For command-line diagnostics, use the cURL proxy setup and testing guide.
To use a proxy with Python Requests, pass a proxy URL for both the http and https keys, keep credentials outside source code, set explicit connect and read timeouts, and verify the route against an endpoint you are authorized to call. Use a Session when several requests share headers, cookies, or connection pools.
The small code sample is easy; the operational details are where most failures happen. A working Python Requests proxy setup must distinguish the proxy connection from the destination response, protect credentials, preserve TLS verification, and handle DNS, timeouts, and destination rules deliberately. The examples below use environment variables so the same script can run locally, in a job runner, or on a server without committing a password to the repository.
Install Requests and define the proxy safely
Install Requests in a virtual environment and keep the dependency version visible in your project lock file. For ordinary HTTP or HTTPS proxy endpoints, the base package is enough. Do not paste a production password into a tutorial, source file, exception message, or shared terminal history.
import os
from urllib.parse import quote
import requests
proxy_host = os.environ["PROXY_HOST"]
proxy_port = os.environ["PROXY_PORT"]
proxy_user = quote(os.environ["PROXY_USER"], safe="")
proxy_pass = quote(os.environ["PROXY_PASS"], safe="")
proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
response = requests.get(
os.environ["APPROVED_TEST_URL"],
proxies=proxies,
timeout=(5, 20),
)
response.raise_for_status()
print(response.status_code)
The https dictionary key describes the destination scheme. An HTTP proxy URL can still carry HTTPS traffic by opening a tunnel to the destination. Include the scheme in every proxy URL; the official Requests advanced usage documentation requires it and documents the proxies argument.
Percent-encoding the username and password avoids treating characters such as @, :, or / as URL separators. It does not make the value safe to print. Environment variables are convenient, but they are not a secret vault: use the secret mechanism provided by your operating system, container platform, or CI service. The deeper proxy authentication guide compares credentials with IP allowlisting.
Use a Session for repeated requests
A requests.Session persists cookies and common headers and uses connection pooling. That can reduce repeated connection setup when several requests go to the same host. A session does not grant permission to send more traffic, and it does not make destination limits disappear.
import os
import requests
PROXIES = {
"http": os.environ["HTTP_PROXY_URL"],
"https": os.environ["HTTPS_PROXY_URL"],
}
with requests.Session() as session:
session.headers.update({
"User-Agent": "AcmeStatusMonitor/1.0 ([email protected])"
})
for url in os.environ["APPROVED_URLS"].split(","):
response = session.get(
url.strip(),
proxies=PROXIES,
timeout=(5, 20),
)
response.raise_for_status()
print(url, response.status_code, response.elapsed.total_seconds())
Passing proxies on each call is intentionally explicit. Requests warns that values stored only in session.proxies can be replaced by proxy settings discovered from the environment. Explicit per-request configuration makes the route easier to review. If a project intentionally uses environment proxy variables, document that decision and test NO_PROXY behavior for internal services.
Use timeouts that explain failures
Requests does not impose a default timeout, so a network call can wait much longer than a scheduled job expects. A tuple such as timeout=(5, 20) separates the connection timeout from the read timeout. The first value covers establishing a connection; the second limits how long Requests waits between bytes after the connection is established.
Do not turn every timeout into an immediate retry storm. Record the stage, apply a small retry budget only to operations that are safe to repeat, and add backoff. A POST that creates an order is not equivalent to a read-only status check. When reliability matters, classify DNS errors, proxy connection errors, authentication failures, TLS failures, read timeouts, and HTTP status responses separately. The proxy troubleshooting sequence shows where each class sits in the request path.
import os
import requests
try:
response = requests.get(
os.environ["APPROVED_TEST_URL"],
proxies={
"http": os.environ["HTTP_PROXY_URL"],
"https": os.environ["HTTPS_PROXY_URL"],
},
timeout=(5, 20),
)
response.raise_for_status()
except requests.exceptions.ProxyError:
print("Proxy connection or authentication failed")
except requests.exceptions.ConnectTimeout:
print("Connection stage timed out")
except requests.exceptions.ReadTimeout:
print("Connected, but the response stalled")
except requests.exceptions.SSLError:
print("TLS verification failed; inspect the certificate path")
except requests.exceptions.HTTPError as exc:
print("Destination returned", exc.response.status_code)
Notice what the example does not do: it does not print the proxy URL, and it does not set verify=False. Requests verifies HTTPS certificates by default. Disabling verification can hide a real certificate problem and expose the connection to interception. If an approved corporate proxy performs TLS inspection, install the correct trusted certificate bundle instead of suppressing validation.
Configure SOCKS5 and decide where DNS resolves
SOCKS support is optional. Install it with python -m pip install 'requests[socks]', then use a SOCKS URL in the proxy map. The scheme changes DNS behavior: socks5:// resolves the destination hostname on the client, while socks5h:// asks the proxy side to resolve it. That distinction matters for privacy tests, split DNS, and destinations available only through a specific resolver.
import os
import requests
proxy_url = os.environ["SOCKS_PROXY_URL"] # socks5h://host:port
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.get(
os.environ["APPROVED_TEST_URL"],
proxies=proxies,
timeout=(5, 20),
)
response.raise_for_status()
print(response.status_code)
Choose the scheme from the actual DNS requirement, not from the assumption that one option is universally safer. Read the HTTP versus SOCKS5 comparison before changing protocols, and verify the final route with the application itself.
Test the route without leaking secrets
A status code of 200 proves only that one request returned successfully. A useful test checks the observed egress address, expected location, DNS behavior when relevant, TLS validation, latency, and repeated stability. Run the smallest controlled test against a destination you own, an approved diagnostic endpoint, or a service whose terms allow the request.
- Run once without the proxy and record the baseline source address and latency.
- Run once through the proxy and confirm that the expected egress address is observed.
- Repeat a small number of times and record connection, TLS, status, and read failures separately.
- Redact credentials, authorization headers, cookies, and full query strings from logs.
- Test the real application path before increasing concurrency.
The guide on how to check whether a proxy works explains the difference between connectivity and suitability. If you are selecting a plan rather than debugging code, start with the proxy selection checklist and compare the current private proxy service only after the workload is defined.
Respect robots.txt, APIs, and rate limits
A proxy changes the route; it does not change the destination’s rules. Prefer a published API when one exists. For automated crawling, read the site’s robots policy and applicable terms before fetching. RFC 9309 standardizes how crawlers match user-agent groups and Allow or Disallow rules, but robots.txt is not a substitute for authorization, privacy review, or rate-limit handling.
Identify the client honestly, cache results when appropriate, apply conservative concurrency, and stop when the destination returns a rate-limit or access response. The responsible web data collection guide covers minimization, retention, and review. These controls improve reliability as much as compliance: a small, observable workflow is easier to debug than an aggressive job that mixes several failure causes.
A practical production checklist
- Pin and review the Requests dependency.
- Load proxy secrets from an approved secret store or protected environment.
- Encode credential components before building a URL.
- Pass both HTTP and HTTPS proxy keys when both destination schemes are used.
- Set connect and read timeouts explicitly.
- Keep TLS verification enabled.
- Use a Session for repeated related requests and close it deterministically.
- Choose
socks5orsocks5hfrom the DNS requirement. - Redact secrets and personal data from logs.
- Respect authorization, robots guidance, APIs, and destination rate limits.
Frequently asked questions
How do I set a proxy in Python Requests?
Create a dictionary with http and https keys and pass it through the proxies argument. Include the scheme in each proxy URL and set an explicit timeout.
How do I authenticate a Requests proxy?
For HTTP Basic proxy authentication, credentials can be encoded in the proxy URL. Keep them outside source code, percent-encode credential components, and never print the complete URL.
Should I use a Requests Session with a proxy?
Use a Session when several related requests share cookies, headers, or connection pools. Passing the proxy map explicitly on each request makes routing easier to audit when environment proxy variables also exist.
What is the difference between socks5 and socks5h?
With socks5, hostname resolution happens on the client. With socks5h, the proxy side resolves the destination hostname.
Why does my proxy work in a browser but fail in Requests?
The browser may use system settings, an extension, a PAC file, stored credentials, or a different DNS route. Compare the exact endpoint, protocol, authentication method, certificate trust, and destination used by the Python process.
