首頁  >  文章  >  web前端  >  NodeJS爬蟲實例之糗事百科_node.js

NodeJS爬蟲實例之糗事百科_node.js

韦小宝
韦小宝原創
2017-12-15 13:39:282729瀏覽

這篇文章主要跟大家講解了一下用NodeJS學習爬蟲,並透過爬糗事百科來講解用法和效果,有NodeJS源碼分析哦,對 NodeJS有興趣的一起學習下吧。

1.前言分析

平常都是利用Python/.NET 語言實作爬蟲,原本現在作為前端開發人員,自然需熟練NodeJS。下面利用 NodeJS 語言實作一個糗事百科的爬蟲。另外,本文使用的部分程式碼是 es6 語法。

實作該爬蟲所需的依賴函式庫如下。

request: 利用 get 或 post 等方法取得網頁的原始碼。 cheerio: 網頁原始碼解析,以取得所需資料。

本文首先對爬蟲所需依賴函式庫及其使用進行介紹,然後利用這些依賴函式庫,實作一個針對糗事百科的網路爬蟲。

2. request 函式庫

request 是一個輕量級的 http 函式庫,功能十分強大且使用簡單。可以使用它實作 Http 的請求,並且支援 HTTP 認證, 自定請求頭等。以下對 request 庫中一部分功能進行介紹。

安裝request 模組如下:


npm install request


在安裝好request 後,即可進行使用,下面利用request請求一下百度的網頁。


const req = require('request');
req('http://www.baidu.com', (error, response, body) => {
 if (!error && response.statusCode == 200) {
 console.log(body)
 }
})


在沒有設定 options 參數時,request 方法預設是 get 請求。而我喜歡利用request 物件的具體方法,使用如下:


req.get({
 url: 'http://www.baidu.com'
},(err, res, body) => {
 if (!err && res.statusCode == 200) {
 console.log(body)
 }
});



##然而很多時候,直接去請求一個網址所取得的html 源碼,往往得不到我們需要的資訊。一般情況下,需要考慮到請求頭和網頁編碼。

網頁的請求頭網頁的編碼

下面介紹在請求的時候如何添加網頁請求頭以及設定正確的編碼。


req.get({
 url : url,
 headers: {
  "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
  "Host" : "www.zhihu.com",
  "Upgrade-Insecure-Requests" : "1"
 },
 encoding : 'utf-8'
}, (err, res, body)=>{
 if(!err)
  console.log(body);
})



#設定options 參數, 新增

headers 屬性即可實現請求頭的設定;新增encoding 屬性即可設定網頁的編碼。需要注意的是,若 encoding:null ,那麼 get 請求所取得的內容則是 Buffer 對象,即 body 是一個 Buffer 物件。

上面介紹的功能足矣滿足後面的所需了

#3. cheerio 庫

cheerio 是一款伺服器端的Jquery,以輕、快、簡單易學等特色被開發者喜愛。有 Jquery 的基礎後再來學習 cheerio 函式庫非常輕鬆。它能夠快速定位到網頁中的元素,其規則和 Jquery 定位元素的方法是一樣的;它也能以一種非常方便的形式修改 html 中的元素內容,以及獲取它們的資料。以下主要針對 cheerio 快速定位網頁中的元素,以及取得它們的內容進行介紹。

先安裝cheerio 函式庫


npm install cheerio


#下面先給出一段程式碼,再對程式碼進行解釋cheerio 函式庫的用法。對部落格園首頁進行分析,然後提取每一頁中文章的標題。

首先對部落格園區首頁進行分析。如下圖:

對html 原始碼進行分析後,首先透過

.post_item 取得所有標題,接著對每一個.post_item 進行分析,使用a.titlelnk 即可符合每個標題的a 標籤。下面透過程式碼進行實作。


const req = require('request');
const cheerio = require('cheerio');

req.get({
 url: 'https://www.cnblogs.com/'
 }, (err, res, body) => {
 if (!err && res.statusCode == 200) {
  let cnblogHtmlStr = body;
  let $ = cheerio.load(cnblogHtmlStr);
  $('.post_item').each((index, ele) => {
  let title = $(ele).find('a.titlelnk');
  let titleText = title.text();
  let titletUrl = title.attr('href');
  console.log(titleText, titletUrl);
  });
 }
 });



#當然,cheerio 函式庫也支援鍊式調用,上面的程式碼也可改寫成:


let cnblogHtmlStr = body;
let $ = cheerio.load(cnblogHtmlStr);
let titles = $('.post_item').find('a.titlelnk');
titles.each((index, ele) => {
 let titleText = $(ele).text();
 let titletUrl = $(ele).attr('href');
 console.log(titleText, titletUrl);



#上面的程式碼非常簡單,就不再用文字進行贅述了。以下總結一點自己認為比較重要的幾點。

使用 find() 方法获取的节点集合 A,若再次以 A 集合中的元素为根节点定位它的子节点以及获取子元素的内容与属性,需对 A 集合中的子元素进行 $(A[i]) 包装,如上面的$(ele) 一样。在上面代码中使用 $(ele) ,其实还可以使用 $(this) 但是由于我使用的是 es6 的箭头函数,因此改变了 each 方法中回调函数的 this 指针,因此,我使用 $(ele); cheerio 库也支持链式调用,如上面的 $('.post_item').find('a.titlelnk') ,需要注意的是,cheerio 对象 A 调用方法 find(),如果 A 是一个集合,那么 A 集合中的每一个子元素都调用 find() 方法,并放回一个结果结合。如果 A 调用 text() ,那么 A 集合中的每一个子元素都调用 text() 并返回一个字符串,该字符串是所有子元素内容的合并(直接合并,没有分隔符)。

最后在总结一些我比较常用的方法。

first() last() children([selector]): 该方法和 find 类似,只不过该方法只搜索子节点,而 find 搜索整个后代节点。

4. 糗事百科爬虫

通过上面对 requestcheerio 类库的介绍,下面利用这两个类库对糗事百科的页面进行爬取。

1、在项目目录中,新建 httpHelper.js 文件,通过 url 获取糗事百科的网页源码,代码如下:


//爬虫
const req = require('request');

function getHtml(url){
 return new Promise((resolve, reject) => {
  req.get({
   url : url,
   headers: {
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
    "Referer" : "https://www.qiushibaike.com/"
   },
   encoding : 'utf-8'
  }, (err, res, body)=>{
   if(err) reject(err);
   else resolve(body);
  })
 });
}
exports.getHtml = getHtml;



2、在项目目录中,新建一个 Splider.js 文件,分析糗事百科的网页代码,提取自己需要的信息,并且建立一个逻辑通过更改 url 的 id 来爬取不同页面的数据。


const cheerio = require('cheerio');
const httpHelper = require('./httpHelper');
function getQBJok(htmlStr){
 let $ = cheerio.load(htmlStr);
 let jokList = $('#content-left').children('p');
 let rst = [];
 jokList.each((i, item)=>{
  let node = $(item);
  let titleNode = node.find('h2');
  let title = titleNode ? titleNode.text().trim() : '匿名用户';
  let content = node.find('.content span').text().trim();
  let likeNumber = node.find('i[class=number]').text().trim();
  rst.push({
   title : title,
   content : content,
   likeNumber : likeNumber
  });
 });
 return rst;
}
async function splider(index = 1){
 let url = `https://www.qiushibaike.com/8hr/page/${index}/`;
 let htmlStr = await httpHelper.getHtml(url);
 let rst = getQBJok(htmlStr);
 return rst;
}
splider(1);



在获取糗事百科网页信息的时候,首先在浏览器中对源码进行分析,定位到自己所需要标签,然后提取标签的文本或者属性值,这样就完成了网页的解析。

Splider.js 文件入口是 splider 方法,首先根据传入该方法的 index 索引,构造糗事百科的 url,接着获取该 url 的网页源码,最后将获取的源码传入 getQBJok 方法,进行解析,本文只解析每条文本笑话的作者、内容以及喜欢个数。

直接运行 Splider.js 文件,即可爬取第一页的笑话信息。然后可以更改 splider 方法的参数,实现抓取不同页面的信息。

在上面已有代码的基础上,使用 koavue2.0 搭建一个浏览文本的页面,效果如下:

源码已上传到 github 上。下载地址:https://github.com/StartAction/SpliderQB ;

项目运行依赖 node v7.6.0 以上, 首先从 Github 上面克隆整个项目。


git clone https://github.com/StartAction/SpliderQB.git



克隆之后,进入项目目录,运行下面命令即可。


node app.js


5. 总结

通过实现一个完整的爬虫功能,加深自己对 Node 的理解,且实现的部分语言都是使用 es6 的语法,让自己加快对 es6 语法的学习进度。另外,在这次实现中,遇到了 Node 的异步控制的知识,本文是采用的是 asyncawait 关键字,也是我最喜欢的一种,然而在 Node 中,实现异步控制有好几种方式。关于具体的方式以及原理,有时间再进行总结。

相关推荐:

NodeJS实现视频转码的示例代码

NodeJs实现定时任务的示例代码

NodeJs之关于数据库异常处理的解决方法

以上是NodeJS爬蟲實例之糗事百科_node.js的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn