Python Requests 代理指南:语法、认证、轮换、重试

proxies 字典仅需三行代码,但 Requests 中的代理错误却在 Stack Overflow 上持续了十年。这里是完整的设置——语法、认证、环境变量、轮换、重试和 SOCKS5——并标注了所有棘手的地方。

Python Requests 仍然是抓取和自动化的默认 HTTP 客户端,将其指向代理仅需三行:传递一个 proxies 字典,每个请求都从代理的 IP 而不是你的 IP 发出。然而“python requests proxy 不工作”在十多年里一直是热门搜索——关于 proxies 字典的最初 Stack Overflow 问题可以追溯到 2011 年,其最佳答案获得了 480 多票,并且在 2026 年 1 月仍在被编辑。语法有棘手之处:缺少方案会引发异常,https 键中的错误方案会触发 SSL 错误,环境变量会默默覆盖代码。此 Python Requests 代理指南涵盖了所有内容:语法、认证、环境变量、轮换、重试、SOCKS5 以及你将实际遇到的错误。

proxies 字典:Python Requests 代理语法

proxies 参数将协议映射到代理 URL。两个键涵盖正常的抓取——一个用于普通 HTTP 目标,一个用于 HTTPS 目标——通常都指向同一个代理:

import requests

proxies = {
    "http": "http://USER:PASS@gate.quantumproxies.io:PORT",
    "https": "http://USER:PASS@gate.quantumproxies.io:PORT",
}

r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=(5, 30))
print(r.json())  # {'origin': '<proxy exit IP>'}

三条规则可防止 90% 的设置失败:

代理认证:用户名和密码

认证代理使用嵌入在 URL 中的 HTTP 基本认证:http://USER:PASS@host:port。如果密码包含 @:/,请先使用 urllib.parse.quote(password, safe="") 进行 URL 编码——未编码的特殊字符会在错误位置拆分 URL,导致看似代理失效的认证失败。407 Proxy Authentication Required 响应意味着代理本身拒绝了你:凭证错误,或从未注册地址调用的 IP 白名单计划。两种情况都在 我们的 407 故障排除指南 中进行了详细分析。对于任何超出一次性脚本的情况,将代理附加到 Session ——你将获得连接池、cookie 持久性和一个配置所有内容的地方:

import requests

session = requests.Session()
session.proxies = {
    "http": "http://USER:PASS@gate.quantumproxies.io:PORT",
    "https": "http://USER:PASS@gate.quantumproxies.io:PORT",
}
session.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})

r = session.get("https://httpbin.org/ip", timeout=(5, 30))
print(r.status_code, r.json())

环境变量和 trust_env

Requests 还从环境中读取代理设置——与 curl 和大多数 Unix 工具遵循的变量相同:HTTP_PROXYHTTPS_PROXYALL_PROXYNO_PROXY(要排除的主机的逗号列表,例如 localhost,127.0.0.1,.internal)。这是在不触及代码的情况下代理使用 Requests 的第三方库的最简洁方式。优先级为显式优于隐式:调用中的 proxies= 参数优先,然后是 session.proxies,然后是环境。值得了解的两个相关工具是:session.trust_env = False 关闭所有环境查找——当公司代理变量劫持你的抓取器时的修复方法——以及 urllib.request.getproxies() 返回 OS 级别的代理设置(包括 macOS 和 Windows 系统配置),其格式正是 Requests 期望的字典格式。

Python Requests 代理流的图示:proxies 字典通过旋转网关 CONNECT 隧道将每个请求路由到目标站点
字典选择路线,网关提供出口 IP。通过每次请求的轮换,相同的两行配置每次调用都会产生一个新的 IP。

轮换:一个网关胜过代理列表

传统的轮换方法——加载 IP 列表,每次请求 random.choice(),修剪失效的——是你不再需要构建的机制。旋转网关在服务器端完成:你配置一个端点,提供商在每次请求时从池中分配一个新的出口 IP。通过 旋转住宅代理,该池包含 90M+ 个家庭 IP,覆盖 200+ 个国家,因此一千个请求看起来像一千个不同的访问者,而无需一行轮换逻辑:

import requests

proxies = {
    "http": "http://USER:PASS@gate.quantumproxies.io:PORT",
    "https": "http://USER:PASS@gate.quantumproxies.io:PORT",
}

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

当一个流程跨越多个请求——登录、加入购物车、结账——每次请求的轮换会破坏会话。粘性会话解决了这个问题:代理用户名中的会话参数在设定的窗口内固定一个出口 IP,然后轮换。相同的端点,只需更改一个字符串。如果你超越简单循环进行扩展,使用 httpx 或 aiohttp 的异步 Python 可以倍增吞吐量,而 Scrapy 的中间件系统 为你提供轮换、重试和禁令处理作为框架配置。

能应对不良出口的重试和超时

即使是高级池也会提供偶尔的缓慢或失效出口,因此生产代码需要两个保护措施:每个请求的超时(Requests 默认等待无限)和具有退避的自动重试。超时采用 (connect, read) 元组——在无法访问的代理上快速失败,允许较慢的页面读取。重试通过 urllib3 在传输层挂载:

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry = Retry(
    total=4,
    backoff_factor=1,  # exponential backoff between attempts
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["GET", "HEAD"],
)

session = requests.Session()
session.mount("http://", HTTPAdapter(max_retries=retry))
session.mount("https://", HTTPAdapter(max_retries=retry))
session.proxies = {
    "http": "http://USER:PASS@gate.quantumproxies.io:PORT",
    "https": "http://USER:PASS@gate.quantumproxies.io:PORT",
}

r = session.get("https://httpbin.org/ip", timeout=(5, 30))

通过旋转网关,这种组合悄然强大:每次重试都会自动通过不同的出口 IP,因此一个不稳定的地址永远不会连续四次失败请求。

Requests 的 SOCKS5 代理

SOCKS 支持是一个额外功能:使用 pip install requests[socks] 安装它。然后字典语法相同——只有方案更改。优先使用 socks5h:// 而不是 socks5://h 将 DNS 解析推送到代理,防止 DNS 泄漏并从出口位置解析地理围栏的主机名。每个 QuantumProxies 计划在同一网关上同时提供 HTTP 和 SOCKS5 代理,因此切换协议只是方案的交换,而不是新的购买:

proxies = {
    "http": "socks5h://USER:PASS@gate.quantumproxies.io:PORT",
    "https": "socks5h://USER:PASS@gate.quantumproxies.io:PORT",
}
检查表比较有效的 Python Requests 代理配置与导致其失效的五个常见错误
五个错误导致大多数失败:缺少方案,https 键中的 https://,未编码的密码,缺少 SOCKS 额外功能,以及没有超时。

常见的 Python Requests 代理错误,解码

要深入了解堆栈跟踪及其根本原因,请参阅 调试 Requests 中的 ProxyError、SSLError 和 ConnectTimeout

常见问题解答

如何在 Python Requests 中使用代理?

将带有 httphttps 键的 proxies 字典传递给任何请求方法:requests.get(url, proxies={...})。每个值都是包含方案的完整代理 URL,凭证嵌入为 http://user:pass@host:port。将相同的字典附加到 Session 以自动应用于每个请求。

为什么我的 Python Requests 代理不起作用?

按顺序检查四个常见嫌疑:代理 URL 中缺少 http:// 方案,在 https 键中使用了 https://,密码中的特殊字符未进行 URL 编码,以及环境变量覆盖了你的代码。用 curl 测试相同的凭证——如果 curl 成功,问题就在你的字典中。

Python Requests 支持 SOCKS5 代理吗?

是的,在安装了额外的依赖项后,使用 pip install requests[socks]。在你的 proxies 字典中使用 socks5h:// 方案,以便 DNS 解析在代理端进行——普通的 socks5:// 方案在本地解析主机名,这会泄露 DNS 查询并可能破坏地理定位抓取。

如何使用环境变量设置代理?

导出带有完整代理 URL 的 HTTP_PROXYHTTPS_PROXY,以及可选的 NO_PROXY 用于排除的主机。Requests 会自动拾取它们,这也会代理基于 Requests 构建的第三方库。要让你的代码完全忽略环境,设置 session.trust_env = False

这就是整个工具包:一个两键字典,URL 中的凭证,一次挂载的重试,以及由网关而不是你的代码处理的轮换。没有任何语法能解决 IP 质量问题——一个完美配置的数据中心代理仍会在住宅出口畅通无阻的地方被阻止。将干净的代码与干净的 IP 配对,Requests 将能够处理惊人的大工作负载。

获取首次就能工作的住宅代理