使用 Node.js 进行 Web 数据抓取的终极指南
什么是网页抓取?
什么是网页抓取?
它涉及自动执行从网站收集信息的任务。
网络数据抓取的用例非常广泛,你可能想从各种电商网站收集价格信息,用于比价网站。又或者,你需要为旅游网站收集航班时间和酒店列表。或许你想从各种目录收集电子邮件,用于销售线索。甚至你还想构建一个像谷歌这样的搜索引擎!
开始进行网页抓取非常简单,整个过程可以分为两个主要部分:
使用 HTML 请求库或无头浏览器获取数据(也许我们会在另一篇文章中讨论这个问题),
并解析数据以获取您想要的精确信息。
本指南将引导您使用流行的 Node.js request-promise 模块、 CheerioJS 和 Puppeteer 完成整个过程 。通过本文中的示例,我们将学习所有必要的技巧和窍门,让您成为使用 Node.js 收集所需数据的专家!
我们将从维基百科收集所有印度总统的姓名和生日列表。
让我们一步一步来
步骤 1: 检查系统中是否安装了 node 和 npm。 在终端/命令行中运行以下命令
node -v
Enter fullscreen mode
Exit fullscreen mode
和
npm -v
Enter fullscreen mode
Exit fullscreen mode
如果命令输出结果显示版本号,则表示您已经安装了 node 和 npm 。如果出现任何错误,请尝试重新安装它们。输出结果可能类似:
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
步骤 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 就会调出其 DevTools 窗格,让您轻松检查页面的源 HTML。
检查完印度总统的名字后,我们发现该名字存储在 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 代码。
欢迎提出建议和指正❤️。 获取代码:
简单的网络抓取应用程序,用于抓取维基百科上的所有印度总统(姓名和生日)。
什么是网页抓取?
简而言之,网页抓取就是自动从网站收集有用信息。网页抓取的用例有很多,但这里仅列举三种:为比价网站收集各种在线商店的价格;为旅游网站获取航班时间和酒店列表;甚至构建像谷歌这样的搜索引擎!
这个仓库将引导你使用流行的 Node.js request-promise 模块、 CheerioJS 和 Puppeteer 完成整个过程。通过本文中的示例,我们将学习所有必要的技巧和窍门,让你成为使用 Node.js 收集所需数据的专家!
我们将从维基百科收集所有印度总统的姓名和生日列表。
要了解如何一步一步操作,请阅读 此处的 我的博客。
由我 撰写和编辑 ❤️
文章来源:https://dev.to/garimasharma/the-ultimate-guide-to-web-scraping-with-node-js-bn3