一个代理由五部分信息组成:协议、用户名、密码、主机和端口。不同的提供商、工具和论坛会以不同的顺序排列这些信息,而在一个工具中能用的代理,放到另一个工具里却可能因为格式不对而失败。本指南展示了常见的几种排列方式、哪些工具期望哪种格式,以及我们在使用住宅代理时最常见的错误应如何避免。
五种常见格式
下面是同一个 Shifter 代理以五种格式呈现的样子,这些格式都可以由我们仪表盘中的 Proxy Generator 生成。用户名携带了定位信息和会话信息,所以它比你预期的要长。
| 格式 | 示例 |
|---|---|
scheme://user:pass@host:port | http://customer-USERNAME-sid-a1-ttl-60:PASSWORD@p.shifter.io:443 |
user:pass@host:port | customer-USERNAME-sid-a1-ttl-60:PASSWORD@p.shifter.io:443 |
host:port:user:pass | p.shifter.io:443:customer-USERNAME-sid-a1-ttl-60:PASSWORD |
user:pass:host:port | customer-USERNAME-sid-a1-ttl-60:PASSWORD:p.shifter.io:443 |
host:port@user:pass | p.shifter.io:443@customer-USERNAME-sid-a1-ttl-60:PASSWORD |
第一种是由网络标准定义的真正的 URL,只要工具支持,它就是最安全的选择。其余几种都是约定俗成的写法。它们之所以存在,是因为许多批量工具导入的是纯文本列表,每行一个代理,而每个工具都选择了自己的顺序。
哪些工具期望哪种格式
curl。 将 URL 形式传给 -x。如果你省略了协议,curl 会假定为 http://。你也可以用 -U username:password 把凭据单独分开,这样可以避免编码问题。我们关于curl 和 Postman 设置的指南提供了完整示例。
Python requests 和 Scrapy。 两者都使用 URL 形式。在 requests 中,字典的键表示网站的协议,值表示代理,所以两个值通常都指向同一个 http:// 代理:
proxy = "http://customer-USERNAME:PASSWORD@p.shifter.io:443"
proxies = {"http": proxy, "https": proxy}
Playwright。 将各部分作为单独的字段:server 包含协议、主机和端口,另加 username 和 password。自己拆分这些字段可以避免所有编码问题。
Puppeteer 和 Chrome。 --proxy-server 标志只接受主机和端口。凭据通过 page.authenticate() 传递。
浏览器配置文件管理器和批量工具。 许多工具以 host:port:user:pass 格式导入列表,有些会询问你的列表使用哪种顺序。粘贴几百行之前,先检查导入界面。
协议描述的是代理,不是网站
这是我们见到的最常见的错误。某位客户在抓取 HTTPS 网站时,在代理前面写了 https://,结果每个请求都因 TLS 错误而失败。
协议告诉你的客户端应该如何与代理通信。访问一个 HTTPS 网站时,是通过一个 http:// 代理,用 CONNECT 方法实现的:客户端请求代理打开一条隧道,然后通过这条隧道与网站进行 TLS 通信。与网站之间的连接依然是端到端加密的。写成 https://p.shifter.io:443 则是要求客户端直接与网关本身建立 TLS,而我们的网关并不提供这种方式,因此握手会失败。无论是 HTTP 还是 HTTPS 网站,都使用 http://,如果你的工具偏好 SOCKS,则用 socks5://。
对于 SOCKS,还有第二个选择。socks5:// 在你本机上解析网站的域名,而 socks5h:// 则把域名发送给代理去解析。如果你在意 DNS 查询发生在哪里,可以阅读我们关于防止 DNS 泄漏的指南。
特殊字符会破坏格式
每种格式都保留了某些字符。
- URL 形式: 用户名或密码中的
@、:、/、#、?和%必须进行百分号编码。像p@ss:word这样的密码会变成p%40ss%3Aword。 - 以冒号分隔的形式: 密码中出现冒号会使其后的所有字段发生偏移,导致工具读取到错误的主机或端口。
Shifter 用户名中的定位和会话部分只使用字母、数字、短横线和下划线,例如 city-new_york,因此在所有格式中都是安全的。如果你设置的密码中含有符号,使用带编码的 URL 形式,或者使用具有独立字段的工具,才是可靠的办法。
在不同格式之间转换
当某个工具给你的是一种格式,而你的代码需要另一种格式时,应该转换整个列表,而不是手动逐行编辑。下面这个 Python 函数可以把五种格式中的任何一种转换为 URL 形式,并对凭据进行编码:
from urllib.parse import quote
def to_proxy_url(line: str, scheme: str = "http") -> str:
line = line.strip()
if "://" in line:
return line
if "@" in line:
left, right = line.split("@", 1)
if left.rsplit(":", 1)[-1].isdigit():
hostport, creds = left, right # host:port@user:pass
else:
creds, hostport = left, right # user:pass@host:port
user, password = creds.split(":", 1)
host, port = hostport.rsplit(":", 1)
else:
parts = line.split(":")
if len(parts) != 4:
raise ValueError(f"unrecognised proxy line: {line}")
if parts[1].isdigit():
host, port, user, password = parts # host:port:user:pass
else:
user, password, host, port = parts # user:pass:host:port
return f"{scheme}://{quote(user, safe='')}:{quote(password, safe='')}@{host}:{port}"
print(to_proxy_url("p.shifter.io:443:customer-USERNAME:PASSWORD"))
# http://customer-USERNAME:PASSWORD@p.shifter.io:443
这个函数通过寻找端口号来判断顺序,所以当用户名或密码全部是数字时,它就无法区分不同的格式。遇到这种情况,请询问提供列表的人使用的是哪种顺序。
ISP 代理使用相同的格式
ISP 代理遵循相同的规则,只是主机不同。每个 ISP 代理都通过 isp.shifter.io:443 连接,所以以 host:port:user:pass 形式书写的一行会是 isp.shifter.io:443:USERNAME:PASSWORD。每个代理是通过其用户名来区分的,而不是每个代理配一个单独的 IP 和端口,这会让习惯了 ip:port:user:pass 列表的人感到意外。
代理无法连接时的快速检查
- 407 Proxy Authentication Required: 已经连接到了代理,但凭据未被接受。检查是否缺少或互换了用户名和密码,或是否存在未编码的符号。我们的407 故障排查指南涵盖了其余情况。
- 一开始就出现 TLS 或握手错误: 你很可能在代理前面写了
https://。改成http://。 - 每个请求都连接被拒绝或超时: 主机或端口有误,通常是因为以冒号分隔的行被按错误的顺序读取。
- 在 curl 中可用,但在你的工具中失败: 该工具期望不同的格式。转换这一行,或者把各字段分别输入。
在仪表盘中,Proxy Generator 允许你在复制之前选择协议和格式,并且可以以相同格式将整份列表下载为 CSV。一开始就选对格式,可以避免大多数此类错误。
来源与参考资料
- RFC 3986, Uniform Resource Identifier: Generic Syntax: rfc-editor.org
- curl, the —proxy option: curl.se
- Requests, proxies: requests.readthedocs.io
- Playwright, HTTP proxy: playwright.dev