![Laucher](../avatar.jpeg)
Laucher
2023年 01月 15日
最佳 Node.js 网页抓取(爬虫)工具
网页抓取工具是一种从网站和网络API中获取信息的工具或脚本,它可以帮助您提取洞察力或编制包含信息的数据库。例如,像谷歌、百度等这些搜索引擎会抓取网络以对站点进行索引,并将其作为用户查询的结果提供。
![封面图](/static/79f7e1cbffc3c144b71a5ba18043c54a/9efee/reptile.webp)
在本文中,我们将探讨一些最佳的 Node.js 网页抓取库和技术。您还将了解它们之间的区别,以便在考虑项目需求时选择合适的工具。首先,我们将回顾一些在选择网页抓取工具之前需要牢记的事项。
在开始进行网页抓取之前需要了解的事项
尽管抓取公开可用信息是合法的,但您应该意识到许多网站在其服务条款中设置了限制。有些甚至可能会包括速率限制,以防止您减慢他们的服务速度 —— 但这是为什么呢?
当您从网站上抓取信息时,您使用了它的资源。
假设您在访问过多页面时过于激进,那么您可能会降低该网站对其用户的总体性能。因此,在进行网页抓取时,您必须获得所有者的同意或许可,并注意您对其网站施加的压力。
最后,网页抓取需要进行大量的开发工作,并且在许多情况下需要进行维护。目标网站结构的变化可能会破坏您的抓取代码,并要求您更新脚本以适应新的格式。
因此,我更倾向于在可能的情况下使用 API,并将网页抓取仅作为最后的选择。现在,让我们开始对最佳的 Node.js 网页抓取库进行评估。
最佳的 Node.js 网页抓取库
Axios
如果您熟悉 Axios,它可能并不是用于网页抓取的最吸引人的选项。尽管如此,它是一个简单的解决方案,可以帮助您完成任务,并且它还具有一个附加优势,即您可能已经相当熟悉这个库。
Axios 是一个基于 Promise 的 Node.js HTTP 客户端,在 JavaScript 项目中因其简单性和适应性而广受欢迎。虽然 Axios 通常用于调用 REST API,但它也可以获取网站的 HTML。
由于 Axios 只会从服务器获取响应,您需要自己解析和处理结果。因此,我建议在处理 JSON 响应或进行简单的抓取时使用此库。
您可以使用您喜欢的包管理器来安装 Axios,步骤如下:
npm install axios
以下是使用 Axios 的示例,从 LogRocket 博客主页列出所有文章的标题: const axios = require(‘axios’);
app.get("/axios", (req, res) => {
axios
.get("https://czhlove.cn")
.then(function (response) {
const reTitles = /<h2.*?class=".*?MuiTypography-root\sMuiTypography-h2\sMuiTypography-gutterBottom\scss-1dem3ju.*?".*?>(.*?)<\/h2>/g;
const t = [];
[...response.data.matchAll(reTitles)].forEach(title => t.push({ 'title': `- ${title[1]}` }));
res.json(t);
});
});
/**
[
{
"title": "- JavaScript 数组常用方法"
},
{
"title": "- 漫游孤独:一个人的旅行"
},
{
"title": "- TypeScript的装饰器"
},
{
"title": "- TypeScript的命名空间和模块"
},
{
"title": "- TypeScript的高级类型"
},
{
"title": "- TypeScript的泛型"
},
{
"title": "- TypeScript的数组类型"
},
{
"title": "- TypeScript的接口和对象类型"
},
{
"title": "- TypeScript的基础类型"
},
{
"title": "- Vue3的script-setup 模式中父组件获取子组件的数据"
}
]
*/
在上面的示例中,您可以看到 Axios 在处理 HTTP 请求方面非常出色。然而,解析复杂结构的 HTML 需要详细的规则,甚至对于简单的任务都需要使用复杂的规则或正则表达式。
因此,如果正则表达式不是您的菜,而您更喜欢基于 DOM 的方法,您可以使用诸如 JSDom 或 Cheerio 等库将 HTML 转换为类似 DOM 的对象。让我们使用 JSDom 来探索上面的相同示例:
app.get("/axiosJSDOM", (req, res) => {
axios
.get("https://czhlove.cn")
.then(function (response) {
const dom = new JSDOM(response.data);
const t = [];
[...dom.window.document.querySelectorAll('.MuiTypography-h2')].forEach(el => t.push({ 'title': `- ${el.textContent}` }));
res.json(t);
});
});
// 输出结果不变,但是基于 DOM 的方法更简单。
但是,这种解决方案很快会遇到其局限性。例如,您只会从服务器获得原始响应 —— 如果您想要访问的页面上的元素是异步加载的呢?
那么对于单页面应用程序(SPA)呢?在这种情况下,HTML 只是加载在客户端上执行所有渲染工作的 JavaScript 库。或者,如果您遇到这些库强加的限制怎么办?毕竟,它们并不是完整的 HTML/DOM 实现,而只是其中的一个子集。
在这些情况下,或者对于复杂的网站,可能最佳选择是使用其他库采用完全不同的方法。
Puppeteer
Puppeteer 是一个高级的 Node.js API,可以通过代码控制 Chrome 或 Chromium。那么,从网页抓取的角度来看,这对我们意味着什么呢?
使用 Puppeteer,您可以访问一个完整的浏览器,比如在后台以无头模式运行的 Chromium,以便浏览网站并完全渲染样式、脚本和异步信息。
要在项目中使用 Puppeteer,您可以像使用任何其他 JavaScript 包一样进行安装:
npm install puppeteer
现在,让我们看一个 Puppeteer 的实际示例:
const puppeteer = require("puppeteer");
async function parseLogRocketBlogHome() {
// 启动浏览器
const browser = await puppeteer.launch();
// 打开一个新标签
const page = await browser.newPage();
// 访问该页面并等待,直到网络连接完成
await page.goto('https://czhlove.cn', { waitUntil: 'networkidle2' });
// 与DOM交互以检索标题
const titles = await page.evaluate(() => {
// 选择所有指定的标签类的元素
return [...document.querySelectorAll('.MuiTypography-h2')].map(el => el.textContent);
});
// 不要忘记关闭浏览器实例来清理内存
await browser.close();
// 打印结果
titles.forEach(title => console.log(`- ${title}`))
// - JavaScript 数组常用方法
// - 漫游孤独:一个人的旅行
// - TypeScript的装饰器
// - TypeScript的命名空间和模块
// - TypeScript的高级类型
// - TypeScript的泛型
// - TypeScript的数组类型
// - TypeScript的接口和对象类型
// - TypeScript的基础类型
// - Vue3的script-setup 模式中父组件获取子组件的数据
}
parseLogRocketBlogHome();
虽然 Puppeteer 是一个很棒的解决方案,但它在使用上更复杂,特别是对于简单的项目。从资源需求的角度来看,它要求更高 — 毕竟,您正在运行一个完整的 Chromium 浏览器,而我们知道这些浏览器可能会消耗大量内存。
X-Ray
X-Ray 是一个专为网页抓取而创建的 Node.js 库,因此它的 API 在很大程度上专注于这个任务。因此,它将我们在 Puppeteer 和 Axios 中遇到的大部分复杂性都进行了抽象。
要安装 X-Ray,您可以运行以下命令:
npm install x-ray
现在,让我们使用 X-Ray 来构建我们的示例:
const Xray = require('x-ray');
const x = Xray()
x('https://czhlove.cn', {
titles: ['.card-title a']
})((err, result) => {
result.titles.forEach(title => console.log(`- ${title}`));
});
// 打印结果:
// - JavaScript 数组常用方法
// - 漫游孤独:一个人的旅行
// - TypeScript的装饰器
// - TypeScript的命名空间和模块
// - TypeScript的高级类型
// - TypeScript的泛型
// - TypeScript的数组类型
// - TypeScript的接口和对象类型
// - TypeScript的基础类型
// - Vue3的script-setup 模式中父组件获取子组件的数据
如果您的使用情景涉及大量网页抓取,X-Ray 是一个很好的选择。它支持并发和分页,因此您不需要担心这些细节。
Superagent
Superagent 是一个轻量级、渐进式的用于处理 HTTP 请求的客户端 Node.js 库。由于其简单性和易用性,它通常被用于网页抓取。
与 Axios 类似,Superagent 也仅限于从服务器获取响应;您需要自己解析和处理结果。根据您的抓取需求,您可以使用 Superagent 获取 HTML 页面、JSON 数据或其他类型的内容。
要在项目中使用 Superagent,您可以像使用任何其他 JavaScript 包一样进行安装:
npm install superagent
在抓取 HTML 页面时,您必须解析 HTML 内容以提取所需数据。为此,您可以使用像 Cheerio 或 JSDOM 这样的库。
要在项目中使用 Cheerio,您可以像使用任何其他 JavaScript 包一样进行安装:
npm install cheerio
让我们来看一个使用 Superagent 和 Cheerio 进行网页抓取的示例:
const superagent = require("superagent");
const cheerio = require("cheerio");
const url = "https://czhlove.cn";
superagent.get(url).end((err, res) => {
if (err) {
console.error("获取网站时出错:", err);
return;
}
const $ = cheerio.load(res.text);
// 请将以下选择器替换为您想要抓取的实际 HTML 元素:
const titles = $(".MuiTypography-h2")
.map((i, el) => $(el).text())
.get();
// 打印抓取的数据:
console.log("Titles:", titles);
});
// 打印结果:
// Titles: [
// 'JavaScript 数组常用方法',
// '漫游孤独:一个人的旅行',
// 'TypeScript的装饰器',
// 'TypeScript的命名空间和模块',
// 'TypeScript的高级类型',
// 'TypeScript的泛型',
// 'TypeScript的数组类型',
// 'TypeScript的接口和对象类型',
// 'TypeScript的基础类型',
// 'Vue3的script-setup 模式中父组件获取子组件的数据'
// ]
该脚本将使用 Superagent 进行 HTTP GET 请求到指定的 URL,获取页面的 HTML 内容,然后使用 Cheerio 从指定的选择器中提取数据。
虽然 Superagent 是一个很好的解决方案,但在进行网页抓取时使用它可能会导致数据提取不完整或不准确,从而导致数据不一致,这取决于网站结构的复杂性和所使用的解析方法。
Playwright
Playwright 是一个强大的工具,用于网页抓取和浏览器自动化,尤其是在处理具有动态内容和复杂交互的现代网页应用程序时。其多浏览器支持、自动化能力和性能使其成为开发人员在 Node.js 应用程序中执行高级网页抓取任务的绝佳选择。
Playwright 是由微软开发的相对较新的开源库。它提供对浏览器状态、Cookie、网络请求和浏览器事件的完全控制,使其在复杂的抓取场景中非常适用。
要在项目中使用 Playwright,您可以按照以下方式进行安装:
npm install playwright
让我们来看一个使用 Playwright 进行网页抓取的示例:
const { chromium } = require("playwright");
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
const url = "https://czhlove.cn"; // 请将其替换为您想要抓取的网站的 URL。
try {
await page.goto(url);
// 请将以下选择器替换为您想要抓取的实际 HTML 元素。
const titleElement = await page.$(".MuiTypography-h2");
const title = await titleElement.textContent();
console.log("Title:", title);
} catch (error) {
console.error("Error:", error);
} finally {
await browser.close();
}
})();
这个脚本将会启动一个 Chromium 浏览器,导航到指定的 URL,并使用 Playwright 的方法与网站进行交互,并从指定的选择器中提取数据。
Playwright 是一个强大的抓取库,但与轻量级的基于 HTTP 的抓取库相比,它会产生更多的资源开销,因为它使用无头浏览器来执行抓取任务。这可能会影响性能和内存使用,特别是如果您正在抓取多个页面或执行大量的抓取任务。
哪个是最好的 Node.js 网络爬虫?
“最佳” Node.js 网络爬虫取决于您的特定需求以及您打算执行的爬取任务的复杂性。提到的每个库 - Axios、X-Ray、Puppeteer、Superagent、Cheerio 和 Playwright - 都有其自身的优点和缺点。以下是它们主要特点的简要概述:
Axios:适用于基本的网络请求,简单且轻量。适合涉及进行HTTP请求的简单爬取任务。
X-Ray:适用于爬取多个网页,具有内置的并发和分页支持。与Puppeteer和Playwright相比,提供更简单的API。
Puppeteer:适用于浏览器自动化,特别是对于动态和复杂的网站。可以处理现代的、JavaScript-heavy的网站并执行交互。
Superagent:轻量级的HTTP库,用于处理请求。对于基本的爬取任务可能会有用。
Cheerio:优秀用于解析HTML并从DOM中提取数据。不需要浏览器,适用于较简单的爬取任务,可以高效地工作。
Playwright:适用于爬取具有复杂交互的现代Web应用程序。提供完整的浏览器控制,适用于更高级的爬取任务。
对于大多数任务来说,任何这些选项都足够满足要求,所以请选择您感觉最舒适的选项。在我的职业生涯中,我有机会使用公开可用信息和内部系统从头构建多个项目,以满足信息收集的需求。
由于需求各异,这些项目中的每一个都采用了不同的方法和库,从Axios到X-Ray不一而足,最终在最复杂的情况下采用了Puppeteer。
最后,无论您选择哪个爬虫,都应始终尊重网站的条款和条件。数据爬取可以是一个强大的工具,但这也伴随着巨大的责任。感谢您的阅读!