Python 里要用代理,先分清是 pip 还是你写的脚本。pip 是命令行工具,通过 --proxy、环境变量或配置文件设置;脚本里的 requests 则在每次调用时传 proxies 字典。要走 SOCKS5,两边都得先装 PySocks。本文按 2026 年 11 月的状态写,代理地址全部是占位符。
pip 装包怎么走代理?
三种方式,按"临时程度"从高到低排列:命令行参数、环境变量、配置文件。pip 的 --proxy 接受 scheme://[user:password@]host:port 形式的地址。
# 一次性
python -m pip install --proxy http://user:password@proxy.example.com:8080 requests
# 当前终端
export HTTPS_PROXY=http://proxy.example.com:8080
# 写进用户配置文件
python -m pip config set global.proxy http://proxy.example.com:8080
python -m pip config list
python -m pip config unset global.proxy
建议养成写 python -m pip 的习惯。机器上有多个 Python 或虚拟环境时,这样能确保你配置和安装的是同一个解释器。想知道 pip 实际读了哪些配置文件,运行 python -m pip config debug。另外 pip 也认 PIP_PROXY 环境变量(pip 的每个选项都可以这样用 PIP_ 加选项名来设置)。
认证信息和特殊字符的写法见前面的 给 git 配代理,前端项目的对应配置见 npm、pnpm、yarn 的代理设置。
requests 的 proxies 字典怎么写?
键是"目标网站"的协议,值是"代理服务器"的地址。很多人疑惑为什么访问 HTTPS 网站时 https 对应的值还要写 http://:因为普通 HTTP 代理是通过 CONNECT 方法替客户端打通一条隧道,加密流量原样穿过,代理本身的地址依然是 http:// 开头。
import requests
proxy = "http://user:password@proxy.example.com:8080"
proxies = {"http": proxy, "https": proxy}
r = requests.get("https://api.ipify.org", proxies=proxies, timeout=10)
print(r.text)
别忘了 timeout,不传的话 requests 可能一直等下去。密码含 @、/ 等保留字符时,先用 urllib.parse.quote 编码:
from urllib.parse import quote
password = quote("p@ss/word", safe="")
proxy = "http://user:" + password + "@proxy.example.com:8080"
环境变量和代码里的 proxies,谁说了算?
requests 默认 trust_env=True,会读 HTTP_PROXY、HTTPS_PROXY、ALL_PROXY、NO_PROXY,还可能读 .netrc。官方文档特别提醒:给 Session.proxies 赋的值可能被环境变量里的代理覆盖。想确保用的是你指定的代理,办法是每次请求都显式传 proxies=,或者干脆把 trust_env 设为 False 让它不看环境。
s = requests.Session()
s.trust_env = False
r = s.get("https://api.ipify.org", proxies=proxies, timeout=10)
这条规则经常解释"脚本明明写了代理,抓包却看到走的是另一个地址"这类怪事:通常是终端里残留了旧的环境变量。
SOCKS5 要装什么,socks5 和 socks5h 怎么选?
requests 通过 PySocks 支持 SOCKS,官方推荐的装法是带 extra 安装 requests[socks]。地址里用 socks5h:// 让代理端解析域名,本机 DNS 不参与;写 socks5:// 则是本机先解析、再把 IP 交给代理。
python -m pip install "requests[socks]"
proxy = "socks5h://user:password@proxy.example.com:1080"
proxies = {"http": proxy, "https": proxy}
pip 本身走 SOCKS 也需要 PySocks,而且必须装在运行 pip 的那个解释器里。如果看到 "Missing dependencies for SOCKS support",这是个先有鸡还是先有蛋的问题:先不用 SOCKS 代理(或临时用 HTTP 代理)执行 python -m pip install pysocks,装好再切换。要注意,这里讲的是 TCP 连接,HTTP 请求用不到 SOCKS5 的 UDP 功能。
报错信息怎么读?
requests 把网络故障包成自己的异常,pip 则直接打印底层信息。看清原文就能判断卡在哪一层:代理连接、认证、TLS,还是目标站本身。
| 报错 | 所在层 | 检查什么 |
|---|---|---|
ProxyError: Cannot connect to proxy | 连代理 | 主机、端口、协议头;防火墙 |
407 Proxy Authentication Required | 认证 | 用户名密码;密码是否编码、是否被重置 |
Missing dependencies for SOCKS support | 本地环境 | 在同一个解释器里装 PySocks |
SSLError: certificate verify failed | TLS | 代理或网关在解密 HTTPS;提供它的根证书,不要关闭验证 |
ConnectTimeout / ReadTimeout | 网络路径或目标站慢 | 用 curl 走同一代理对比 |
分不清是代码问题还是代理问题时,先拿 curl 做对照:同一个代理、同一个地址,curl 能通而 Python 不通,问题就在 Python 这一侧的配置。
怎么确认脚本真的走了代理?
最直接的办法是对比:让公共的"回显 IP"服务分别看一次直连和走代理时的来源地址,两个值不同就说明代理生效了。把检测函数建在一个关掉 trust_env 的 Session 上,可以避免残留的环境变量干扰结果;再分别捕获几类异常,出错时能立刻知道是哪一层的问题。
import requests
from requests.exceptions import ProxyError, ConnectTimeout, ReadTimeout
proxy = "http://user:password@proxy.example.com:8080"
proxies = {"http": proxy, "https": proxy}
def seen_ip(proxies=None):
s = requests.Session()
s.trust_env = False
return s.get("https://api.ipify.org", proxies=proxies, timeout=10).text
print("直连:", seen_ip())
try:
print("代理:", seen_ip(proxies))
except ProxyError as e:
print("代理或认证有问题:", e)
except (ConnectTimeout, ReadTimeout) as e:
print("超时:", e)
在终端里可以用 curl -x http://proxy.example.com:8080 https://api.ipify.org 做同样的检查。curl 和 Python 的结果不一致时,依次排查环境变量、trust_env,以及跑脚本的到底是哪个解释器(虚拟环境里的 pip 和系统的 pip 经常不是同一个)。
脚本里的密码怎么处理才不尴尬?
把代理地址写死在源码里,迟早会被提交进仓库。更稳妥的做法有两种:一是由运行环境注入 HTTPS_PROXY / HTTP_PROXY,脚本里不出现凭据,pip 和 requests 都会读到;二是使用支持来源 IP 白名单的代理,运行脚本的机器被放行后,地址里根本不需要密码。无论哪种,密码一旦被重置,凡是写死过它的地方都要更新。
安泊 VPN 能在哪里帮上忙
安泊 VPN 的代理 IP(HTTP/SOCKS5 proxy)独占一个 IP,HTTP 端口(含 HTTPS 隧道)和 SOCKS5 端口共用同一组用户名密码,上面的写法可以直接套用。不支持 SOCKS5 UDP,但 pip 和 requests 只用 TCP,不受影响。把机器加入来源 IP 白名单后,脚本里无需密码。用量计入流量套餐,用尽后代理关闭。详见代理 IP 页面。


