知其然,知其所以然
gRPC 2026-10-12

max_concurrent_streams:单连接的并发上限与排队

实测 gRPC 的 max_concurrent_streams:服务端在 SETTINGS 帧里公布,客户端自己排队而不是被拒绝;排队时间算在 deadline 里;限制是每条连接的;长流会占满名额让普通调用无限期排队。

gRPC MaxConcurrentStreams 并发流 HTTP/2 排队 SETTINGS Go 真实验证 动画演示
Scrapy 内部原理 2026-10-12

并发控制:CONCURRENT_REQUESTS 与按域名、按 IP 的限制

在 Scrapy 2.19.0 本机实测并发限制:默认 asyncio reactor 下 CONCURRENT_REQUESTS_PER_DOMAIN 没有生效(单域名 48 个请求峰值始终 48,SelectReactor 下峰值等于设置值);全局 CONCURRENT_REQUESTS 和 DOWNLOAD_DELAY 有效;PER_IP 和 DOWNLOAD_SLOTS 同样失效;无 reactor 模式的限制来自 aiohttp 连接器。

Scrapy 并发 CONCURRENT_REQUESTS 每域名限制 下载槽 asyncio 真实验证 动画演示
Scrapy 内部原理 2026-10-12

DOWNLOAD_DELAY 与 RANDOMIZE_DOWNLOAD_DELAY:请求间隔的真实分布

实测 2.19 的下载延迟:DOWNLOAD_DELAY = 0.2 且默认 ±50% 抖动时,实际平均间隔是 243 ms 而不是 200 ms(总耗时 24.2 s 对 20.1 s);延迟按“发出到发出”计算,慢响应只会让在途请求变多;每个域名独立计时;DOWNLOAD_SLOTS 可以单独设 delay;RANDOMIZE_DOWNLOAD_DELAY 与 download_delay 属性已弃用。

Scrapy DOWNLOAD_DELAY 抖动 下载延迟 DOWNLOAD_SLOTS 真实验证 动画演示
Scrapy 内部原理 2026-10-12

下载器 slot:每个域名一个槽位怎么工作

实测下载槽:槽名默认是小写主机名(忽略端口和协议),CONCURRENT_REQUESTS_PER_IP 下变成解析后的 IP,meta["download_slot"] 优先;把两个主机名合并成一个槽总耗时从 4.0 s 变 7.9 s,把一个主机拆成两个槽从 7.9 s 变 3.8 s;DOWNLOAD_SLOTS 可按槽名设 delay;空闲的槽在 60~120 秒后被回收。

Scrapy 下载槽 slot download_slot DOWNLOAD_SLOTS 真实验证 动画演示
Scrapy 内部原理 2026-10-12

AutoThrottle:延迟怎么根据响应时间调整

实测 AutoThrottle:延迟每次向 latency ÷ 目标并发 走一半,约 8 个响应收敛;变慢时一步跳升、变快时折半下降;非 200 响应不会让延迟下降(404 后 delay 保持 506 ms,200 后降到 25 ms);DOWNLOAD_DELAY 是下限、MAX_DELAY 是上限;它只调延迟,实际并发峰值会超过目标。

Scrapy AutoThrottle 自动限速 延迟 真实验证 动画演示
Scrapy 内部原理 2026-10-12

RetryMiddleware:哪些响应与异常会被重试

实测 RetryMiddleware:默认 RETRY_TIMES = 2(共 3 次请求);8 个状态码(500、502、503、504、522、524、408、429)和连接被拒/超时/断开/DNS 失败都会重试,404/403/400 不重试;重试之间只隔 1 ms 没有退避;重试请求优先级 -1 排到所有正常请求之后;meta 的 dont_retry、max_retry_times 可逐请求控制;get_retry_request 可在回调里手动重试。

Scrapy RetryMiddleware 重试 RETRY_TIMES get_retry_request 真实验证 动画演示
Scrapy 内部原理 2026-10-12

RedirectMiddleware:跳转次数与 meta 里的跳转记录

实测重定向中间件:301/302/303 的 POST 变 GET 丢请求体、307/308 保持 POST;meta 记录 redirect_urls/reasons/times/ttl;REDIRECT_MAX_TIMES = 20 时服务器收到 21 次请求后丢弃(errback 拿到 IgnoreRequest),跳回同一 URL 会被去重;跨主机删除 Cookie/Authorization;meta refresh 秒数 < 100 就立即跳转。

Scrapy RedirectMiddleware 重定向 meta refresh redirect_urls 真实验证 动画演示
Scrapy 内部原理 2026-10-12

HTTP 缓存:HTTPCACHE 的存储与策略

实测 Scrapy 2.19 的 HTTP 缓存:默认关闭,打开后第二次运行 3 个请求全部命中、服务器 0 个请求;每个请求在磁盘上 7 个文件;DummyPolicy 连 no-store 和 404/500 都缓存;RFC2616Policy 尊重 no-store、max-age、ETag/Last-Modified(304 用缓存正文);EXPIRATION_SECS 过期;服务器关闭时用旧缓存兜底。

Scrapy HTTP缓存 HttpCacheMiddleware RFC2616Policy ETag 真实验证 动画演示
Scrapy 内部原理 2026-10-12

CookiesMiddleware:多个 cookiejar 与 meta 里的 cookiejar

实测 CookiesMiddleware:Set-Cookie 自动存进 jar 并带到后续请求;headers 里的 Cookie 会被覆盖,要用 cookies 参数;meta["cookiejar"] 隔离多个会话,但必须自己一路传下去;Path、Secure、Domain、Max-Age 都按规则生效;COOKIES_DEBUG 的日志;dont_merge_cookies。

Scrapy CookiesMiddleware cookiejar Cookie Set-Cookie 真实验证 动画演示
Scrapy 内部原理 2026-10-12

RobotsTxtMiddleware:robots.txt 的下载与等待

实测 RobotsTxtMiddleware:内置默认 ROBOTSTXT_OBEY = False 而项目模板写 True;被禁请求抛 IgnoreRequest 且不发出,robots.txt 每个 netloc 只下载一次并排在前面;默认 UA 匹配 User-agent: Scrapy 组;robots.txt 404/500/超时/乱码一律放行;Crawl-delay 被忽略。

Scrapy RobotsTxtMiddleware robots.txt 爬虫礼仪 真实验证 动画演示
Scrapy 内部原理 2026-10-12

默认请求头与 User-Agent 的设置位置

用原始套接字服务器看 Scrapy 2.19 发出的请求字节:默认头顺序是 Accept、Accept-Language、User-Agent、Accept-Encoding(gzip, deflate, br, zstd)、Host;请求自己的头 > DEFAULT_REQUEST_HEADERS > USER_AGENT 设置;USER_AGENT 设空串就不发 UA;头名规范成 Title-Case,列表值拆成多行;Request 的 POST 不带 Content-Type,FormRequest 才带。

Scrapy 请求头 User-Agent DEFAULT_REQUEST_HEADERS Accept-Encoding 真实验证 动画演示
Scrapy 内部原理 2026-10-12

DepthMiddleware:DEPTH_LIMIT 与 DEPTH_PRIORITY

在二叉树站点上实测 DepthMiddleware:DEPTH_LIMIT = 1/2/3/4 分别抓 3/7/15/31 个页面;DEPTH_PRIORITY = 1 把层号序列从 011223333223333(深度优先)变成 011222233333333(广度优先);重定向沿用 depth,depth_reset 归零,手动 meta depth 会被覆盖。

Scrapy DepthMiddleware DEPTH_LIMIT DEPTH_PRIORITY depth_reset 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号