结论先说: Python 接入静态住宅IP时,先确认供应商给出的协议、主机、端口和鉴权方式,再分别设置连接超时与读取超时。同步任务可用 Requests,异步并发任务可用 aiohttp;只有需要 SOCKS5 时才安装相应依赖。生产代码必须限制重试次数、保护账号密码,并保留 TLS 证书校验。
先把四项连接信息确认清楚
“代理连不上”经常不是代码问题,而是协议和鉴权参数填错。动手前先整理以下信息:
| 参数 | 示例 | 容易出错的地方 |
|---|---|---|
| 协议 | HTTP、HTTPS proxy、SOCKS5 | 目标网址是 HTTPS,不代表代理地址一定写成 https:// |
| 主机与端口 | proxy.example.com:3128 |
端口被本地防火墙、公司网络或供应商白名单拦截 |
| 鉴权 | 用户名密码或源 IP 白名单 | 密码含 @、:、/ 时直接拼 URL 会解析失败 |
| 目标与用途 | API、网页或自有测试地址 | 目标站是否允许自动访问、请求频率是否合规 |
HTTP 代理访问 HTTPS 目标时,客户端通常通过 HTTP CONNECT 建立隧道,所以 https 目标对应的代理 URL 仍可能是 http://proxy-host:port。不要凭目标网址猜协议,应以供应商交付信息为准。协议概念不清楚时,可先阅读HTTP、HTTPS、SOCKS5 的区别。
Requests 配置 HTTP 代理的推荐写法
下面示例把凭据放在环境变量中,并对用户名、密码进行 URL 编码。示例目标应替换成你有权访问的测试端点。
import os
from urllib.parse import quote
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
proxy_user = quote(os.environ["PROXY_USER"], safe="")
proxy_pass = quote(os.environ["PROXY_PASS"], safe="")
proxy_host = os.environ["PROXY_HOST"]
proxy_port = os.environ["PROXY_PORT"]
proxy_url = (
f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
)
proxies = {
"http": proxy_url,
"https": proxy_url,
}
retry = Retry(
total=3,
connect=3,
read=2,
status=2,
backoff_factor=0.5,
status_forcelist=(429, 502, 503, 504),
allowed_methods=frozenset({"GET", "HEAD", "OPTIONS"}),
respect_retry_after_header=True,
)
session = requests.Session()
session.trust_env = False
session.mount("http://", HTTPAdapter(max_retries=retry))
session.mount("https://", HTTPAdapter(max_retries=retry))
response = session.get(
"https://example.com/health",
proxies=proxies,
timeout=(5, 20),
)
response.raise_for_status()
print(response.status_code, response.elapsed.total_seconds())
timeout=(5, 20) 分别表示连接阶段和读取阶段的等待上限。Requests 官方文档说明,如果不显式设置 timeout,请求可能长时间挂起;单一数字也不是整个下载任务的绝对总时限。Session 可以复用连接,但同一 Session 也会保留 Cookie,因此不同业务身份不要混用一个 Session。
示例只对通常具有幂等性的 GET、HEAD、OPTIONS 自动重试。订单创建、付款或写入接口的 POST 如果直接重试,可能产生重复操作;除非目标 API 有幂等键和明确文档,否则不要把所有方法加入 allowed_methods。
Requests 配置 SOCKS5 与远端 DNS
先安装可选依赖:
python -m pip install "requests[socks]"
然后把代理 URL 改为:
proxy_url = (
f"socks5h://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
)
proxies = {"http": proxy_url, "https": proxy_url}
Requests 文档区分 socks5:// 和 socks5h://:前者由客户端解析目标域名,后者让代理端解析。需要让 DNS 查询跟随代理出口时,应优先核对 socks5h 是否符合业务需求;更完整的区别可参考SOCKS5 与 SOCKS5H 的 DNS 解析指南。
aiohttp 的异步代理配置
aiohttp 适合并发 I/O,但并发并不等于可以无上限访问。先遵守目标站 API 配额、robots.txt、服务条款和当地法律,再设置连接池与并发阈值。
import asyncio
import os
import aiohttp
async def main():
proxy = f"http://{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}"
proxy_auth = aiohttp.BasicAuth(
os.environ["PROXY_USER"],
os.environ["PROXY_PASS"],
)
timeout = aiohttp.ClientTimeout(
total=30,
connect=5,
sock_read=20,
)
async with aiohttp.ClientSession(
timeout=timeout,
trust_env=False,
) as session:
async with session.get(
"https://example.com/health",
proxy=proxy,
proxy_auth=proxy_auth,
) as response:
response.raise_for_status()
print(response.status)
asyncio.run(main())
aiohttp 官方文档说明,它默认不会读取系统代理环境变量;只有设置 trust_env=True 才会读取。显式传入 proxy 并保持 trust_env=False,可以减少机器上残留代理变量干扰测试。aiohttp 原生文档主要描述 HTTP 代理和通过 CONNECT 的隧道;如果业务要求 SOCKS,应选用有明确维护文档的连接器,并单独验证 DNS 与 TLS 行为,不能只把 URL 前缀改成 socks5:// 就假定生效。
五类常见故障怎么定位
| 现象 | 优先检查 | 不建议的处理 |
|---|---|---|
| 407 Proxy Authentication Required | 用户名密码、白名单、URL 编码、套餐状态 | 盲目切换 User-Agent |
| ConnectTimeout | 主机端口、路由、防火墙、代理节点可达性 | 无限延长超时 |
| ReadTimeout | 目标站响应、代理出口质量、读取阈值 | 把读取慢误判为鉴权失败 |
| TLS/证书错误 | 系统时间、CA 链、是否存在 HTTPS 检查代理 | 使用 verify=False 长期绕过 |
| 403 或 429 | 目标站权限、规则、频率、Retry-After |
轮换 IP 规避访问控制 |
407 的详细分层方法见代理IP 407 鉴权错误排查指南。如果直连和代理访问同一目标都失败,先查目标服务;只有代理路径失败,再查代理协议、节点和鉴权。一次只改变一个变量,才能知道修复真正发生在哪一层。
凭据、日志与证书的安全底线
- 不要把代理密码写进 Git 仓库、截图、报错工单或公开日志。
- 环境变量比硬编码好,但并非密钥保险箱;生产环境应使用权限受控的 Secret 管理方案。
- 记录错误类型、状态码、耗时和节点代号即可,不要记录完整代理 URL。
- 不要用
verify=False或关闭 TLS 校验掩盖证书问题;这会让中间人攻击更容易发生。 - 若供应商使用源 IP 白名单,离职人员、旧服务器和临时出口应及时移除。
- 自动采集只访问公开且被允许的数据,设置并发上限、退避与审计日志。可配合公开数据采集合规清单检查上线条件。
上线前验收清单
- 用同一测试 URL 分别做直连与代理请求,记录状态码和分阶段耗时。
- 通过受信任的自有回显端点确认出口 IP,避免只依赖单一第三方数据库。
- 连续执行小样本请求,确认 Session 复用后没有跨业务 Cookie 污染。
- 人为填错密码,确认程序能明确报告 407,而不是无限重试。
- 人为设置很短 timeout,确认超时会被捕获、记录并受限重试。
- 检查日志、异常追踪和监控平台中没有明文凭据。
- 对写接口验证幂等键,不把非幂等请求纳入通用重试。
常见问题(FAQ)
HTTPS 网站为什么使用 http:// 开头的代理地址?
因为这里的 URL 描述的是客户端如何连接代理,而不是目标网站的协议。HTTP 代理可通过 CONNECT 为 HTTPS 目标建立隧道。最终写法以供应商提供的代理协议为准。
Requests 中 socks5 和 socks5h 应该选哪个?
需要客户端本地解析域名时用 socks5;希望域名由代理端解析时用 socks5h。跨地区测试常需要后者,但仍应实测 DNS 结果。
代理失败可以一直自动重试吗?
不可以。有限重试只适合短暂连接故障和明确可重试的状态码;应采用退避、尊重 Retry-After,并避免自动重试可能产生副作用的写请求。
为什么不建议把密码直接写在代码里?
代码会进入版本历史、构建日志、截图或协作工具,删除当前文件也未必能清除历史。生产环境应使用权限受控的密钥管理方式。
