开始使用 JavaScript 进行网页抓取

探索网页抓取的奥秘

网页抓取是编程世界中最引人入胜的领域之一。它究竟是什么?它为何如此重要?让我们深入探索,揭开其神秘面纱。

网页抓取的定义

网页抓取,又称网络数据提取,是一种自动化技术,用于从网站上收集数据。它就像一个数字侦探,高效地从网页中检索信息。

网页抓取的应用范围极其广泛:从比较不同电商平台上的产品价格,到获取每日更新的股市行情,甚至构建像谷歌、雅虎这样的搜索引擎,其可能性几乎是无限的。

一旦掌握了从网站提取数据的技巧,您就可以根据自己的需求对这些数据进行各种处理和分析。执行数据提取任务的程序被称为网络爬虫或抓取工具。本文将指导您使用 JavaScript 创建自己的网络爬虫。

网页抓取主要分为两个核心步骤:

  • 首先,利用请求库和无头浏览器获取目标网页的原始数据。
  • 然后,解析这些数据,从中提取出您所需的精确信息。

现在,让我们开始实际操作!

项目准备

假设您已经安装了 Node.js。如果没有,请先查阅相关的Node.js安装指南。

我们将使用 node-fetchcheerio 这两个JavaScript库来实现网页抓取。我们需要使用 npm 来设置项目,以便使用这些第三方库。

以下是设置步骤的简要概述:

  • 创建名为 web_scraping 的目录,并进入该目录。
  • 运行 npm init 命令以初始化项目。
  • 根据提示填写相关信息。
  • 然后,使用命令 npm install node-fetch cheerio 安装所需的库。

让我们了解一下已安装的软件包:

node-fetch

node-fetch 库将 window.fetch 功能引入 Node.js 环境,使我们能够发送 HTTP 请求并获取网页的原始数据。

cheerio

cheerio 库则用于解析原始数据,并从中提取出我们需要的信息。

node-fetchcheerio 这两个库足以满足我们使用 JavaScript 进行网页抓取的需求。我们不会深入探讨每个方法,而是重点关注网页抓取的流程以及最常用的方法。

通过实践操作,您将更好地掌握网页抓取。那么,让我们开始吧!

实战演练:抓取板球世界杯冠军名单

在本部分,我们将进行实际的网络数据抓取。

我们的目标是什么?

顾名思义,我们将抓取历届板球世界杯的冠军和亚军名单。

  • 首先,在您的项目中创建一个名为 extract_cricket_world_cups_list.js 的文件。
  • 我们将从
    维基百科的板球世界杯页面
    获取相关信息。
  • 首先,使用 node-fetch 库获取页面的原始数据。
  • 以下代码展示了如何获取维基百科页面的原始数据。

const fetch = require("node-fetch");

// 获取原始数据的函数
const getRawData = (URL) => {
   return fetch(URL)
      .then((response) => response.text())
      .then((data) => {
         return data;
      });
};

// 数据来源的 URL
const URL = "https://en.wikipedia.org/wiki/Cricket_World_Cup";

// 程序入口
const getCricketWorldCupsList = async () => {
   const cricketWorldCupRawData = await getRawData(URL);
   console.log(cricketWorldCupRawData);
};

// 调用主函数
getCricketWorldCupsList();

现在,我们已经成功获取了原始数据。接下来,我们需要从中提取我们需要的信息,这时候就需要使用 cheerio 库。

利用 cheerio 处理 HTML 数据非常简单。在实际操作之前,我们先来看一些使用 cheerio 解析数据的例子:

  • 使用 cheerio.load 方法解析 HTML 数据。

const parsedSampleData = cheerio.load(
      `<div id="container"><p id="title">I'm title</p></div>`
   );
  • 我们已经解析了上述 HTML 代码,现在如何从中提取 p 标签的内容呢?这与 JavaScript DOM 操作中的选择器类似。

console.log(parsedSampleData("#title").text());

您可以根据需要选择标签。 更多信息,请参考 cheerio官方文档.

  • 现在,让我们开始提取世界杯名单吧。我们需要知道目标信息位于页面中的哪个 HTML 标签。请访问
    板球世界杯维基百科页面
    并检查相关 HTML 标记。

以下是完整的代码:


const fetch = require("node-fetch");
const cheerio = require("cheerio");

// 获取原始数据的函数
const getRawData = (URL) => {
   return fetch(URL)
      .then((response) => response.text())
      .then((data) => {
         return data;
      });
};

// 数据来源的 URL
const URL = "https://en.wikipedia.org/wiki/Cricket_World_Cup";

// 程序入口
const getCricketWorldCupsList = async () => {
   const cricketWorldCupRawData = await getRawData(URL);

   // 解析数据
   const parsedCricketWorldCupData = cheerio.load(cricketWorldCupRawData);

   // 提取表格数据
   const worldCupsDataTable = parsedCricketWorldCupData("table.wikitable")[0]
      .children[1].children;

   console.log("Year --- Winner --- Runner");
   worldCupsDataTable.forEach((row) => {
      // 提取 `td` 标签
      if (row.name === "tr") {
         let year = null,
            winner = null,
            runner = null;

         const columns = row.children.filter((column) => column.name === "td");

         // 提取年份
         const yearColumn = columns[0];
         if (yearColumn) {
            year = yearColumn.children[0];
            if (year) {
               year = year.children[0].data;
            }
         }

         // 提取冠军
         const winnerColumn = columns[3];
         if (winnerColumn) {
            winner = winnerColumn.children[1];
            if (winner) {
               winner = winner.children[0].data;
            }
         }

         // 提取亚军
         const runnerColumn = columns[5];
         if (runnerColumn) {
            runner = runnerColumn.children[1];
            if (runner) {
               runner = runner.children[0].data;
            }
         }

         if (year && winner && runner) {
            console.log(`${year} --- ${winner} --- ${runner}`);
         }
      }
   });
};

// 调用主函数
getCricketWorldCupsList();

以下是抓取的数据:


Year --- Winner --- Runner
1975 --- West Indies --- Australia
1979 --- West Indies --- England
1983 --- India --- West Indies
1987 --- Australia --- England
1992 --- Pakistan --- England
1996 --- Sri Lanka --- Australia
1999 --- Australia --- Pakistan
2003 --- Australia --- India
2007 --- Australia --- Sri Lanka
2011 --- India --- Sri Lanka
2015 --- Australia --- New Zealand
2019 --- England --- New Zealand

是不是很酷? 😎

通用抓取模板

在每一个网页抓取项目中,从 URL 获取原始数据都是常见的步骤。唯一变化的是根据需要提取数据的部分。您可以尝试将以下代码作为模板:


const fetch = require("node-fetch");
const cheerio = require("cheerio");
const fs = require("fs");
// 获取原始数据的函数
const getRawData = (URL) => {
   return fetch(URL)
      .then((response) => response.text())
      .then((data) => {
         return data;
      });
};
// 数据来源的 URL
const URL = "https://example.com/";
// 程序入口
const scrapeData = async () => {
   const rawData = await getRawData(URL);
   // 解析数据
   const parsedData = cheerio.load(rawData);
   console.log(parsedData);
   // 在这里编写提取数据的代码
   // ...
   // ...
};
// 调用主函数
scrapeData();

总结

您已经学习了如何抓取网页,现在是时候动手实践了!

我还建议您探索一些流行的网页抓取框架,了解基于云端的网络抓取解决方案。

祝您编程愉快!🙂

喜欢这篇文章吗?请分享给更多人吧!