返回资讯中心
外部精选
软件工程
#开发者实时流

Puppeteer与Selenium同环境对比:整体抓取速度接近,单元素读取差距明显

来源标题:Puppeteer vs. Selenium for Web Scraping, Tested on the Same Chrome

在同一Chrome 156环境下对比Puppeteer和Selenium抓取网页,两者抓取五个产品页仅相差79毫秒,整体速度接近。但读取单个元素时Selenium比Puppeteer慢约五倍,在大型爬虫中会显著放大差距。文章通过编写相同爬虫,还比较了请求拦截、指纹检测等场景。

Hacker News 最新noorsimar2026/11/12 · 今天30 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

用真实浏览器做网页抓取,通常有两种常用工具:Puppeteer 通过 Chrome DevTools Protocol 控制 Chrome,而 Selenium 通过 WebDriver 协议控制几乎所有浏览器。

那么哪个更快?差距并不大——在同样运行 Chrome 156 的测试中,两个工具抓取五个产品页面的完成时间只相差 79 毫秒。不过,在读取单个元素时,Selenium 要慢得多——大约比 Puppeteer 慢五倍,在规模较大的抓取器中,这会很快累积成明显差距!

我们将用 Puppeteer 和 Selenium 编写相同的抓取器来比较这两个工具。我们会讨论一些常见问题,比如每个工具如何工作、哪个更快、Puppeteer 能否用于 Python,以及一些高级任务,比如请求拦截与阻断,还有它们在指纹检测中的表现。

Puppeteer 是 Chrome 团队开发的 Node.js 库,用于直接控制 Chrome 和 Firefox;而 Selenium 最初是一个用于测试网站的工具,后来迅速成为几乎支持所有语言和浏览器的通用浏览器自动化框架。

那么该选哪个?我们建议先根据项目所需的编程语言和浏览器来选择,因为就抓取速度而言,在我们的测试中两个工具几乎完全相同。

让我们快速看一下两个工具的对比:

请注意,表中的数字来自我们自己的测试(详情见下面的速度部分),两个工具在同一台机器、同一个 Google Chrome 156 浏览器上运行(bot.sannysoft.com 那一行用的是 157)。

Puppeteer 和 Selenium 使用两种不同的浏览器自动化协议。Puppeteer 使用 Chrome DevTools Protocol(即 CDP)——一种高层协议,允许程序通过单个 socket 连接控制 Chrome。

Selenium 则使用 WebDriver——一个 W3C 协议,一个称为 driver 的中间件程序(Chrome 用 ChromeDriver,Firefox 用 geckodriver)位于我们的代码和浏览器之间,将每条命令翻译成浏览器操作。

CDP 连接是双向的,因此浏览器可以主动向 Puppeteer 发送消息。这意味着网络请求、响应和控制台消息会在页面加载时作为事件到达,我们的抓取器可以立即对它们做出反应。

而在 Selenium 中,每条命令都作为独立的 HTTP 请求发送给 driver——无论是 find_element、.text 还是 get。让我们打开 Selenium 的调试日志并读取一个产品标题,看看实际发生了什么:

import logging from selenium import webdriver from selenium.webdriver.common.by import By options = webdriver.ChromeOptions() options.add_argument("--headless=new") driver = webdriver.Chrome(options=options) driver.get("https://web-scraping.dev/products")

print every HTTP request Selenium sends to ChromeDriver from here on

logging.basicConfig(format="%(message)s") logging.getLogger("selenium.webdriver.remote.remote_connection").setLevel(logging.DEBUG) title = driver.find_element(By.CSS_SELECTOR, ".product h3").text print(title) driver.quit()

在上面的示例中,我们在读取标题之前打开了 Selenium remote_connection 模块的调试日志,这会打印我们的代码发送给 ChromeDriver 的每个请求。如果运行它,我们会看到那一行代码发出了两个请求(我们省略了 "Finished Request" 行、响应头和最后的 DELETE 请求,并缩短了 ID):

POST http://localhost:50086/session/554dfd28.../element {'using': 'css selector', 'value': '.product h3'} Remote response: status=200 | data={"value":{"element-6066-11e4-a52e-4f735466cecf":"f.389A0E62...e.5"}} GET http://localhost:50086/session/554dfd28.../element/f.389A0E62...e.5/text {} Remote response: status=200 | data={"value":"Box of Chocolate Candy"} Box of Chocolate Candy

如你所见,第一个请求找到元素并取回其引用,只有第二个请求才获取文本——所以仅仅读取一个标题就要往返 ChromeDriver 两次!更不用说,driver 是一个独立的程序,还必须与我们的 Chrome 版本匹配。

那 WebDriver BiDi 呢?这是 WebDriver 协议的新版本,可以双向发送消息(就像 CDP 一样),而且两个项目都已经在使用它。Puppeteer 用它来控制 Firefox,而 Selenium 4 用它实现跨浏览器的事件和网络拦截——基本上就是 Puppeteer 通过 CDP 获得的能力!

Chrome CDP 可被检测吗?CDP 与 WebDriver 在浏览器自动化中的对比。Chrome CDP 本身并不隐蔽。了解 CDP、WebDriver、Playwright、Puppeteer、nodriver、Camoufox 和云浏览器如何影响检测。

Puppeteer 比 Selenium 快吗?

是的,但没有你想象的那么多。Puppeteer 启动更快,读取单个元素大约快五倍,但在抓取五个页面时,两个工具的完成时间相差在 4% 以内,因为大部分时间都花在等待页面加载上。

那么 Selenium 在哪里浪费时间?在逐个读取大量元素的循环中,因为每次读取都是两次 WebDriver 调用(先 find,再 .text),而 Puppeteer 直接在页面内部读取。

在这个测试中,我们将使用一个简单的网页抓取任务:两个工具都打开 web-scraping.dev/products 的前五页,收集全部 25 个产品标题。我们还会保持简短,并读取单个标题 200 次,看看每次读取需要多长时间(Puppeteer 通过 $eval,Selenium 通过 find_element 加 .text)。

现在有了测试任务,让我们开始吧!我们将每个工具运行五次,在各自预热运行一次后,在 Puppeteer 和 Selenium 之间轮流进行。我们使用 Puppeteer 25.16.0 搭配 Node.js 26.5,以及 Selenium 4.52.0 搭配 Python 3.14——两者都在一台 Apple M5 MacBook 上控制同一个无头 Google Chrome 156。以下是中位数结果:

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →