前段时间朋友老张接了个爬虫小需求:爬取某比价网站,每天要批量采集一万个商品的价格数据。
为了避免本机IP被网站封禁,他找了一批免费代理IP凑合用。可实测完延迟直接心态炸裂:最慢的代理延迟能飙到800毫秒,就算是最快的,也要五百多毫秒。
无奈之下老张只能自我安慰:慢就慢一点吧,免费凑活能用,总比直接被封IP、爬取中断要强。
之后他写了一段最基础的循环代码:逐个读取商品链接,通过代理发送请求,等接口完全返回结果、处理完毕,再执行下一个请求。
结果上线运行后,效率低得离谱。

单次请求算上代理延迟、网络响应、数据处理,平均要1秒左右。一万条数据挨个爬完,足足需要一万秒,差不多三个小时。
这还不是最坑的,免费代理本身就不稳定,时不时超时、请求失败,还要重试,实际耗时只会更长。
老张盯着控制台慢悠悠滚动的日志,越看越头疼:明明代码没毛病,代理也能用,为啥效率这么低?难道慢代理就只能硬扛,没办法提速吗?
慢的不是代理,是代码只会“傻傻等待”
其实老张的核心问题,根本不是代理延迟高,而是串行等待的执行方式太浪费资源。
我们拆解一下单次代理请求的耗时构成,主要就三部分:
- 和代理服务器建立连接的耗时(几百毫秒)
- 代理转发请求、等待目标网站返回数据的耗时(几百到几千毫秒不等)
- 本地接收、下载数据的耗时(基本可以忽略,非常快)
哪怕单次请求只需要1秒,一万次串行跑下来,总耗时就是实打实的一万秒,这是简单的数学逻辑,根本没法偷懒。
更关键的是:这整整1秒里,代码90%以上的时间都在原地干等。
等代理连接、等网站响应,本地CPU闲着、网络带宽闲着,全程就是纯挂机等待,完全没有发挥出设备的性能。这种低效的串行执行,才是拖垮整体速度的罪魁祸首。
举个很通俗的生活例子:
快餐店做一份汉堡需要3分钟,你要买10份。如果傻傻排队等一份做好、拿到手再买下一份,总共要等30分钟。
但正常人都会直接一次性下单10份,厨房多份同时制作,最后你只需要等3分钟就能全部拿到。
放到网络请求、爬虫场景里,这个高效思路,就是大家常说的异步并发。
异步并发,专治“慢代理拖速度”
传统的同步串行请求,本质就是排队机制:一个请求发出去,代码直接阻塞停住,必须等结果返回、处理完成,才会发起下一个请求。哪怕绝大部分时间只是在等网络响应,也只能老老实实等着,什么事都做不了。
而异步并发的逻辑完全不一样:
发出一个请求后,代码不会原地卡死等待,而是立刻发起下一个、再下一个请求。谁先返回结果,就优先处理谁。全程代码一直在高效运转,不停收发请求,不会被单次慢速请求拖累。
还是拿老张的需求举例:单次代理延迟500毫秒,网站响应200毫秒,单次完整请求耗时700毫秒。但这里面,真正占用本地CPU运算的时间只有几十毫秒,剩下的全是等待时间。
如果开启50并发同时请求,理论总耗时可以套用一个简单公式:单次请求耗时 ×(总请求数 ÷ 并发数)。
代入数据计算:700ms ×(10000 ÷ 50)= 140秒,也就是两分多钟。
对比之前三个小时的耗时,效率直接翻倍提升,差距肉眼可见!
当然这是理想理论值,实际运行中会受代理带宽、网站反爬、网络波动影响,但核心规律不变:合理提升并发数,就能大幅缩短整体耗时。
实操超简单,不用复杂改造
最后老张也是用Python的asyncio + aiohttp简单改了几行代码,就彻底解决了速度问题。
给大家对比一下前后代码,差别一目了然。
原来的串行写法,低效又耗时:
for url in urls:
response = requests.get(url, proxies=proxy)
parse(response)
改造后的异步并发写法:
async def fetch(url):
async with session.get(url, proxy=proxy) as resp:
return await resp.text()
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
核心改动就一点:不再等单个请求结束再发起下一个,而是批量投递请求,统一回收处理结果。
如果你的开发环境比较老旧,比如传统PHP不支持异步,也完全不用慌。用多线程并行也能实现一模一样的效果。开启几十个线程,每个线程独立循环发起请求,线程之间互不阻塞、同步干活,原理和异步并发完全一致。
就算不想手写代码,主流爬虫框架基本都自带异步能力,比如Scrapy。只需要简单配置一下并发数量,框架会自动帮你批量推送请求、异步执行,开箱即用。
重点避坑:并发不是越高越快
很多人弄懂并发提速的原理后,容易走入一个误区:一味拉高并发数,觉得并发越高、速度越快。
但免费代理本身就是低成本、低性能的资源,盲目超高并发只会翻车:
- 代理负载超标,单次请求延迟不降反升,从500ms直接飙升到3秒以上
- 目标网站识别到高频批量请求,直接封禁代理IP,导致大量请求失败
- 本地端口、连接数被占满,出现网络阻塞、程序报错
最稳妥的调试方式是循序渐进、从小试起。先设置10并发,观察请求延迟、成功率,稳定后再慢慢调到20、30。一旦发现延迟暴涨、失败率飙升,就说明到了当前代理的性能上限,立刻回落即可。
除此之外,一定要搭配我上一篇提到的超时机制使用。
免费代理稳定性极差,总会有个别请求卡死、十几秒不响应。如果不设置超时,这些无效请求会一直占用并发槽位,拖慢整体进度。建议统一设置3秒左右的超时时间,超时直接放弃,不拖全队后腿。
总结
免费代理延迟高、不稳定,这是白嫖资源的固有短板,没法彻底改变。但我们能优化自己的代码逻辑,避开这个短板。
- 串行执行:排队等待,总耗时完全被单条慢请求拖累,量大必崩
- 异步/多线程并发:多请求同时等待执行,大幅压缩整体耗时
分享一句很接地气的总结:单条代理慢没关系,咱们多条代理一起跑,用数量弥补速度短板。
老张改完代码后,原本三个小时的爬取任务,现在五分钟就能轻松跑完。即便偶尔有少量代理超时失败,也完全不影响整体进度,效率和稳定性直接拉满。
这就好比用一群走得慢的驴拉货,不用纠结单头驴跑得快慢,只要多头驴同时发力,照样能按时完成任务。
如果你平时也有批量请求、批量爬取的慢任务,赶紧试试这个方法,效果立竿见影。
