实测 Scrapy 2.19 的 item pipeline:按数字顺序调用,DropItem 丢弃并计入 item_dropped_count,其它异常只记 ERROR;open_spider / close_spider 并行执行;返回 None 不是丢弃(下一个管道收到 None,仍计入 item_scraped_count);CONCURRENT_ITEMS 1 → 100 让 50 个 await 0.1 s 的 item 从 5.13 s 降到 0.11 s。
实测 ItemLoader:输入处理器每次 add_value 调用、输出处理器只在 load_item 时调用;TakeFirst 取第一个非 None 非空串(0 算有值)、MapCompose 丢 None 并展平列表;Loader 的 字段_in 压过 Field 元数据压过 default;loader_context 传参;None 不收集而 '' 会收集;默认 item 类是 scrapy.Item,未声明字段 KeyError。
在 Scrapy 2.19.0 本机实测并发限制:默认 asyncio reactor 下 CONCURRENT_REQUESTS_PER_DOMAIN 没有生效(单域名 48 个请求峰值始终 48,SelectReactor 下峰值等于设置值);全局 CONCURRENT_REQUESTS 和 DOWNLOAD_DELAY 有效;PER_IP 和 DOWNLOAD_SLOTS 同样失效;无 reactor 模式的限制来自 aiohttp 连接器。
实测 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 属性已弃用。
实测下载槽:槽名默认是小写主机名(忽略端口和协议),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 秒后被回收。
实测 AutoThrottle:延迟每次向 latency ÷ 目标并发 走一半,约 8 个响应收敛;变慢时一步跳升、变快时折半下降;非 200 响应不会让延迟下降(404 后 delay 保持 506 ms,200 后降到 25 ms);DOWNLOAD_DELAY 是下限、MAX_DELAY 是上限;它只调延迟,实际并发峰值会超过目标。
实测 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 可在回调里手动重试。
实测重定向中间件: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 2.19 的 HTTP 缓存:默认关闭,打开后第二次运行 3 个请求全部命中、服务器 0 个请求;每个请求在磁盘上 7 个文件;DummyPolicy 连 no-store 和 404/500 都缓存;RFC2616Policy 尊重 no-store、max-age、ETag/Last-Modified(304 用缓存正文);EXPIRATION_SECS 过期;服务器关闭时用旧缓存兜底。
实测 CookiesMiddleware:Set-Cookie 自动存进 jar 并带到后续请求;headers 里的 Cookie 会被覆盖,要用 cookies 参数;meta["cookiejar"] 隔离多个会话,但必须自己一路传下去;Path、Secure、Domain、Max-Age 都按规则生效;COOKIES_DEBUG 的日志;dont_merge_cookies。
实测 RobotsTxtMiddleware:内置默认 ROBOTSTXT_OBEY = False 而项目模板写 True;被禁请求抛 IgnoreRequest 且不发出,robots.txt 每个 netloc 只下载一次并排在前面;默认 UA 匹配 User-agent: Scrapy 组;robots.txt 404/500/超时/乱码一律放行;Crawl-delay 被忽略。
用原始套接字服务器看 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 才带。