Cheerio 与 Puppeteer 的网页抓取比较

通过构建网页抓取器,了解 Puppeteer 和 Cheerio 之间的区别。
3 min read
Cheerio与Puppeteer比较

在选择Node.js网页抓取工具时,有几种选择。最常见的两个工具是CheerioPuppeteer

Cheerio 最初是作为一个更高效的jQuery版本,用于解析和操作 HTML 文档。而 Puppeteer 则是为了自动化网页和应用的测试而创建的。

尽管如此,这两个工具在网页抓取中都能发挥作用:Cheerio 使您能够解析网页的 HTML 以找到所需的信息,而 Puppeteer 使您能够自动化一个网页浏览器以抓取使用 JavaScript 的动态网站。

本文将会分析这两个工具,并在功能、性能和易用性方面进行比较。

Cheerio 与 Puppeteer 的比较

Cheerio 和 Puppeteer 之间有一个主要区别:Cheerio 是一个 HTML 解析器,而 Puppeteer 是一个浏览器自动化工具。这意味着这两个工具的工作方式非常不同。

Cheerio 使您能够获取 HTML 文档并通过CSS 选择器找到所需的 HTML 元素。

例如,以下选择器搜索具有h1标签的元素:

const title = $('h1');

您可以在 HTML 代码上运行此选择器,例如以下代码(取自example.com):

<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>

结果是 Cheerio 返回了h1元素,您可以从中提取信息,例如标题名称:

<h1>Example Domain</h1>

要使用 Cheerio,您需要使用类似axios的库来获取网页的 HTML 代码。然后,您可以解析 HTML 代码并找到所需的信息。

例如,以下代码示例下载了example.com的 HTML 代码,解析它,然后找到h1元素的文本:

(async () => {

  const url = 'https://example.com/';
  const response = await axios.get(url); // get HTML
  const $ = cheerio.load(response.data); // parse HTML with Cheerio
  const title = $('h1'); // use selectors to find data you need
  console.log(title.text());

})();

相比之下,Puppeteer 打开一个专用的浏览器实例,并利用浏览器实例可以提供的内容。这意味着它可以与 HTML 页面中不存在的 JavaScript 元素交互。例如,它可以点击按钮进行导航、滚动页面,甚至在页面上下文中执行 JavaScript。

以下是一个脚本示例,该脚本启动浏览器、打开页面并提取所有h1元素的标题。与 Cheerio 相比,Puppeteer 还能够找到可点击的元素,例如More Information按钮,并使用它们进行导航:

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null
  });

  const page = await browser.newPage(); // open browser
  await page.goto('https://example.com/'); // go to the page

  const title = await page.evaluate(async () => { // use selectors to find data you need

    const h1 = document.querySelector('h1');
    return h1.textContent;
  });

  console.log(title);

  more_information = await page.waitForSelector('a');  // can also click on elements!
  await more_information.click();

  await new Promise(r => setTimeout(r, 2000));

  await browser.close(); // close the browser

})();

由于操作方式不同,Puppeteer 更适合抓取使用 JavaScript 使网站像应用程序一样交互的现代网站。相比之下,Cheerio 更适合抓取静态网站,例如博客。

功能

一旦打开包含所有必要信息的页面,这两个库的操作方式非常相似——它们使用 CSS 选择器定位所需的信息并提取它。

Cheerio 使用内置的类似 jQuery 的语法定位信息,这对大多数 JavaScript 开发者来说很方便:

const title = $('h1');

Puppeteer 通常通过在页面上评估 JavaScript(尤其是querySelector和 querySelectorAll 方法)来定位信息并返回结果:

const title = await page.evaluate(async () => {

  const h1 = document.querySelector('h1');
  return h1.textContent;
});

然而,由于 Puppeteer 在浏览器中运行,它具有额外的功能。例如,在页面上,Puppeteer 可以执行用户可以执行的任何操作:

await button.click(); \\ clicking
await form.type('User'); \\ typing

这使得它可以通过任何类型的用户流程,例如注册和身份验证。您还可以使用它通过网站的 UI 搜索信息并找到其他隐藏的信息。

例如,如果有一个网站需要登录,使用 Puppeteer 登录非常简单——只需点击必要的字段并输入用户名和密码,浏览器会处理其他事情。与此同时,您从技术上讲无法使用 Cheerio 登录帐户,因为它只关注解析单个页面,而不是管理网页会话。

Puppeteer 甚至可以执行任意 JavaScript 来操作页面内容。这通常用于滚动页面。因此,您可以使用 Puppeteer 抓取具有无限滚动的网站,而 Cheerio 只能加载第一页。这也使得绕过自定义的反抓取措施变得更加容易。

由于抓取是在浏览器中以自然的操作方式进行的,这也非常有利于调试!您可以禁用无头模式以观察执行过程,并在执行期间注意到网站的问题:

通过构建网页抓取器,了解 Puppeteer 和 Cheerio 之间的区别。

性能

由于 Puppeteer 需要启动并运行浏览器来实现网页抓取,因此启动和执行脚本的速度显著慢于 Cheerio,并且需要更多的计算资源。

例如,以下是对两个 库抓取基本网页所需时间的快速速度测试。

使用以下脚本,您可以打开 Bright Data 博客并提取首页博客文章的链接:

Cheerio

async function cheerio_scrape() {

  const url = 'https://brightdata.com/blog';
  const response = await axios.get(url);
  const $ = cheerio.load(response.data);
  const h5s = $('h5');
  let titles = []
  h5s.each((i, el) => titles.push($(el).text().trim()));
  console.log(titles);

};

Puppeteer

async function puppeteer_scrape() {
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null
  });

  const page = await browser.newPage();
  await page.goto('https://brightdata.com/blog');


  await page.waitForSelector('h5');

  const titles = await page.evaluate(async () => {

    let titles = [];
    const h5s = document.querySelectorAll('h5');
    h5s.forEach(el => titles.push(el.textContent.trim()));
    return titles;
  });

  console.log(titles);
 await browser.close();
};

然后您可以计时两个函数的执行时间。

以下代码计时 Cheerio 脚本的执行时间,大约需要 500 毫秒(但实际情况可能有所不同):

let start = Date.now();
cheerio_scrape().then(() => {
  let end = Date.now();
  console.log(`Execution time: ${end - start} ms`);
});

以下代码计时 Puppeteer 脚本的执行时间:

let start = Date.now();
puppeteer_scrape().then(() => {
  let end = Date.now();
  console.log(`Execution time: ${end - start} ms`);
});

使用 Puppeteer,脚本完成大约需要 4000 毫秒,这显著长于 Cheerio 所需的 500 毫秒。

易用性

如果您是网页抓取的新手,Cheerio 可能更适合,因为它仅处理页面的 HTML 代码。用户无需与网页元素交互并调整脚本的加载时间,这意味着他们可以专注于重要的网页抓取要素,例如创建正确的选择器。

此外,使用 Cheerio,下载网页的 HTML 代码后不会改变。相比之下,对于运行 JavaScript 并进行交互的网站,HTML 会不断变化,变化的时间也有些不可预测。

因此,浏览器自动化工具会使用等待。特别是 Puppeteer 具有waitForSelector函数,该函数等待条件满足,例如页面上出现某个元素。如果元素在给定时间内(默认是 30 秒)不可用,脚本会抛出错误:

await page.waitForSelector('h1')

如果您没有正确设置它们,延迟会使您的脚本变得不太可靠。

此外,对于 JavaScript 开发者来说,Cheerio 的语法应该感觉更简单、更自然。虽然 Puppeteer 功能强大,但它并不是专门为网页抓取设计的,这在使用时会有所体现。

结论

本文分析了 JavaScript 生态系统中两种常用的网页抓取库:Cheerio 和 Puppeteer。由于操作模式的不同,它们各有优劣。Cheerio 更适合针对静态页面的简单网页抓取脚本,而 Puppeteer 则适用于从现代的 JavaScript 丰富网页中抓取信息。

需要注意的是,这两个工具都不是专门为网页抓取设计的。开发者为了抓取网站而适应了这些工具,因为它们提供了处理 HTML 和自动化浏览器的能力。这意味着这些工具的界面并未针对网页抓取者的需求进行优化。

如果您在寻找一个功能强大且易于使用的解决方案,您应该查看Bright Data,一个全面的网页抓取服务。除了抓取网站和自动化浏览器的工具外,Bright Data 还是最大的代理服务提供商,为几十家财富 500 强公司和超过 20,000 名客户提供服务。其全球代理网络包括:

  • 数据中心代理 – 超过 770,000 个数据中心 IP。
  • 住宅代理 – 超过 72M 个来自 195 多个国家的住宅设备 IP。
  • ISP 代理 – 超过 700,000 个来自 ISP 注册设备的 IP。
  • 移动代理 – 超过 7M 个来自移动网络的 IP。

立即开始您的免费试用。