Scrapy效率低下的核心原因是CONCURRENT_REQUESTS设置过低、DOWNLOAD_DELAY与RANDOMIZE_DOWNLOAD_DELAY配置冲突、中间件含同步阻塞操作、HTTP缓存未启用。需将CONCURRENT_REQUESTS调至32,关闭RANDOMIZE_DOWNLOAD_DELAY,启用HTTPCACHE_ENABLED,并确保中间件完全异步。

CONCURRENT_REQUESTS 设置太低,直接卡死吞吐量
Scrapy 默认 CONCURRENT_REQUESTS = 16,对多数中等负载网站已偏保守;若目标站响应快(如静态页面、CDN加速)、服务器带宽充足,这个值会成为硬瓶颈——请求排队、调度器空转、Twisted事件循环“饿着”。
- 先试
CONCURRENT_REQUESTS = 32,观察日志里scrapy.core.engine: Crawled 0 pages (at 0 pages/min)是否消失,以及Downloader slot slots占用率是否持续高于 80% - 搭配
CONCURRENT_REQUESTS_PER_DOMAIN = 16(避免单域名压垮对方),而非盲目拉满 - 别设超过 128:过高的并发会触发 Twisted 的文件描述符耗尽(
OSError: [Errno 24] Too many open files),需同步调高系统 ulimit
DOWNLOAD_DELAY 和 RANDOMIZE_DOWNLOAD_DELAY 配置冲突
很多人开了 DOWNLOAD_DELAY = 1 又启 RANDOMIZE_DOWNLOAD_DELAY = True,结果延迟实际在 0.5–1.5 秒间抖动——看似“更自然”,实则破坏了 AutoThrottle 的收敛判断,导致限速策略反复震荡、吞吐忽高忽低。
- 生产环境优先关掉
RANDOMIZE_DOWNLOAD_DELAY,让AUTOTHROTTLE_ENABLED = True主导节奏 - 若必须模拟人工行为,改用中间件在
process_request中对特定域名加time.sleep(random.uniform(0.8, 1.2)),避开全局延迟干扰 -
DOWNLOAD_DELAY = 0是安全的(只要AUTOTHROTTLE开着),不是“必须设成 1”
Downloader 中间件里藏着同步阻塞操作
自定义中间件里调 time.sleep()、requests.get()、或未异步化的数据库查询,会把整个 Twisted reactor 线程拖住——所有并发请求瞬间退化为串行。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 检查所有
process_request方法:禁止出现任何time.sleep、requests.、sqlite3.connect、open(...).read() - 代理/IP 轮换逻辑必须用异步方式(如
asyncio.to_thread包裹阻塞调用,或直接用aiohttp查代理有效性) - User-Agent 切换推荐预加载到内存列表,用
random.choice(ua_list),而不是每次读文件或发 HTTP 请求取
HTTPCACHE_ENABLED 没开,重复请求白跑三遍
开发调试阶段反复跑同一组 URL?没开缓存的话,每次都是真实网络请求 + DNS 解析 + TLS 握手 —— 这些开销远大于解析 HTML。尤其本地测试时,HTTPCACHE_ENABLED 几乎零成本提升 3–5 倍迭代速度。
立即学习“Python免费学习笔记(深入)”;
- 开发期无脑开:
HTTPCACHE_ENABLED = True,HTTPCACHE_DIR = '.scrapy_cache'(加进 .gitignore) - 缓存目录别放 NFS 或慢盘,SSD 本地路径最稳
- 注意
HTTPCACHE_IGNORE_HTTP_CODES默认含[500, 502, 503, 504, 400, 403, 404, 408],如果目标站返回 429 也想缓存,得手动加进去
request.url 导致缓存 key 失效。调参前先看日志里 “Scheduler latency” 和 “Downloader request count” 的实际分布,比凭经验拍脑袋更可靠。


















