先别急着写代码,把"谁替谁去敲门"想明白
很多人第一次调代理,脑子里其实只有一个模糊的印象:加个参数,IP 就变了。但真出问题时——连不上、超时、返回 407、访问到的页面跟浏览器不一样——就完全不知道从哪儿查。
说到底,是没搞清楚这条链路长什么样。
你可以先做个特别土但特别有效的类比。你住在 A 小区,想给 C 公司递一份材料。直连的意思是你自己走过去把材料交到前台;走代理的意思是,你把材料交给 B 先生,B 先生从自己家出发去 C 公司把材料交了,再把对方的回执带回来给你。C 公司的前台只见过 B 先生,登记本上写的是 B 先生的住址。
代理 IP 就是这么回事。你电脑上的程序把请求发给代理服务器,代理服务器拿着自己的 IP 去访问目标站点,拿到内容之后再转交给你。目标站点那边的访问日志里,留下的是代理的地址,不是你的。
下面就把这条链路拆成几段,一段一段看。
第一段:本机到代理服务器,先过"门禁"
第一步其实不是转发,是握手。
你的程序(不管是 requests、Scrapy 还是别的)按照你给的地址和端口,先跟代理服务器建立一条 TCP 连接。这一步跟访问普通网站没区别,区别在于连上之后要"报家门"。
常见的两种门禁方式:
账号密码认证。你在代理地址里带上用户名和密码,代理服务器校验通过才放行。这种方式灵活,换台机器也能用。
IP 白名单。你提前把自己服务器的出口 IP 报给服务商,之后只有这个 IP 来连才认。省事,但机器一换就得重新加白。
这一步最容易翻车的地方是把账号密码写错位置。正确的写法是把认证信息塞在代理 URL 里,而不是当成请求参数。另外密码里如果有 @、# 这类字符,记得做 URL 编码,否则解析会直接崩掉。
import requests
# 认证信息写在代理地址里,注意特殊字符要编码
proxy_url = "http://你的账号:你的密码@代理主机:端口"
proxies = {
"http": proxy_url,
"https": proxy_url,
}
resp = requests.get(
"https://目标站点/路径",
proxies=proxies,
timeout=10, # 一定要设,别让它无限等
headers={"User-Agent": "Mozilla/5.0"}
)
print(resp.status_code)
print(resp.text[:200])
顺手提醒一句:timeout 千万别省。代理链路比直连多了一跳,不设超时的话,某一条线路抽风,整个脚本能卡到你怀疑人生。
第二段:代理服务器替你去敲门
门禁过了,代理服务器开始干活。它要做三件事。
一是解析你要去哪。你请求的是哪个域名、哪个路径,代理得知道。这就是为什么用 HTTP 代理访问 HTTP 站点时,请求行里写的往往是完整地址,而不是单纯的路径。
二是决定用哪种协议。HTTP 和 HTTPS 的处理方式完全不一样。
访问 HTTP 站点时,代理是"看得见"内容的,它会把你发出去的请求头整理一遍再转发,中间可能补上 X-Forwarded-For 之类的字段,告诉目标站点"这个请求是经过我转的,原始来源在哪"。有些站点会读这个头,所以你偶尔会遇到"用了代理但还是被识别"的情况,原因就在这儿。
访问 HTTPS 站点时情况不同。你的程序先向代理发一个 CONNECT 请求,代理帮你和目标站点之间打一条加密隧道,之后的数据在隧道里跑,代理只负责搬运,看不到明文。所以 HTTPS 时代理更像一个"管道工",不是"翻译官"。
三是挑一个出口地址。这一步是动态代理的核心,下面单独说。
关键环节:IP 池是怎么挑出这一个地址的
你买到的不是一个固定 IP,而是一个池子。每次请求进来,服务端要从池子里挑一个"当前能用、位置合适"的地址给你。
挑的过程大致看三件事:
地区对不对。你要采集某个城市公开的门店信息,用的 IP 却落在另一个省,拿到的页面内容可能完全不是你要的。所以城市级定位这件事很重要,误差越小,拿到的页面越贴近真实用户看到的。
这个 IP 还活着没有。池子里总有到期、被回收、临时不通的地址。调度之前要先探活,或者干脆用实时检测的方式过滤,把不可用的直接跳过。
这个 IP 最近被用得凶不凶。同一个地址短时间内被反复拿去访问同一个站点,很容易触发对方的频率限制。好的调度会做轮换,让请求分散开。
这三件事做得怎么样,直接体现在两个数字上:可用率和你实际感受到的延迟。IP 池再大,如果一半是死号,你的脚本就得不停重试,重试本身又吃掉时间,最后跑得比直连还慢。
第三段:响应原路返回,中间多做了一次拆装
目标站点处理完请求,把响应交给代理服务器。代理服务器做的事,本质上是把你这一层"信封"拆掉,再换回你认识的那一层,然后传给你。
这段路上有几个细节值得注意:
状态码会被原样带回。407 是代理认证失败,502 一般是代理连不上目标,504 是超时。看到这些码,先分清是代理的问题还是目标站点的问题,别一股脑改代码。
响应头可能被改动。有些代理会加上自己的标识字段。如果你的程序依赖某个响应头做判断,最好先打一次纯直连的请求,对比一下差异。
编码和压缩要处理好。gzip 压缩的内容代理一般不负责解压,还是你的程序来解。requests 会自动处理,但如果自己手写 socket 逻辑,这里容易踩坑。
下面这张表,把三种走法放在一起对比,看得更直观:
| 对比项 | 直连 | HTTP 代理 | SOCKS5 代理 |
|---|---|---|---|
| 目标站点看到的来源 | 你的本机 IP | 代理 IP | 代理 IP |
| 代理是否能看到请求内容 | — | HTTP 明文时可看到 | 基本看不到 |
| 是否支持非 HTTP 流量 | — | 不支持 | 支持 |
| 典型使用场景 | 本地调试 | 公开网页数据采集 | 需要更底层转发的场景 |
| 额外多出的链路跳数 | 0 跳 | 1 跳 | 1 跳 |
换成 SOCKS5 的写法也顺手记一下,改的地方就那么一行:
# 先装:pip install requests[socks]
proxies = {
"http": "socks5://你的账号:你的密码@代理主机:端口",
"https": "socks5://你的账号:你的密码@代理主机:端口",
}
# 短效代理一般有效期有限,
# 建议每批请求前重新获取一次新的 IP,
# 而不是一个地址从头用到尾。
为什么同样的链路,有人跑得快有人跑得慢
链路结构是一样的,差距全在细节里。
并发没做对。单线程一条一条发,代理再快也白搭。但并发也不能乱开,开到几百个同时打同一个站点,多半会被限流。比较稳的做法是先小批试跑,看成功率和响应时间,再往上加。
IP 换得太勤或太懒。短效代理本身有有效期,一个地址用到快过期才换,中间那段时间失败率会明显上升。反过来,每个请求都换一个新地址,握手开销全摊在时间上。按实际场景找平衡点,比如按批次换而不是按请求换。
没做失败重试的区分。超时应该重试,但 403、404 这类重试意义不大,硬重试只会把 IP 用废。分类处理,比无脑 for 循环重试三次要理智得多。
请求头太假。不少站点会看 UA、Accept 这些字段。代理只负责换出口地址,不负责帮你伪装成一个正常的浏览器。这部分工作得自己做。
想少踩坑,选个链路干净的供应商能省一半事
把上面这条链路想通之后,你会发现很多问题其实不发生在你的代码里,而是在代理那一端。
神龙HTTP 这边的情况可以简单说一下。它家有 3000 万+ 正规授权代理 IP 储备,来自国内三大运营商的授权资源,可用率标称 99.9%,IP 纯度 99.8%,支持 300+ 城市级精准定位。这几个数字对应到上面讲的链路里,就是"IP 调度那一步挑出来的地址更靠谱"——池子里的死号少,你重试的次数就少,脚本跑起来自然顺。
协议上支持 HTTP、HTTPS、SOCKS5,短效动态、长效静态、固定 IP 三条产品线都在,按你的场景挑就行。接入方式也简单,API 兼容主流爬虫语言,文档里有示例代码,基本是复制粘贴改个地址就能跑通的状态。个人中心里能看到用量统计和实时监控,哪一批请求失败率突然上去了,一眼就能看出来是线路问题还是代码问题——这点在排障的时候特别有用,比对着日志一行行猜强多了。
真遇到调不通的情况,技术团队 7×24 小时在线,把请求日志甩过去,一般能比较快定位到是认证、协议还是调度层面的问题。
常见问题
Q:用了代理,为什么目标站点还是能识别出我?
可能性有三种。一是你请求的是 HTTP 站点,代理在转发时补了 X-Forwarded-For 之类的来源头,对方读到了;二是你的请求头、Cookie、浏览器指纹和 IP 归属地对不上,比如 IP 显示在某个城市,时区却是另一个地方的;三是这个 IP 之前被大量使用过,已经在对方的风控名单里。排查顺序建议从请求头开始,再看 IP 的纯净度。
Q:HTTP 代理和 SOCKS5 到底该选哪个?
只采集公开网页,用 HTTP/HTTPS 就够了,兼容性最好,大部分库开箱即用。如果程序里要处理非 HTTP 的流量,或者不想让代理看到请求内容,那就上 SOCKS5,代价是部分库需要额外装依赖。
Q:短效动态 IP 多久换一次比较合适?
跟着有效期走,别卡在最后几秒。一般建议在有效期过半之后就重新获取新的 IP,留出重试的余量。如果目标站点的限制比较严,那就按批次换,一批请求用一个地址,跑完再换,比每个请求都换要稳。
Q:报 407 和报 502 分别说明什么?
407 是代理认证没通过,先检查账号密码有没有写错、特殊字符有没有做编码、白名单 IP 有没有加对。502 一般是代理服务器自己没能连上目标站点,可能是目标那边拒绝了这个 IP,也可能这条线路暂时不通,换一个 IP 重试通常就好了。
Q:为什么并发一拉高,成功率就往下掉?
两种情况居多。一是你本机的连接数、文件描述符被打满了,请求还没发出去就排队;二是同一批 IP 短时间集中访问同一个站点,触发了对方的频率控制。先看看是本地报错还是远端返回异常,再决定是加机器还是降并发。





