
Scrapy 性能基准测试scrapy bench 命令、内置基准服务器与仓库中的 CPU 基准套件【免费下载链接】scrapyScrapy, a fast high-level web crawling scraping framework for Python.项目地址: https://gitcode.com/GitHub_Trending/sc/scrapyScrapy 自带一套轻量级基准测试工具运行scrapy bench即可在本机启动一个 HTTP 服务器并让一个只跟链接的蜘蛛以最大速度爬取它从而得到当前硬件下 Scrapy 的吞吐基线pages/min。读完本文你能掌握scrapy bench的运行方式与输出解读、命令背后子进程服务器与蜘蛛的实现细节源码级以及仓库中用于追踪引擎性能回归的 pytest-codspeed CPU 基准套件为你的爬虫性能调优建立可对比的基准。基准测试的目标与设计思路官方文档 benchmarking.rst 对基准测试的定位非常明确启动一个本地 HTTP 服务器以尽可能快的速度爬取它目标是了解 Scrapy在你的硬件上表现如何为不同版本、不同配置之间的比较提供一个共同基线使用的蜘蛛什么都不做只是跟链接a simple spider that does nothing and just follows links。这是一种压力上限式测量它不模拟真实业务中解析、入库、延迟、反爬等待成本因此测出的速率是引擎与网络栈在理想条件下的吞吐上限适合作为对比锚点而不是对你自己爬虫的实际预估。运行 scrapy bench 并解读输出运行方式只有一条命令scrapy bench安装文档 也推荐用它来验证 Scrapy 是否安装成功。该命令会打印与真实爬取几乎一致的启动日志启用的扩展、下载器中间件、蜘蛛中间件随后每秒输出一行进度统计例如2016-12-16 21:18:49 [scrapy.core.engine] INFO: Spider opened 2016-12-16 21:18:49 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2016-12-16 21:18:50 [scrapy.extensions.logstats] INFO: Crawled 70 pages (at 4200 pages/min), scraped 0 items (at 0 items/min) ... 2016-12-16 21:18:59 [scrapy.core.engine] INFO: Closing spider (closespider_timeout) 2016-12-16 21:18:59 [scrapy.extensions.logstats] INFO: Crawled 518 pages (at 2880 pages/min), scraped 0 items (at 0 items/min) 2016-12-16 21:19:00 [scrapy.statscollectors] INFO: Dumping Scrapy stats: {downloader/request_bytes: 229995, downloader/request_count: 534, downloader/response_bytes: 1565504, downloader/response_count: 534, downloader/response_status_count/200: 534, finish_reason: closespider_timeout, request_depth_max: 19, scheduler/dequeued: 533, scheduler/dequeued/memory: 533, scheduler/enqueued: 10661, scheduler/enqueued/memory: 10661, ...} 2016-12-16 21:19:00 [scrapy.core.engine] INFO: Spider closed (closespider_timeout)输出中几个关键点速率读数官方示例约 10 秒爬了 518 页即大约3000 pages/min。每秒一行日志来自LOGSTATS_INTERVAL: 1由 LogStats 扩展 打印累计页数与瞬时速率pages/min。结束原因closespider_timeout爬取在 10 秒后被 CloseSpider 扩展 以超时为由关闭CLOSESPIDER_TIMEOUT: 10。这两个设置并非来自你的配置文件而是bench命令自带的默认设置见下文源码分析。调度器统计揭示去重scheduler/enqueued: 10661而scheduler/dequeued只有 533。服务器端每个页面都会生成随机链接大量链接指向相同 URL调度器的去重机制过滤掉了大部分重复项——所以请求数远少于入队数这正是只跟链接场景下调度器正常工作的一部分。不要拿它当你的爬虫速率文档特别提醒这是最简蜘蛛你自己写的 spider 通常会做更多事解析、字段提取、Item 处理实际爬取速率会更慢慢多少取决于 spider 的工作量与实现质量。源码解析bench 命令如何工作命令入口与默认设置scrapy bench的实现是 bench.py。命令类 Command 携带一组内置默认设置class Command(ScrapyCommand): default_settings: ClassVar[dict[str, Any]] { LOG_LEVEL: INFO, LOGSTATS_INTERVAL: 1, CLOSESPIDER_TIMEOUT: 10, } def run(self, args: list[str], opts: argparse.Namespace) - None: with _BenchServer(): self.crawler_process.crawl(_BenchSpider, total100000) self.crawler_process.start()LOGSTATS_INTERVAL: 1对应输出中每秒一行的Crawled N pages (at X pages/min)CLOSESPIDER_TIMEOUT: 10对应输出末尾的Closing spider (closespider_timeout)即基准固定跑 10 秒爬取的蜘蛛是同一个模块内定义的_BenchSpider链接池规模通过total100000传入。内置基准 HTTP 服务器_BenchServerbench.py是一个上下文管理器进入时用当前解释器以子进程方式启动基准服务器读取首行输出表示服务器就绪后才开始爬取退出时kill()掉该进程并等待其结束。class _BenchServer: def __enter__(self) - None: pargs [sys.executable, -u, -m, scrapy.utils.benchserver] self.proc subprocess.Popen(pargs, stdoutsubprocess.PIPE, envget_testenv()) self.proc.stdout.readline() def __exit__(self, exc_type, exc_value, traceback): self.proc.kill() self.proc.wait() time.sleep(0.2)服务器本体是 benchserver.py基于 Twisted Web 实现端口 8998__main__块通过reactor.listenTCP(8998, Site(root))监听本机 8998 端口并在启动时打印Bench server at http://...:8998见 benchserver.py任意路径都渲染同一个页面Root资源的getChild始终返回自身因此/follow?...下任意路径都命中同一渲染逻辑benchserver.py随机链接树每次渲染读取total默认 100与show默认 10两个查询参数随机取show个[1, total]范围内的整数为每个整数生成一个形如a href/follow?total...show...nNfollow N/a的链接。链接目标 URL 由参数决定从而形成一个规模可控、无重复死循环的随机链接网络。服务器端这套渲染逻辑有专门的单元测试 test_utils_benchserver.py验证了链接数量、取值范围以及 HTML 结构如test_render断言生成恰好show个 1..total 范围内的链接。基准蜘蛛只跟链接_BenchSpiderbench.py结构极简class _BenchSpider(scrapy.Spider): A spider that follows all links name follow total 100000 show 20 baseurl http://localhost:8998 link_extractor LinkExtractor() async def start(self) - AsyncIterator[Any]: qargs {total: self.total, show: self.show} url f{self.baseurl}?{urlencode(qargs, doseqTrue)} yield scrapy.Request(url, dont_filterTrue) def parse(self, response: Response) - Any: for link in self.link_extractor.extract_links(response): yield scrapy.Request(link.url, callbackself.parse)total100000、show20决定了链接池规模每个页面 20 条随机链接池子足够大10 秒内不会把所有页面都爬完起点请求使用dont_filterTrue避免去重器把唯一一条入口 URL 过滤掉parse回调只做一件事用 LinkExtractor 提取链接并逐个发起Request没有任何解析、Item 产出或 I/O 之外的重逻辑——这正是引擎吞吐上限测量的前提。仓库中的 CPU 基准套件pytest-codspeed除了scrapy bench这条面向用户的命令仓库还维护了一套面向开发者的 CPU 基准测试位于 tests/benchmarks基于pytest-codspeedconftest.py 中安装AsyncioSelectorReactor并以reactor.iterate()手动驱动事件循环。这些基准用于持续追踪引擎层面的性能回归。tests/benchmarks/test_crawl.py 按维度拆分了多种场景比scrapy bench精细得多基准测量目标test_parse_http/test_parse_engine在真实书籍快照页面上做链接提取 CSS/XPath 字段解析的成本带/不带真实 HTTP I/Otest_overhead_http/test_overhead_engine单请求经过引擎、中间件、下载处理器的固定开销页面刻意做得很小test_overhead_broad广域爬取每主机一页shallow与少主机多页deep两种布局的调度开销差异test_overhead_concurrencyCONCURRENT_REQUESTS_PER_DOMAIN: 1受限并发的开销test_overhead_delay每个请求都受DOWNLOAD_DELAY等待的场景关闭随机化以保证可复现test_overhead_items/test_overhead_item_concurrencyItem 经 Item Pipeline 传递的开销以及CONCURRENT_ITEMS并发上限生效时的表现其关键技巧是 NullDownloadHandler一个不做任何 I/O 的下载处理器直接把响应凭空返回让基准只测量引擎、调度器与中间件而不受 HTTP 解析、DNS 或套接字影响同时它用await asyncio.sleep(0)让出一次事件循环保证并发限制依然真实生效并用benchmark/peak_concurrency统计跟踪峰值并发。真实 HTTP 场景则复用测试用 mock 服务器的/follow资源http_resources.py该资源额外支持orderdesc/rand与maxlatency模拟网络延迟参数比scrapy bench的服务器更灵活。适用前提与进阶建议适用前提scrapy bench依赖本机可用端口 8998scrapy.utils.benchserver硬编码监听该端口且使用当前 Python 解释器启动子进程服务器它测量的是跟链接上限不含真实业务解析成本解读方式把同一台机器、同一版本配置下的速率作为基线再对比修改后的数值才有意义跨机器、跨硬件的绝对值没有可比性更复杂的基准官方文档指出如需更复杂的基准测试应使用社区项目 scrapy-bench文档中 benchmarking.rst 的延伸阅读。对于我的具体爬虫为什么慢这类问题建议结合 性能调优指南 定位瓶颈而不是只看 bench 数字可深入的仓库位置命令实现 scrapy/commands/bench.py、服务器实现 scrapy/utils/benchserver.py、CPU 基准套件 tests/benchmarks/、命令说明 commands.rst。【免费下载链接】scrapyScrapy, a fast high-level web crawling scraping framework for Python.项目地址: https://gitcode.com/GitHub_Trending/sc/scrapy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考