用gevent能显著提升Python3.10爬虫并发吞吐量,但必须首行执行monkey.patch_all()、禁用time.sleep()改用gevent.sleep()、用gevent.spawn()并发并设timeout,且需处理DNS缓存、HTTP连接复用和SSL握手阻塞问题。

直接上结论:用 gevent 能显著提升 Python 3.10 爬虫的并发吞吐量,但前提是必须打猴子补丁、禁用原生阻塞调用、且只适用于纯 IO 密集型场景——一旦混入 CPU 计算或未 patch 的模块,性能反而会断崖式下跌。
必须在导入任何标准库前调用 monkey.patch_all()
这是最常踩的坑。很多同学把 from gevent import monkey; monkey.patch_all() 放在文件中间甚至函数里,结果 socket、ssl、threading、time 这些模块早已被其他依赖(比如 requests 或 urllib3)提前加载,补丁失效,协程照样阻塞。
- 正确做法:第一行代码就是
from gevent import monkey; monkey.patch_all(),不加任何条件判断 - 特别注意:如果你用了
requests,它底层依赖urllib3和ssl,这两者都必须被 patch 才能生效;monkey.patch_all()默认已覆盖它们,但顺序错就白搭 - 验证是否生效:运行后打印
import socket; print(socket.socket),如果输出是<class 'gevent._socket3.socket'>才算成功;否则仍是<class 'socket.socket'>,说明 patch 失败
不能用 time.sleep(),必须用 gevent.sleep()
time.sleep() 是系统级阻塞调用,哪怕打了补丁,它也不会自动 yield 到其他 greenlet;而 gevent.sleep() 是协程感知的让出点,触发调度器切换。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 所有延时逻辑(如反爬 sleep、重试间隔、请求节流)必须写成
gevent.sleep(1.5),而不是time.sleep(1.5) - 如果你封装了通用延时工具函数,务必检查内部是否偷偷用了
time.sleep - 第三方库中隐含的
time.sleep(比如某些解析库的 retry 逻辑)仍会阻塞,这时得手动 patch 对应模块,或换用gevent.monkey.patch_time()单独加固
用 gevent.spawn() + gevent.joinall() 启动并发请求
别套用线程/进程那一套去写循环创建+join,gevent 的 spawn 是轻量级的,开几千个 greenlet 没压力,但 spawn 太多没意义——真正瓶颈是 DNS 解析、TCP 连接数、远端服务器限流。
立即学习“Python免费学习笔记(深入)”;
- 推荐模式:
jobs = [gevent.spawn(request_func, url) for url in urls],然后gevent.joinall(jobs, timeout=10) - 务必加
timeout参数,否则某个请求卡死会拖垮整个协程池;超时后 job.value 为None,需主动判空 - 不要在 spawn 内部 try/except 捕获所有异常——greenlet 错误默认静默,得用
job.exception显式检查,或设raise_error=True让异常冒泡 - 避免在协程里做耗时解析(如大 HTML 正则、复杂 JSON path),CPU 密集操作会锁死当前 greenlet,建议用
gevent.threadpool.ThreadPool卸载到线程池
真实爬虫中容易被忽略的三个细节
多数人跑通 demo 就以为 OK,但在真实网站抓取中,这三个点几乎必出问题:
- DNS 缓存:默认
gevent会缓存 DNS 结果,但若目标站做了轮询 IP(如 CDN),缓存会导致部分请求失败;可加gevent.socket.gethostbyname = gevent.socket.gethostbyname_ex强制每次解析,或用dnspython配合自定义 resolver - HTTP 连接复用:
requests的 Session 在 gevent 下默认不复用连接,每个请求新建 TCP,开销极大;改用urllib3.PoolManager(num_pools=20, maxsize=50)并传给 requests.adapters.HTTPAdapter - SSL 握手阻塞:某些老旧 HTTPS 站点握手慢,
gevent默认未优化;可在monkey.patch_all()后加gevent.monkey.patch_ssl(),并确保 OpenSSL 版本 ≥ 1.1.1


















