往常都是利用 Python/.NET 语言实现爬虫,然如今做为一名前端开发人员,天然须要熟练 NodeJS。下面利用 NodeJS 语言实现一个糗事百科的爬虫。另外,本文使用的部分代码是 es6 语法。javascript
实现该爬虫所须要的依赖库以下。html
本文首先对爬虫所需依赖库及其使用进行介绍,而后利用这些依赖库,实现一个针对糗事百科的网络爬虫。前端
request 是一个轻量级的 http 库,功能十分强大且使用简单。可使用它实现 Http 的请求,而且支持 HTTP 认证, 自定请求头等。下面对 request 库中一部分功能进行介绍。vue
安装 request 模块以下:java
npm install request
在安装好 request 后,便可进行使用,下面利用 request 请求一下百度的网页。node
const req = require('request'); req('http://www.baidu.com', (error, response, body) => { if (!error && response.statusCode == 200) { console.log(body) } })
在没有设置 options 参数时,request 方法默认是 get 请求。而我喜欢利用 request 对象的具体方法,使用以下:git
req.get({ url: 'http://www.baidu.com' },(err, res, body) => { if (!err && res.statusCode == 200) { console.log(body) } });
然而不少时候,直接去请求一个网址所获取的 html 源码,每每得不到咱们须要的信息。通常状况下,须要考虑到请求头和网页编码。es6
下面介绍在请求的时候如何添加网页请求头以及设置正确的编码。github
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 对象。npm
上面介绍的功能足矣知足后面的所需了,更多功能请参看官网的文档 request
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)
;$('.post_item').find('a.titlelnk')
,须要注意的是,cheerio 对象 A 调用方法 find()
,若是 A 是一个集合,那么 A 集合中的每个子元素都调用 find()
方法,并放回一个结果结合。若是 A 调用 text()
,那么 A 集合中的每个子元素都调用 text()
并返回一个字符串,该字符串是全部子元素内容的合并(直接合并,没有分隔符)。最后在总结一些我比较经常使用的方法。
关于更多 cheerio 库的用法,请参考文档 cheerio
经过上面对 request
和 cheerio
类库的介绍,下面利用这两个类库对糗事百科的页面进行爬取。
一、在项目目录中,新建 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;
二、在项目目录中,新建一个 Splider.js
文件,分析糗事百科的网页代码,提取本身须要的信息,而且创建一个逻辑经过更改 url 的 id 来爬取不一样页面的数据。
const cheerio = require('cheerio'); const httpHelper = require('./httpHelper'); function getQBJok(htmlStr){ let $ = cheerio.load(htmlStr); let jokList = $('#content-left').children('div'); 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
方法的参数,实现抓取不一样页面的信息。
在上面已有代码的基础上,使用 koa
和 vue2.0
搭建一个浏览文本的页面,效果以下:
源码已上传到 github 上。下载地址:https://github.com/StartAction/SpliderQB ;
项目运行依赖 node v7.6.0
以上, 首先从 Github 上面克隆整个项目。
git clone https://github.com/StartAction/SpliderQB.git
克隆以后,进入项目目录,运行下面命令便可。
node app.js
经过实现一个完整的爬虫功能,加深本身对 Node
的理解,且实现的部分语言都是使用 es6
的语法,让本身加快对 es6
语法的学习进度。另外,在此次实现中,遇到了 Node
的异步控制的知识,本文是采用的是 async
和 await
关键字,也是我最喜欢的一种,然而在 Node
中,实现异步控制有好几种方式。关于具体的方式以及原理,有时间再进行总结。