使用 Node.js 进行 Web 抓取的终极指南什么是 Web 抓取?

2025-06-05

使用 Node.js 进行 Web 数据抓取的终极指南

什么是网页抓取?

什么是网页抓取?

它涉及自动执行从网站收集信息的任务。

网络数据抓取的用例非常广泛,你可能想从各种电商网站收集价格信息,用于比价网站。又或者,你需要为旅游网站收集航班时间和酒店列表。或许你想从各种目录收集电子邮件,用于销售线索。甚至你还想构建一个像谷歌这样的搜索引擎!

开始进行网页抓取非常简单,整个过程可以分为两个主要部分:

  • 使用 HTML 请求库或无头浏览器获取数据(也许我们会在另一篇文章中讨论这个问题),
  • 并解析数据以获取您想要的精确信息。

本指南将引导您使用流行的 Node.js request-promise模块、CheerioJSPuppeteer完成整个过程。通过本文中的示例,我们将学习所有必要的技巧和窍门,让您成为使用 Node.js 收集所需数据的专家!

我们将从维基百科收集所有印度总统的姓名和生日列表。

让我们一步一步来

步骤 1:检查系统中是否安装了 node 和 npm。
在终端/命令行中运行以下命令

node -v
Enter fullscreen mode Exit fullscreen mode


npm -v
Enter fullscreen mode Exit fullscreen mode

如果命令输出结果显示版本号,则表示您已经安装了nodenpm。如果出现任何错误,请尝试重新安装它们。输出结果可能类似:

v14.16.1
Enter fullscreen mode Exit fullscreen mode

第 2 步:设置新的 npm 包
运行命令

npm init -y
Enter fullscreen mode Exit fullscreen mode

此命令将在后台完成大量艰苦的工作,并创建一个package.json文件,该文件将跟踪我们在整个程序中安装的所有依赖项和 DevDependencies。

步骤 3:提出第一个请求

npm i -D request request-promise cheerio puppeteer
Enter fullscreen mode Exit fullscreen mode

或者

npm install --save request request-promise cheerio puppeteer
Enter fullscreen mode Exit fullscreen mode
  • -D--save标签用于将 npm 模块安装为 DevDependencies。

  • Puppeteer 需要一段时间才能安装,因为它也需要下载 Chromium,或者您可以跳过这一步,因为我们还没有在我们的程序中使用 puppeteer。

步骤 3:转到您最喜欢的代码编辑器/IDE
让我们创建一个名为scraper.js的文件,并编写一个快速函数来获取维基百科“总统列表”页面的 HTML。

const rp = require('request-promise');
const url = 'https://en.wikipedia.org/wiki/List_of_presidents_of_India';

rp(url)
  .then((html)=>{
    console.log(html);
  })
  .catch((err)=>{
    console.log(err);
  });
Enter fullscreen mode Exit fullscreen mode

输出:

<!DOCTYPE html>
<html class="client-nojs" lang="en" dir="ltr">
<head>
<meta charset="UTF-8"/>
<title>List of Presidents of the India - Wikipedia</title>
...
Enter fullscreen mode Exit fullscreen mode

使用 Chrome DevTools

太棒了,我们从网页中获取了原始 HTML!但现在我们需要理解这大段文本的含义。为此,我们需要使用 Chrome DevTools,以便轻松搜索网页的 HTML。

使用 Chrome DevTools 非常简单:只需打开 Google Chrome,然后右键单击要抓取的元素

Chrome 开发者工具

现在,只需单击“检查”,Chrome 就会调出其 DevTools 窗格,让您轻松检查页面的源 HTML。

ChromeDevtools2t

检查完印度总统的名字后,我们发现该名字存储在th标签中,并被一个锚标签包裹着。那就赶紧用起来吧!

步骤 4:使用CheerioJS解析 HTML

const rp = require('request-promise');
const $ = require('cheerio');
const url = 'https://en.wikipedia.org/wiki/List_of_presidents_of_India';

rp(url)
  .then((html)=>{
    console.log($('th > a', html).length);
    console.log($('th > a', html));
  })
  .catch((err)=>{
    console.log(err);
  });
Enter fullscreen mode Exit fullscreen mode

输出:

18
{ '0':
  { type: 'tag',
    name: 'a',
    attribs: { href: '/wiki/Rajendra_Prasad', title: 'Rajendra Prasad' },
    children: [ [Object] ],
    next: null,
    prev: null,
    parent:
      { type: 'tag',
        name: 'big',
        attribs: {},
        children: [Array],
        next: null,
        prev: null,
        parent: [Object] } },
  '1':
    { type: 'tag'
...
Enter fullscreen mode Exit fullscreen mode

笔记:

我在使用 cheerio 时遇到了一些问题,发现有时需要导出 require('packageName').default 。所以,如果你收到关于cherrio is not function 或 $ is not a function 的错误,请尝试使用以下命令:

var $ = require('cheerio');
if (typeof $ != "function") $ = require("cheerio").default;
Enter fullscreen mode Exit fullscreen mode

它对我有用!

第五步:获取所有总统的姓名。

我们检查返回的元素是否恰好是 18 个(印度总统的数量),这意味着页面上其他地方没有多余的隐藏“th”标签。现在,我们可以遍历并从每个元素的“attribs”部分获取所有 18 个总统维基百科页面的链接列表。

const rp = require('request-promise');
const $ = require('cheerio');
const url = 'https://en.wikipedia.org/wiki/List_of_presidents_of_India';
if (typeof $ != "function") $ = require("cheerio").default;

rp(url)
  .then((html)=>{
    const presidentUrls = [];
    const length = $("th > a", html).length;
    for (let i = 0; i < length ; i++) {
      presidentUrls.push($('th > a', html)[i].attribs.href);
    }
    console.log(presidentUrls);
  })
  .catch((err)=>{
    console.log(err);
  });
Enter fullscreen mode Exit fullscreen mode

输出

[
  '/wiki/Rajendra_Prasad',
  '/wiki/Sir Sarvepalli_Radhakrishnan',
  '/wiki/Zakir_Husain',
  '/wiki/V._V._Giri',
  '/wiki/Mohammad_Hidayatullah',
  '/wiki/V._V._Giri',
  '/wiki/Fakhruddin_Ali_Ahmed',
  ...
]
Enter fullscreen mode Exit fullscreen mode

步骤 6:让我们从 html 页面中获取他们的生日。

现在我们有了所有 18 位总统维基百科页面的列表。让我们创建一个新文件(名为 scrapParse.js),其中包含一个函数,用于获取总统维基百科页面并返回总统的姓名和生日。首先,让我们从 Rajendra Prasad 的维基百科页面获取原始 HTML。

const rp = require('request-promise');
const url = 'https://en.wikipedia.org/wiki/Rajendra_Prasad';

rp(url)
  .then((html)=> {
    console.log(html);
  })
  .catch((err)=> {
    console.log(err);
  });
Enter fullscreen mode Exit fullscreen mode

输出:

<html class="client-nojs" lang="en" dir="ltr">
<head>
<meta charset="UTF-8"/>
<title>Rajendra Prasad - Wikipedia</title>
...
Enter fullscreen mode Exit fullscreen mode

让我们再次使用 Chrome DevTools 来查找我们要解析的代码的语法,以便我们可以使用 Cheerio.js 提取姓名和生日。

替代文本

替代文本

所以我们看到,姓名位于一个名为“firstHeading”的类中,生日位于一个名为“bday”的类中。让我们修改代码,使用 Cheerio.js 提取这两个类。

const rp = require('request-promise');
const $ = require('cheerio');
const url = 'https://en.wikipedia.org/wiki/Rajendra_Prasad';
if (typeof $ != "function") $ = require("cheerio").default;

rp(url)
  .then((html)=> {
    console.log($('.firstHeading', html).text());
    console.log($('.bday', html).text());
  })
  .catch((err)=> {
    console.log(err);
  });
Enter fullscreen mode Exit fullscreen mode

输出:

Rajendra Prasad
1884-12-03
Enter fullscreen mode Exit fullscreen mode

步骤 4:将所有内容整合在一起
现在让我们将其包装成一个函数并从该模块中导出。

const rp = require('request-promise');
var $ = require('cheerio');

if( typeof $ != 'function' ) $ = require('cheerio').default;

const scrapParse = (url) => {
    return rp(url)
    .then((html)=>{
        return {
        name: $('.firstHeading', html).text(),
        birthday: $('.bday', html).text(),
        };
    }).catch((err)=>{
        console.log(err);
    });
}

module.exports = scrapParse;
Enter fullscreen mode Exit fullscreen mode

现在让我们回到原始文件 Scraper.js,并引用scrapParse.js模块。然后,我们将它应用于之前收集的 PresidentUrls 列表。

const rp = require("request-promise");
var $ = require("cheerio");
const scrapParse = require("scrapParse");
if (typeof $ != "function") $ = require("cheerio").default;

const url = "https://en.wikipedia.org/wiki/List_of_presidents_of_India";

if (typeof $ != "function") $ = require("cheerio").default;

rp(url)
  .then((html) => {
    const presidentUrl = [];
    const length = $("th > a", html).length;
    for (let i = 0; i < length; i++) {
      presidentUrl.push($("th > a", html)[i].attribs.href);
    }
    return Promise.all(
      presidentUrl.map((name) => {
        return scrapParse(`https://en.wikipedia.org${name}`);
      })
    );
  })
  .then((presidents) => {
    console.log(presidents);
  })
  .catch((err) => {
    console.log(err);
  });
Enter fullscreen mode Exit fullscreen mode

输出:

[
  { name: 'Rajendra Prasad', birthday: '1884-12-03' },
  { name: 'Sarvepalli Radhakrishnan', birthday: '1888-09-05' },
  { name: 'Zakir Husain (politician)', birthday: '1897-02-08' },
  { name: 'V. V. Giri', birthday: '1894-08-10' },
  { name: 'V. V. Giri', birthday: '1894-08-10' },
  { name: 'Fakhruddin Ali Ahmed', birthday: '1905-05-13' },
  { name: 'B. D. Jatti', birthday: '1912-09-10' },
  { name: 'Neelam Sanjiva Reddy', birthday: '1913-05-19' },
  { name: 'Zail Singh', birthday: '1916-05-05' },
  { name: 'Zail Singh', birthday: '1916-05-05' },
  { name: 'Zail Singh', birthday: '1916-05-05' },
  { name: 'Ramaswamy Venkataraman', birthday: '1910-12-04' },
  { name: 'Shankar Dayal Sharma', birthday: '1918-08-19' },
  { name: 'K. R. Narayanan', birthday: '1997-07-25' },
  { name: 'A. P. J. Abdul Kalam', birthday: '1931-10-15' },
  { name: 'Pratibha Patil', birthday: '1934-12-19' },
  { name: 'Pranab Mukherjee', birthday: '1935-12-11' },
  { name: 'Ram Nath Kovind', birthday: '1945-10-01' }
]
Enter fullscreen mode Exit fullscreen mode

其他资源

这就是清单!现在,你应该可以轻松编写自己的第一个网页爬虫,从任何网站收集数据了。以下是一些额外的资源,在你的网页爬虫之旅中可能会有所帮助:

一些适合初学者的 Web 抓取 API

Scraper API - 一款具备网页抓取优势的 API,支持多种数据收集类型。它支持处理代理、浏览器和验证码,因此您只需简单的 API 调用即可从任何网页获取 HTML 代码。

欢迎提出建议和指正❤️。
获取代码:

GitHub 徽标 Garima-sharma814 /网络爬虫

简单的网络抓取应用程序,用于抓取维基百科上的所有印度总统(姓名和生日)。

什么是网页抓取?

简而言之,网页抓取就是自动从网站收集有用信息。网页抓取的用例有很多,但这里仅列举三种:为比价网站收集各种在线商店的价格;为旅游网站获取航班时间和酒店列表;甚至构建像谷歌这样的搜索引擎!

这个仓库将引导你使用流行的 Node.js request-promise模块、CheerioJSPuppeteer完成整个过程。通过本文中的示例,我们将学习所有必要的技巧和窍门,让你成为使用 Node.js 收集所需数据的专家!

我们将从维基百科收集所有印度总统的姓名和生日列表。

要了解如何一步一步操作,请阅读此处的我的博客。






由我撰写和编辑❤️

文章来源:https://dev.to/garimasharma/the-ultimate-guide-to-web-scraping-with-node-js-bn3
PREV
如何在 C# 中使用工厂方法设计模式 工厂方法设计模式简介
NEXT
理解 JavaScript 中的闭包 - JavaScript 周刊