使用 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>class = "client-nojs"  lang = "en"  dir = "ltr" > 
<head > 
<meta charset = "UTF-8" />
  
   
    
     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' ,'a' ,{  href: '/wiki/Rajendra_Prasad' , title: 'Rajendra Prasad'  } ,[  [ Object] ] ,{  type : 'tag' ,'big' ,{} ,[ Array],[ 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" />
  
   
    
     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
  
   
    
     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