在 Scrapy 2.19 上对比三种运行方式:默认 asyncio reactor、SelectReactor、TWISTED_REACTOR_ENABLED=False(无 reactor、aiohttp 下载);单线程并发 100 个慢请求只要 0.6 s;回调里 time.sleep(0.1) 让 20 个请求从 0.34 s 变成 2.39 s;SelectReactor 下 async 回调 await asyncio.sleep 全部抛 RuntimeError。
抓包看 gRPC 的消息帧:消息边界由 5 字节前缀决定,和 HTTP/2 DATA 帧边界无关(20000 字节切成 16384 + 3628,1 MiB 切成 65 帧);gzip 压缩是逐条消息的,标志位为 1、长度是压缩后的;超过 4 MiB 的消息服务端读到长度就拒绝,线上只传了一小部分。
实测 gRPC 的 17 个状态码:线上传的是数字;普通 error 一律变成 Unknown;连接失败默认立刻返回 Unavailable(0.4 ms),加 WaitForReady 才会等;网关返回 429/502/503/504 在客户端都是 Unavailable,500 却是 Unknown。
为什么 grpc-status 放在 trailers:HTTP 状态 200 在第一个 HEADERS 就发出去了,流中途出错只能放在最后;一条消息都没发就失败是 trailers-only 的单个 HEADERS;grpc-message 做百分号编码;-bin 键用 base64;连接中途断了得到 Unavailable;缺少 trailers 得到 Internal。
实测 Scrapy 2.19 的四个启动类:start() 只能调一次(第二次 ReactorNotRestartable);CrawlerProcess 并发两个 spider 0.62 s、CrawlerRunner 顺序 1.39 s;CrawlerRunner 不 stop reactor 进程永远不退出;asyncio.run 配 asyncio reactor 会卡死;第一次 SIGINT 优雅停止、第二次强制退出。
实测 gRPC 的 deadline:线上是最多 8 位数字加单位字母的相对时长(999978u);A→B→C 逐跳扣减(999、898、797 ms);中间一层不传 ctx,客户端超时后下游还会把活干完;已过期的调用不发任何帧;服务端不监听 ctx 就看不到取消;传输延迟不会被扣掉。
实测 Scrapy 2.19 的 settings 优先级:default 0 / command 10 / addon 15 / project 20 / spider 30 / cmdline 40;startproject 模板默认 DOWNLOAD_DELAY = 1;spider.update_settings 里用 "cmdline" 优先级输给 -s,要用 41 才赢;字典型设置整体替换;-s 的值是字符串('False' 当 if 是真);设置在 start() 里已冻结。
实测 Scrapy 2.19 的 start():默认 start() 对 start_urls 的重复项也会请求(dont_filter=True);只写旧的 start_requests 的 spider 什么也不抓、没有任何警告;start() 一次性把 300 个请求塞进调度器(积压 295),用 needs_backout 退让后积压为 0;start 请求走独立的 FIFO 队列,其它请求优先。
实测 gRPC 取消:cancel 是一个 RST_STREAM(CANCEL),deadline 到期两边各发一个;handler 不监听 ctx 就会继续跑完;流式 Send 在取消后失败并带 Canceled;取消与响应赛跑可能成功也可能 Canceled;调用完成后 cancel() 不发帧;取消沿调用链几乎同时传到下游。
实测 Scrapy 2.19 的 callback / errback / cb_kwargs / meta:404、500 走 errback(HttpError),超时、连接被拒、DNS 失败也走 errback(新的 Download…Error 异常类);回调里抛异常不触发 errback;cb_kwargs 与 meta 在重定向和重试后保留;response.follow 什么都不继承。
实测 Scrapy 2.19 怎么决定响应编码:构造参数 > BOM > HTTP 头 > <meta> > 自动探测;头写错时不报错但满是替换字符,JSON 的键会因此合并丢数据;短 GBK 文本被自动探测成 cp949;gb2312 → gb18030、latin1 → cp1252;只有文本类型的响应才有 .text。
实测 gRPC metadata:键统一小写;普通键只能放可打印 ASCII,-bin 键可放任意字节(线上无填充 base64);user-agent、content-type、grpc-timeout 等库占用的头被静默丢弃;同键多值是多行;头总大小 16 MiB 附近断开;响应头必须在第一条消息之前设置。