在选择Node.js网页抓取工具时,有几种选择。最常见的两个工具是Cheerio和Puppeteer。
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,并且需要更多的计算资源。
例如,以下是对两个 库抓取基本网页所需时间的快速速度测试。
使用以下脚本,您可以打开 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。
立即开始您的免费试用。