2024 年使用 Next.JS 进行网页抓取

如何在几分钟内从 Next.js 网站抓取数据
Next.js 已迅速成为构建现代 Web 应用程序最流行的框架之一。根据 Statista 的数据,Next.js 是第五大使用最广泛的 Web 技术,为 Netflix、Uber、Twitch 等主要品牌的网站提供支持。

对于网络爬虫来说,Next.js 网站提供了一个独特的机会。由于该框架的底层架构,通常只需几行代码即可从 Next.js 应用程序中提取数据 - 无需复杂的抓取。在本指南中,我们将逐步详细介绍其工作原理。

什么是 Next.js 以及它是如何工作的?
Next.js 是一个 React 框架,支持服务器端渲染 (SSR) 和生成静态网站等关键功能。简而言之,Next.js 允许开发人员构建在服务器而不是客户端上呈现的 React 应用程序。

奇迹是通过一个称为水合作用的过程发生的。当用户访问 Next.js 站点时,会生成初始 HTML 并从服务器发送,以及一个特殊的脚本标记,其中包含 React 组件所需的所有数据。浏览器接收这个 HTML 文档,渲染它,然后 React “水合”静态标记以使其具有交互性。

与动态获取数据的客户端呈现应用程序相比,这种架构使得 Next.js 网站更容易抓取。使用 Next.js,我们想要的数据通常可以在初始服务器响应中获得。

下一个数据标签是关键
为了使水合作用无缝进行,Next.js 包含一个 id 为的脚本标签
下一个数据
在服务器渲染的 HTML 中。这个不起眼的标签包含一个数据宝库——通常是用于生成页面的整个数据对象。

典型的 __NEXT_DATA__ 脚本如下所示:

{
“道具”:{
“页面属性”:{
“产品”: [{
“id”:1,
"title": "产品一",
"description": "第一个产品。",
「价格」:19.99
}, {
“id”:2,
"title": "产品二",
"description": "第二个产品。",
「价格」:29.99
}] }
}
}

如您所见,数据以 JSON 格式方便地提供。要检索它,我们只需要一种访问和解析脚本标记内容的方法。

从 Next.js 网站抓取数据
现在是有趣的部分。让我们逐步了解如何通过几行代码从 Next.js 站点抓取数据。

  1. 首先,在浏览器中加载要抓取的页面并打开开发人员工具。

  2. 在控制台中,选择 __NEXT_DATA__ 脚本标签,如下所示:

const scriptTag = document.getElementById('__NEXT_DATA__');

  1. 获取标签内部内容:

const jsonString = scriptTag.innerHTML;

  1. 解析 JSON 字符串以将其转换为 JavaScript 对象:

const 数据 = JSON.parse(jsonString);

  1. 从 props 访问您需要的数据:

const 产品 = data.props.pageProps.products;
控制台.log(产品);

就是这样!您已成功从 Next.js 页面抓取数据。您现在可以将其保存到文件或执行您需要的任何其他处理。

请注意,数据对象的确切结构将取决于应用程序的构建方式。但在大多数情况下,您要查找的数据将在 data.props.pageProps 内的某个位置可用。

Next.js 13+ 和 self.next_f.push()
在较新版本的 Next.js(13 及更高版本)中,数据水合的工作方式略有变化。而不是 __NEXT_DATA
标签中,您会发现一个或多个内联脚本标签,其中包含对名为 self.__next_f.push() 的函数的调用。

以下是这些标签的示例:

self.__next_f.push({
id: "__next_f_initialTree",
数据: {
树: {
孩子们: [{
名称:“家”,
数据: {
标题:“欢迎来到 Next.js 13”,
产品: [{
编号: 1,
名称:《产品一》
}, {
编号: 2,
名称:《产品二》
}] }
}] }
}
});

要抓取这些数据,我们需要:

  1. 选择页面上的所有脚本标签。

  2. 仅过滤包含 self.__next_f.push() 调用的标签。

  3. 找到id为“__next_f_initialTree”的标签

  4. 从匹配的脚本标签中提取并解析数据。

这是执行此操作的代码片段:

// 选择所有脚本标签
const scriptTags = document.querySelectorAll("script");

// 将 NodeList 转换为数组,以便我们可以使用 filter()
const scriptTagsArray = Array.from(scriptTags);

// 仅过滤带有 self.__next_f.push() 的标签
const nextDataTags = scriptTagsArray.filter(
标签 => tag.innerHTML.includes("self.__next_f.push")
);

// 查找具有initialTree数据的标签
const initialTreeTag = nextDataTags.find(
标签 => tag.innerHTML.includes("__next_f_initialTree")
);

// 提取 () 括号之间的数据字符串
const dataString = initialTreeTag.innerText.split("push(")

。分裂(”);”)
;

// 将数据字符串解析为 JSON

const data = JSON.parse(dataString);

console.log(data.data.tree.children
。数据);

这将记录第一个子路由的数据,在本例中包括一个产品数组。数据结构可能会有所不同,具体取决于特定的 Next.js 应用程序。

  • 反机器人保护和 IP 封锁
  • 虽然从技术角度来看,从 Next.js 站点抓取数据很简单,但还需要考虑其他挑战。许多网站采用反机器人措施来检测和阻止可疑的抓取活动。
  • 一些常见的反机器人技术包括:
  • IP速率限制:阻止短时间内发出过多请求的IP地址。

用户代理检查:在用户代理标头中寻找自动化工具的迹象。

浏览器指纹识别:检测类似刮刀的浏览器属性和行为。

  1. 蜜罐链接:放置只有机器人才能找到并遵循的隐藏链接。

  2. 如果抓取工具被检测到并被阻止,它通常会收到错误响应,例如验证码页面、403 禁止或 429 请求过多。一旦 IP 被封锁,抓取工具将无法再从该地址访问该网站。

  3. 有一些策略可以在抓取时避免检测并防止 IP 块:

  4. 使用轮换代理服务器池在多个 IP 地址之间分发请求。 Bright Data、Smartproxy 和 IPRoyal 等代理服务提供适合抓取的大型数据中心和住宅代理网络。

  5. 设置实际的请求速率限制,并在请求之间设置延迟,以模仿人类行为。过于频繁地发送请求是一个明显的危险信号。

轮换用户代理并创建与真实设备匹配的浏览器配置文件以避免指纹识别。 FingerprintJS 等工具可以帮助生成令人信服的配置。

使用 Puppeteer 或 Playwright 等无头浏览器像真实用户一样与页面交互。这更加耗费资源,但在绕过机器人检测方面非常有效。
监视阻塞迹象(例如验证码),并在检测到阻塞时使用后备逻辑来切换代理或用户代理。

Bright Data Web Unlocker 是一个可以自动处理所有这些问题的 API。它管理代理轮换、重试失败并在幕后解决验证码问题。对于严肃的抓取项目来说,这可以节省大量时间。

结论