在脚本里启动 Scrapy,有 CrawlerProcess、CrawlerRunner 和 2.19 里新出现的 Async 版本。谁装 reactor、谁停 reactor、能不能跑第二次、Ctrl-C 之后发生什么——这篇一项项实测。
$ CrawlerProcess(SET); p.crawl(A); p.start(); p.crawl(A); p.start()
第一次 start() 返回,耗时 0.62 s
第二次: twisted.internet.error.ReactorNotRestartable
$ AsyncCrawlerProcess(SET); p.crawl(A); p.start(); p.crawl(A); p.start()
第一次 start() 返回,耗时 0.78 s
第二次: twisted.internet.error.ReactorNotRestartablereactor 停下后不能再启动,所以脚本里要么把所有 crawl() 排好再 start() 一次,要么自己管 reactor。
CrawlerProcess:crawl(A); crawl(B); start() 总耗时 0.62 s CrawlerRunner:yield crawl(A); yield crawl(B) 总耗时 1.39 s 两种方式服务器收到的请求数:20、20(都是 2 × 10)
CrawlerProcess 把多个 crawler 交给同一个 reactor 并发跑;CrawlerRunner 只给你 Deferred,想顺序就自己链起来。
(a) 没有先 install_reactor 就 CrawlerRunner(SET).crawl(A):退出码 0
builtins.RuntimeError: We expected a Twisted reactor to be installed but it isn't.
(b) 装了 reactor,crawl 结束后没有 reactor.stop():5 秒内输出 'crawl 的 Deferred 触发了\n[超时被杀]',退出码 -9(-9 = 超时被杀:Deferred 触发了,但 reactor.run() 一直不返回,进程不会自己退出)
(c) d.addBoth(lambda _: reactor.stop()):'reactor.run() 返回了',退出码 0,耗时 1.14 sCrawlerRunner 要求 reactor 已经装好、爬完以后由你停掉;忘了 stop 进程不会退出。
装了 asyncio reactor + asyncio.run(main()):退出码 -9,耗时 8.0 s;输出 [超时被杀](8 秒超时被杀,卡死) TWISTED_REACTOR_ENABLED=False + asyncio.run(main()):退出码 0,耗时 1.7 s;输出 crawl 1 完成 / crawl 2 完成 / asyncio.run 返回 装了 asyncio reactor + Deferred.fromFuture(main()) + reactor.run():退出码 0,耗时 1.7 s;输出 crawl 1 完成 / crawl 2 完成 / reactor.run 返回
2.19 的 AsyncCrawlerRunner 返回可 await 的任务,但事件循环要和 reactor 是同一个,或者干脆用无 reactor 模式。
发一次 SIGINT:进程退出码 0,从启动到退出共 3.5 s(第 1.5 s 发的信号)
[scrapy.crawler] INFO: Received SIGINT, shutting down gracefully. Send again to force
[scrapy.core.engine] INFO: Closing spider (shutdown)
start() 返回
finish_reason=shutdown;response_received_count=4;服务器收到 4 个请求
间隔 0.5 s 连发两次 SIGINT:进程退出码 0,从启动到退出共 2.5 s(第 1.5 s 发的信号)
[scrapy.crawler] INFO: Received SIGINT, shutting down gracefully. Send again to force
[scrapy.core.engine] INFO: Closing spider (shutdown)
[scrapy.crawler] INFO: Received SIGINT twice, forcing unclean shutdown
start() 返回
finish_reason=None;response_received_count=None;服务器收到 4 个请求CrawlerProcess 装了 SIGINT/SIGTERM 处理:第一次让引擎优雅关闭,第二次强制退出。