使用 JavaScript 和 Node.js 进行网页爬虫指南

我们将介绍为什么前端 JavaScript 不是网页爬虫的最佳选择,并教你如何从零开始构建一个 Node.js 爬虫工具。
7 分钟阅读
使用 JavaScript 和 Node.js 进行网页抓取指南博客图片

在本文中,我们将讨论:

  • 使用前端 JavaScript 进行网页爬虫
  • 先决条件
  • 用于 Node.js 的网页爬虫库
  • 结论

使用前端 JavaScript 进行网页爬虫

谈到网页爬虫时,前端 JavaScript 是一种受限的解决方案。首先,因为你必须直接从浏览器控制台运行你的 JavaScript 网页爬虫脚本。这不是一种可以以编程方式执行的操作。

具体来说,你可以按如下方式从控制台爬虫页面中的数据:

在前端运行 JS 网页抓取脚本

在前端运行 JS 网页爬虫脚本

其次,如果你想从其他网页爬虫数据,就必须通过 AJAX 下载它们。但不要忘记,Web 浏览器会对 AJAX 应用同源策略。因此,使用前端 JavaScript,你只能访问同一来源内的网页。

让我们通过一个简单示例来理解这意味着什么。假设你正在访问来自 brightdata.com 的页面。那么,你的前端 JavaScript 网页爬虫脚本只能下载 brightdata.com 域名下的网页。

请注意,这完全不意味着 JavaScript 不是一种适合网页爬虫的好技术。实际上,Node.js 允许你在服务器上运行 JavaScript,并避免上述两个限制。

现在让我们了解如何使用 Node.js 构建 JavaScript 网页爬虫工具。

先决条件

在你开始开发 Node.js 网页爬虫应用之前,需要满足以下先决条件列表:

  • Node.js 18+ 与 npm 8+:任何包含 npm 的 Node.js 18+ LTS(长期支持)版本都可以。本教程基于 Node.js 18.12 与 npm 8.19,在撰写本文时它代表 Node.js 的最新 LTS 版本。
  • 支持 JavaScript 的 IDE:IntelliJ IDEA 的 Community Edition 是本教程选择的 IDE,但任何其他支持 JavaScript 和 Node.js 的 IDE 都可以。

点击上面的链接并按照安装向导设置你所需的一切。你可以通过在终端中启动以下命令来验证 Node.js 是否已正确安装:

node -v

这应该返回类似如下内容:

v18.12.1

同样,使用以下命令验证 npm 是否已正确安装

npm -v 

这应该返回类似这样的字符串:

8.19.2

上面两个命令分别表示你机器上全局可用的 Node.js 和 npm 版本。

太棒了!你现在已经准备好了解如何在 Node.js 中执行 JavaScript 网页爬虫了!

用于 Node.js 的最佳 JavaScript 网页爬虫库

让我们探索用于在 Node.js 中进行网页爬虫的最佳 JavaScript 库:

  • Axios – 一个易于使用的库,可帮助你在 JavaScript 中发起 HTTP 请求。你可以在浏览器和 Node.js 中使用 Axios,它代表了最受欢迎的 JavaScript HTTP 客户端之一。
  • Cheerio – 一个轻量级库,提供类似 jQuery 的 API 来探索 HTML 和 XML 文档。你可以使用 Cheerio 解析 HTML 文档、选择 HTML 元素并从中提取数据。换句话说,Cheerio 提供了一个高级网页爬虫 API。
  • Selenium – 一个支持多种编程语言的库,你可以用它为 Web 应用构建自动化测试。你也可以将其无头浏览器功能用于网页爬虫目的。阅读我们详细的 Selenium 网页爬虫指南
  • Playwright – 一个由 Microsoft 开发的用于为 Web 应用创建自动化测试脚本的工具。它提供了一种指示浏览器执行特定操作的方式。因此,你可以将 Playwright 用于网页爬虫,作为无头浏览器解决方案。
  • Puppeteer – 一个由 Google 开发的用于自动化 Web 应用测试的工具。Puppeteer 构建在 Chrome DevTools 协议之上。就像 Selenium 和 Playwright 一样,它允许你像人类用户一样以编程方式与浏览器交互。了解更多关于 Selenium 和 Puppeteer 之间差异的信息。

在 Node.js 中构建 JavaScript 网页爬虫工具

在这里,你将学习如何在 Node.js 中构建一个能够从网站自动提取数据的 JavaScript 网页爬虫工具。具体来说,目标网页将是 Bright Data 主页。Node.js 网页爬虫过程的目标是从页面中选择感兴趣的 HTML 元素,从中检索数据,并将爬虫到的数据转换为更有用的格式。

在撰写本文时,Bright Data 主页如下所示:

Bright Data 主页 gif

Bright Data 主页的总体视图

正如你可以注意到的,Bright Data 主页包含大量不同格式的数据和信息,从文本描述到图片。此外,它还包含很多有用链接。你将学习如何检索所有这些数据。

现在让我们通过分步教程来看看如何使用 Node.js 抓取数据!

步骤 1:设置 Node.js 项目

首先,使用以下命令创建将包含你的 Node.js 网页抓取项目的文件夹:

mkdir web-scraper-nodejs

你现在应该有一个空的 web-scraper-nodejs 目录。请注意,你可以给项目文件夹取任何想要的名称。使用以下命令进入文件夹:

cd web-scraper-nodejs

现在,使用以下命令初始化 npm 项目:

npm init -y

此命令将为你设置一个新的 npm 项目。请注意,-y 标志是必需的,它使 npm 无需通过交互式流程即可初始化默认项目。如果省略 -y 标志,终端中会询问你一些问题。

web-scraper-nodejs 现在应包含一个如下所示的 package.json

{
  "name": "web-scraper-nodejs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

现在,在项目的根文件夹中创建一个 index.js 文件,并按如下方式初始化它:

// index.js

console.log("Hello, World!")

这个 JavaScript 文件将包含 Node.js 网页抓取逻辑。

打开你的 package.json 文件,并在 scripts 部分添加以下脚本:

"start": "node index.js"

你现在可以在终端中运行以下命令来启动你的 Node.js 脚本:

npm run start

这应该返回:

Hello, World!

这意味着你的 Node.js 应用正在正确运行。现在,在你的 IDE 中打开项目,并准备在 Node.js 中编写一些抓取逻辑!

如果你是 IntelliJ IDEA 用户,你应该会看到以下内容:

步骤 2:安装 Axios 和 Cheerio

现在是安装在 Node.js 中实现网页爬虫工具所需依赖项的时候了。要弄清楚应该采用哪些 JavaScript 网页抓取库,请访问目标网页,右键点击空白部分,然后选择“Inspect”选项。这应该会打开你浏览器的 DevTools 窗口。在 Network 选项卡中,查看 Fetch/XHR 部分。

Fetch XHR 部分几乎为空

请注意,Fetch/XHR 部分几乎为空

目标页面的 AJAX 请求没有显示重要数据;相反,所需信息直接位于网页的源代码中,这对于在服务器端渲染的网站来说很典型。这意味着页面不需要 JavaScript 来显示内容或获取数据,因此无需使用无头浏览器进行抓取。为了避免使用浏览器带来的额外负载,更简单的解决方案是将 Cheerio 与 Axios 一起使用,这样更高效并避免不必要的复杂性。

因此,使用以下命令安装 cheerioaxios

npm install cheerio axios

然后,通过向 index.js 添加以下两行代码来导入 cheerioaxios

// index.js

const cheerio = require("cheerio")
const axios = require("axios")

现在让我们编写一个使用 Cheerio 和 Axios 执行网页抓取的 Node.js 网页抓取脚本!

步骤 3:下载你的目标网站

使用 Axios 通过以下代码行连接到你的目标网站:

// downloading the target web page 
// by performing an HTTP GET request in Axios
const axiosResponse = await axios.request({
    method: "GET",
    url: "https://brightdata.com",
})

借助 Axios 的 request() 方法,你可以执行任何 HTTP 请求。具体来说,如果你想下载网页的源代码,就必须对其 URL 执行 HTTP GET 请求。通常,Axios 会立即返回一个 Promise。你可以使用 await 关键字等待 Promise 并同步获取其值。

请注意,如果 request() 失败,将抛出一个 Error。这可能由多种原因引起,从无效 URL 到服务器暂时不可用。此外,不要忘记有些网站会实施反爬虫措施。最流行的措施之一涉及阻止没有有效 User-Agent HTTP 标头的请求。了解更多关于用于网页抓取的 User-Agent 的信息。

默认情况下,Axios 将使用以下 User-Agent

axios <axios_version>

这并不像浏览器使用的 User-Agent。因此,反抓取技术可能会检测并阻止你的 Node.js 网页爬虫工具。

通过向传递给 request() 的对象添加以下属性,在 Axios 中设置有效的 User-Agent 标头:

headers: {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
}

headers 属性允许你在 Axios 中设置任何 HTTP 标头。

你的 index.js 文件现在应该如下所示:

// index.js

const cheerio = require("cheerio")
const axios = require("axios")

async function performScraping() {
    // downloading the target web page
    // by performing an HTTP GET request in Axios
    const axiosResponse = await axios.request({
        method: "GET",
        url: "https://brightdata.com",
        headers: {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
        }
    })
}

performScraping()

请注意,你只能在标记为 async 的函数中使用 await。这就是为什么你必须将 JavaScript 网页抓取逻辑嵌入到 async performScraping() 函数中。

现在让我们花一些时间分析目标网页,以定义网页抓取策略。

步骤 4:检查 HTML 页面

如果你查看 Bright Data 主页,会看到一个行业列表,显示可以使用 Bright Data 的行业。这是值得抓取的有趣数据。

右键点击这些 HTML 元素之一并选择“Inspect”:

与目标 HTML 元素相关的 DevTools 窗口

与目标 HTML 元素相关的 DevTools 窗口

通过分析所选节点的 HTML 代码,你会看到该卡片是一个 <a> HTML 元素。具体来说,这个 <a> 包含:

  1. 一个 <figure> HTML 元素,其中包含与行业领域相关的图片
  2. 一个 <div> HTML 元素,其中包含行业领域的名称

现在,请注意表征这些 HTML 元素的 CSS 类。使用它们,你将能够定义从 DOM 中选择这些 HTML 元素所需的 CSS 选择器。具体来说,请注意 .e-container 卡片包含在 .elementor-element-7a85e3a8 <div> 中。然后,给定一张卡片,你可以使用以下 CSS 选择器提取其所有相关数据:

  1. .elementor-image-box-img img
  2. .elementor-image-box-content .elementor-image-box-title

类似地,你可以应用相同的逻辑来定义所需的 CSS 选择器,以:

  • 提取 Bright Data 成为行业领导者的原因。
  • 选择使 Bright Data 提供的客户体验成为市场最佳的原因。

换句话说,目标网页有三个爬虫目标:

  1. 关于你可以利用 Bright Data 的行业的数据。
  2. 关于 Bright Data 成为行业领导者的原因的数据。
  3. 关于为什么 Bright Data 提供业内最佳客户体验的数据。

步骤 5:使用 Cheerio 选择 HTML 元素

Cheerio 提供了多种从网页中选择 HTML 元素的方法。但首先,你必须使用以下方式初始化 Cheerio:

// parsing the HTML source of the target web page with Cheerio
const $ = cheerio.load(axiosResponse.data)

Cheerio 的 load() 方法接受字符串形式的 HTML 内容。请注意,Axios 响应对象在 data 属性中包含 HTTP 请求返回的数据。在这种情况下,data 将存储服务器返回的网页 HTML 源代码。因此,你将 axiosResponse.data 传递给 load() 以初始化 Cheerio。

你应该将 Cheerio 变量命名为 $,因为 Cheerio 基本上与 jQuery 共享相同的语法。这样,你就能够从互联网上复制 jQuery 代码片段。

你可以使用 Cheerio 通过类来选择 HTML 元素:

const htmlElement = $(".elementClass")

类似地,你可以使用 ID 检索 HTML 元素:

const htmlElement = $("#elementId")

具体来说,你可以通过向 $ 传递任何有效的 CSS 选择器来选择 HTML 元素,就像在 jQuery 中所做的那样。你还可以使用 find() 方法串联选择逻辑:

// retrieving the list of industry cards
const industryCards = $(".elementor-element-7a85e3a8").find(".e-container")

find() 让你访问当前 HTML 元素中由 CSS 选择器过滤的后代。然后你可以使用 each() 方法遍历 Cheerio 节点列表,如下所示:

// iterating over the list of industry cards
$(".elementor-element-7a85e3a8")
    .find(".e-container")
    .each((index, element) => {
         // scraping logic...
    })

现在让我们学习如何使用 Cheerio 从感兴趣的 HTML 元素中提取数据。

步骤 6:使用 Cheerio 从目标网页爬虫数据

你可以扩展之前展示的逻辑,从所选 HTML 元素中提取所需数据,如下所示:

// initializing the data structure
// that will contain the scraped data
const industries = []

// scraping the "Learn how web data is used in your market" section
$(".elementor-element-7a85e3a8")
    .find(".e-container")
    .each((index, element) => {
        // extracting the data of interest
        const pageUrl = $(element).attr("href")
        const image = $(element).find(".elementor-image-box-img img").attr("data-lazy-src")
        const name = $(element).find(".elementor-image-box-content .elementor-image-box-title").text()

        // filtering out not interesting data
        if (name && pageUrl) {
            // converting the data extracted into a more
            // readable object
            const industry = {
                url: pageUrl,
                image: image,
                name: name
            }

            // adding the object containing the scraped data
            // to the industries array
            industries.push(industry)
        }
    })

这个网页爬虫 Node.js 代码片段会从 Bright Data 主页选择所有行业卡片。然后,它会遍历所有 HTML 卡片元素。对于每张卡片,它会爬虫与该卡片关联的网页 URL、图片以及行业名称。借助 Cheerio 的 attr()text() 方法,你可以分别检索 HTML 属性值和文本。最后,它将爬虫到的数据存储在一个对象中,并将其添加到 industries 数组。

each() 循环结束时,industries 将包含与第一个爬虫目标相关的所有感兴趣数据。现在让我们看看如何实现另外两个目标。

类似地,你可以按如下方式爬虫用于支持 Bright Data 成为行业领导者的数据:

const marketLeaderReasons = []

// scraping the "What makes Bright Data
// the undisputed industry leader" section
$(".elementor-element-ef3e47e")
    .find(".elementor-widget")
    .each((index, element) => {
        const image = $(element).find(".elementor-image-box-img img").attr("data-lazy-src")
        const title = $(element).find(".elementor-image-box-title").text()
        const description = $(element).find(".elementor-image-box-description").text()

        const marketLeaderReason = {
            title: title,
            image: image,
            description: description,
        }

        marketLeaderReasons.push(marketLeaderReason)
    })

最后,你可以使用以下方式抓取关于为什么 Bright Data 提供出色客户体验的数据:

const customerExperienceReasons = []
// scraping the "The best customer experience in the industry" section
$(".elementor-element-288b23cd .elementor-text-editor")
    .find("li")
    .each((index, element) => {
        const title = $(element).find("strong").text()
        // since the title is part of the text, you have
        // to remove it to get only the description
        const description = $(element).text().replace(title, "").trim()

        const customerExperienceReason = {
            title: title,
            description: description,
        }

        customerExperienceReasons.push(customerExperienceReason)
    })

恭喜!你刚刚学会了如何实现全部三个 Node.js 网页爬虫目标!

请记住,你可以通过跟随在当前页面中发现的链接来爬虫其他网页的数据。这就是网页爬虫的含义。因此,你也可以定义网页爬虫逻辑来从这些页面中提取数据。

industriesmarketLeaderReasonscustomerExperienceReasons 将把所有爬虫到的数据存储在 JavaScript 对象中。让我们学习如何将其转换为更有用的格式。

步骤 7:将提取的数据转换为 JSON

JSON 是涉及 JavaScript 时最好的数据格式之一。这是因为 JSON 源自 JavaScript,并且是 API 通常用于接受或返回数据的格式。因此,你很可能需要将 JavaScript 爬虫数据转换为 JSON。你可以使用下面的逻辑轻松实现这一点:

// trasforming the scraped data into a general object
const scrapedData = {
    industries: industries,
    marketLeader: marketLeaderReasons,
    customerExperience: customerExperienceReasons,
}

// converting the scraped data object to JSON
const scrapedDataJSON = JSON.stringify(scrapedData)

首先,你必须创建一个包含所有爬虫到的数据的 JavaScript 对象。然后,你可以使用 JSON.stringify() 将该 JavaScript 对象转换为 JSON。

scrapedDataJSON 将包含以下 JSON 数据:

{
  "industries": [
    {
      "url": "https://brightdata.com/use-cases/ecommerce",
      "image": "https://brightdata.com/wp-content/uploads/2022/07/E_commerce.svg",
      "name": "E-commerce"
    },

    // ...

    {
      "url": "https://brightdata.com/use-cases/data-for-good",
      "image": "https://brightdata.com/wp-content/uploads/2022/07/Data_for_Good_N.svg",
      "name": "Data for Good"
    }
  ],
  "marketLeader": [
    {
      "title": "Most reliable",
      "image": "https://media.brightdata.com/2022/01/reliable.svg",
      "description": "Highest quality data, best network uptime, fastest output "
    },

    // ...

    {
      "title": "Most efficient",
      "image": "https://media.brightdata.com/2022/01/efficient.svg",
      "description": "Minimum in-house resources needed"
    }
  ],
  "customerExperience": [
    {
      "title": "You ask, we develop",
      "description": "New feature releases every day"
    },

    // ...

    {
      "title": "Tailored solutions",
      "description": "To meet your data collection goals"
    }
  ]
}

恭喜!你从连接到一个网站开始,现在可以爬虫其数据并将其转换为 JSON。你现在准备好查看完整的网页爬虫 Node.js 脚本了。

将所有内容整合起来

这就是 Node.js 网页爬虫工具的样子:

// index.js

const cheerio = require("cheerio")
const axios = require("axios")

async function performScraping() {
    // downloading the target web page
    // by performing an HTTP GET request in Axios
    const axiosResponse = await axios.request({
        method: "GET",
        url: "https://brightdata.com/",
        headers: {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
        }
    })

    // parsing the HTML source of the target web page with Cheerio
    const $ = cheerio.load(axiosResponse.data)

    // initializing the data structures
    // that will contain the scraped data
    const industries = []
    const marketLeaderReasons = []
    const customerExperienceReasons = []

    // scraping the "Learn how web data is used in your market" section
    $(".elementor-element-7a85e3a8")
        .find(".e-container")
        .each((index, element) => {
            // extracting the data of interest
            const pageUrl = $(element).attr("href")
            const image = $(element).find(".elementor-image-box-img img").attr("data-lazy-src")
            const name = $(element).find(".elementor-image-box-content .elementor-image-box-title").text()

            // filtering out not interesting data
            if (name && pageUrl) {
                // converting the data extracted into a more
                // readable object
                const industry = {
                    url: pageUrl,
                    image: image,
                    name: name
                }

                // adding the object containing the scraped data
                // to the industries array
                industries.push(industry)
            }
        })

    // scraping the "What makes Bright Data
    // the undisputed industry leader" section
    $(".elementor-element-ef3e47e")
        .find(".elementor-widget")
        .each((index, element) => {
            // extracting the data of interest
            const image = $(element).find(".elementor-image-box-img img").attr("data-lazy-src")
            const title = $(element).find(".elementor-image-box-title").text()
            const description = $(element).find(".elementor-image-box-description").text()

            // converting the data extracted into a more
            // readable object
            const marketLeaderReason = {
                title: title,
                image: image,
                description: description,
            }

            // adding the object containing the scraped data
            // to the marketLeaderReasons array
            marketLeaderReasons.push(marketLeaderReason)
        })

    // scraping the "The best customer experience in the industry" section
    $(".elementor-element-288b23cd .elementor-text-editor")
        .find("li")
        .each((index, element) => {
            // extracting the data of interest
            const title = $(element).find("strong").text()
            // since the title is part of the text, you have
            // to remove it to get only the description
            const description = $(element).text().replace(title, "").trim()

            // converting the data extracted into a more
            // readable object
            const customerExperienceReason = {
                title: title,
                description: description,
            }

            // adding the object containing the scraped data
            // to the customerExperienceReasons array
            customerExperienceReasons.push(customerExperienceReason)
        })

    // trasforming the scraped data into a general object
    const scrapedData = {
        industries: industries,
        marketLeader: marketLeaderReasons,
        customerExperience: customerExperienceReasons,
    }

    // converting the scraped data object to JSON
    const scrapedDataJSON = JSON.stringify(scrapedData)

    // storing scrapedDataJSON in a database via an API call...
}

performScraping()

如这里所示,你可以用不到 100 行代码在 Node.js 中构建一个网页爬虫工具。借助 Cheerio 和 Axios,你可以下载 HTML 网页、解析它,并自动检索其所有数据。然后,你可以轻松地将爬虫到的数据转换为 JSON。这就是 Node.js 网页爬虫的核心。

使用以下命令启动你的 Node.js 网页爬虫工具:

npm run start

瞧!你刚刚学会了如何在 Node.js 中执行 JavaScript 网页爬虫!

结论

在本教程中,你看到了为什么在前端使用 JavaScript 进行网页爬虫是一种受限的解决方案,以及为什么 Node.js 是更好的选择。此外,你了解了创建 Node.js 网页爬虫脚本需要什么,以及如何在 JavaScript 中从网络爬虫数据。具体来说,你学习了如何基于真实示例使用 Cheerio 和 Axios 在 Node.js 中创建 JavaScript 网页爬虫应用。正如你所学,使用 Node.js 进行网页爬虫只需要几行代码。

但请记住,网页爬虫可能并没有那么容易。原因是你可能需要应对许多挑战。具体来说,反爬虫和反机器人解决方案正变得越来越常见。幸运的是,你可以通过 Bright Data 提供的下一代高级网页爬虫工具轻松避免这一切。不想处理网页爬虫?探索我们的数据集

如果你想了解更多关于如何避免被阻止的信息,可以采用多个可用代理服务之一的 Web 代理,或开始使用高级网络解锁器

支持支付宝等多种支付方式

Antonello Zanini

技术写作

5.5 years experience

Antonello是一名软件工程师,但他更喜欢称自己为技术传教士。通过写作传播知识是他的使命。

Expertise
Web 开发 网页抓取 AI 集成