如何用 Node.js 爬虫?

原创 2017年11月08日 00:00:00

本文来自作者 小北 在 GitChat 上分享「Node.js 爬虫从 0 到 1」,阅读原文」查看交流实录

文末高能

编辑 | 家辉

写在前面

我们经常会听说爬虫这个词语,但是却从来没有见过这个「虫子」,在我们日常生活中,每天使用的百度,谷歌,搜狗,360 等搜索引擎的背后,都是无数的爬虫在支持。

相信很多人都听过 SEO,其实,SEO 就是一门如何让爬虫更快更好的爬取到你的网站的技术,当然,如果你有钱,完全可以搞个竞价排名~

课程简介

其实很多语言都能写爬虫,最著名的应该是 Python,它是一门强大的语言,建议有精力的人学一学,以后大数据,深度学习肯定是大方向!

当然,除了 Python 还有很多语言能写爬虫,比如今天我们要讲的 Node.js。

简单的介绍一下 Node.js,它可以在服务端运行 js,做过前端开发的程序员肯定很熟悉,js 是一门弱语言。

但现在发展很迅速,茁长成长,在 Nodejs 出现以后,使得 js 不光能写前端的动态效果,交互效果,还能写 web 服务器,我们甚至能用 Nodejs 去打包桌面端程序,从此,前端工程师的触角向后延伸了一大块。

对于前端工程师来说有时候可能想爬取点简单的页面,那么 Nodejs 将是我们的好帮手,当然了,闲来无事的时候,你也可以爬取一点福利站之类的,你懂得!

这节 chat 可能只会讲一点简单的爬虫,真正的爬虫与反爬虫博弈十分厉害。

后期会推出一系列的教程来讲解,正在求职之中,时间紧,任务重,如果写的不好,还请提出,我会认真改正,谢谢!

开发环境&工具

  1. Nodejs

  2. 坚挺了5年的小本本

  3. VS Code

    Nodejs环境搭建

  • 下载地址:https://nodejs.org/en/download/(此网址为 node 官网)

  • 这个是 node 中文网 http://nodejs.cn/download/

Windows 和 Mac 直接下载安装包,双击打开安装就好了。

下面重点来说一下 linux 系统下的安装,为什么要重点说 Linux 系统呢?因为我用的是 Linux。

当然这个不是主要原因,主要原因是目前大多数服务器环境是 Linux,如果我们将来将 node 的程序部署的服务器上,那这是很有用的。

Linux 参照这个去安装,https://nodejs.org/en/download/package-manager/

这个网址有时候会上不了,你懂得,我在这贴出几个常用的服务器系统的安装方式。

安装完成后后,可以执行 npde -v 和 npm -v 确认是否安装成功。

Debian and Ubuntu curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get install -y nodejs

RHEL, CentOS or Fedora curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - sudo yum -y install nodejs

爬虫简介

话不多说,直奔主题,下面来讲解一下爬虫是啥。

说了半天,爬虫是什么呢?其实爬虫就是你,说的具体点,当你坐在电脑前面打开这篇 chat,你就充当了一个爬虫的角色,那我们来分解一下你打开这篇 chat 的行为:

输入固定的网址---->点击回车---->看到这篇chat

“爬虫就是模拟人类打开网址,浏览内容的过程” 我们来分析一下整个过程。

首先,你输入了网址,浏览器发起请求,服务器返回数据,浏览器渲染成你看到的页面(这个过程其实很复杂,不做过多介绍)。

从这里就可以看出,我们大致可将爬虫分为两个部分:

请求---->解析&数据处理

其实不然,一个完整的爬虫还需要有保存数据的能力,即

请求---->解析&处理数据---->保存处理好的数据

其实还能向下再去细分

请求---->解析&处理数据---->数据去重---->保存数据

今天我们以第二种模型来讲解,先让大家对爬虫有个初步的了解。

模型Node化

这节的标题有点奇怪,也不是太贴切,这节主要讲的是,对应上述模型,在 node 中我们使用那些对应的模块去操作呢?

请求                     request模块 解析&数据处理             cheerio模块 保存数据                  fs模块

为保证大多数人听懂(很多朋友是从 python 群里过来的),本次 chat 代码将不会使用 promise,class,async & await 等 ES6,7 的代码,尽可能的简单。

但我希望大家能学习上面几个代码,如果后续推出高阶课程,我会使用他们来构建爬虫代码,解决 node 爬虫异步的问题。

只要明白原理了,那 js 代码还不是你想怎么写就怎么写。说了这么多,开始写代码!

从0到1,开始代码

首先说一下,今天我们爬取的是花瓣美素网址 http://www.meisupic.com/

里面有大量的图片供我们做设计使用.当我们拿到想要爬取的网址时,首先要分析这个网站的url。

http://www.meisupic.com/   这个网址相当与主站地址,下面的为分页地址 http://www.meisupic.com/topic.php?topic_id=5 http://www.meisupic.com/topic.php?topic_id=20 http://www.meisupic.com/topic.php?topic_id=1

打开美素网的页面,F12 查看,我们会发现其实有多种方法爬取这个网站。

  • 第一种:我们可以看到其实每个 url 有大部分是相同的,只有结尾的 id 是不同的,那也就是说,我们只需要改变结尾的 id 数就能获取全部的 url 链接。

  • 第二种:我们不难发现,其实在这个a标签里是包含有我们链接的后半部分的,我们也可以在这个主站页面将所有的子站页面链接全部爬取出来。

今天会分别演示这两种方法,下面是第二种方式的代码:

1. 在桌面上简历一个文件夹huaban           // 建议英文名,中英混合会报错 2. cd huaban            // cd到这个文件夹 这个应该都会! 3. npm init             // 初始化项目,如果不想更改,依次回车即可 4. touch app.js         // 创建一个app.js文件,这里可以手动新建,名字叫什么都行 5. mkdir data           // 新建data文件夹,用来存储csv文件,如果不新建,后期会报错 5. npm install request --save       // 安装request模块 6. npm install cheerio --save       // 安装cheerio模块 7. fs模块是node自带的不需要安装 8. 将文件夹在vscode里面打开,开始编写代码

以下是正式代码:

const request = require('request'); const cheerio = require('cheerio'); const fs = require('fs'); // 上面三行代码是导入我们所需的三个模块 // 下面的代码,我将会用最简单的js代码书写,会显得比较low,请见谅! /*  http://www.meisupic.com/topic.php?topic_id=1  http://www.meisupic.com/topic.php?topic_id=5  http://www.meisupic.com/topic.php?topic_id=20  分析上面的代码,可将代码分成两部分,  http://www.meisupic.com/topic.php? 与 topic_id=1  由于我们不知道这个网址具体有多少个子页面,所以我们可以去  http://www.meisupic.com/topic.php上将他全部的子页面爬取下来  再次进行抓取 */ // 主站地址 let Url = 'http://www.meisupic.com/topic.php' // request 负责请求 request({url : Url}, function (err, res, body) {    if (err) {        console.log(err)    } else { /*   cheerio模块负责html的解析,有兴趣的可以直接在上面打印body,这里只需要把   返回的body load进去就可以进行解析了.   cheerio的用法很简单,和JQuery一样,使用时只需要使用jq的语法就可以解析html了 */          let $ = cheerio.load(body)        let href = $('.album_page .glide .slide dl a') /*   简单的使用方法是 $('class名称'),只需要定位到网页中你需要的元素即可   上面的代码是将dl下所有的a标签全部选出来,放到一个叫href的数组里 */              for(let i = 0; i<href.length;i++){                  //这里是对href这个数组做简单的循环简历,js大牛们请自行修改,教学会使用最简单的            let picUrl = href[1].attribs.href               //这里是选出a标签中的href属性            let reUrl ='http://www.meisupic.com/' +picUrl   //你可以在这里将picUrl打印出来,它并不是完整的url,所以我们要做拼接 /*   此处做了简单的header伪装,但header伪装还有很多参数我没有写上,比如说有些网址是有防盗链的,那我们就要伪造一个referer来破解防盗链 */                          request({                url:reUrl,                method: 'GET',                headers: {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36'}            }, function (err, response, body) {                let $ = cheerio.load(body)                let pichref = $('.imgList .imgItem a img')                let picname = $('.ui_cover dl')                for(let j=0;j<pichref.length;j++){                   let downpichref = pichref[j].attribs['data-original']                   let downpicname = picname[j].attribs.title                   save(downpicname, downpichref) /*  以下代码是调用下载程序的,不建议调用,会给网站造成很多流量浪费.                   downloadImg(downpichref, downpicname, function () {                    console.log(downpicname + 'upload 完成');                }); */                }            })        }    } }) /*   下面的代码是使用fs去保存文本,我并没有真正的去下载这些图片,   考虑到版权以及下载图片会增加花瓣网站的流量,   我只是简单的将链接保存在了一个csv文件里   还可以使用mongoose链接上mongoDB,存数据库里.   那如果我们要下载要怎么写呢?可以用pipe通道,或者是使用专用的下载模块去下载,   毕竟node的模块这么多 */ let k = 0 function save(x, y) {    let line;    name = x;    src = y;    line = `${name.replace(/\n/g, '')},${src}`;    fs.appendFile('./data/url.csv', `${line}\n`, 'utf8', (err) => {        if (err) {            console.log(err)        } else {            console.log('已成功爬取'+ k + '条')            k = k + 1        }    }); } /*   此处为保存url的代码,只需要在上面的函数中调用就可以了 */   function downloadImg(url, filename, callback) {    var stream = fs.createWriteStream('./images/' + filename);    request({url:url}).on('error',function(){        console.log('done no');    }).pipe(stream).on('close', callback); /*   这段是下载function的代码   有兴趣的可以自己研究 */   } /*   代码没有使用es6,7的新特性,有兴趣的朋友可以自己修改代码,只要原理清楚就可以了   后期会推出node爬虫更详细的教程,我会将此代码开源到github,大家一定去我的github看看   记得给个start,别问为什么,你会懂的! */

HTTP请求头模拟

本次代码中的请求头模拟并没有涉及到太多,后续的课程里会详细的讲解,爬虫需要模拟人的正常访问,模拟 header 里的参数,达到拟人的效果。

  referer : 达到破解防盗链的效果   headers : {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36'}   模拟请求头   有些时候还会模拟cookie或者登录等等,后续会详细讲解

课程小结

我已经将本文的代码开源到 github 了,会给大家提供三个版本的代码:一个是上面演示的代码,2.0 版本的是第一种方式的代码,用了一些 es6 语法。

第三个版本是让好基友帮忙写的 class 版本,建议大家参考 1.0 版本来熟悉原理,3.0 版本要好好看,以后尽量写成 3.0 版本的代码.

本文参考文献如下:

  • 讲解 request 的文章:
    http://blog.csdn.net/sbt0198/article/details/66479510

  • cheerio 中文 api:
    https://cnodejs.org/topic/5203a71844e76d216a727d2e

  • 讲解 fs 的文章:
    http://www.jianshu.com/p/5683c8a93511

福利

「阅读原文」看交流实录,你想知道的都在这里

版权声明:本文为GitChat作者的原创文章,未经 GitChat 允许不得转载。

相关文章推荐

node.js爬虫例子

  • 2017年11月17日 08:55
  • 15.8MB
  • 下载

Node.js 爬虫批量下载美剧 from 人人影视 HR-HDTV

这两天发现了一个叫看知乎的网站,是知乎的苏莉安做的,其中爬虫使用的 Node.js。这里就针对上一篇博客中的美剧小爬虫,改用 nodejs 进行实现一下,体验一下强大的 Node.js。如果之前没有用...

node.js爬虫dome

  • 2016年01月11日 09:35
  • 1.88MB
  • 下载

node.js 小爬虫抓取网页数据(2)

node.js 小爬虫抓取网页数据 http://blog.csdn.net/sunnylinner/article/details/52942096 在原来的基础上,采用了promise的模块,...

node.js 教你写爬虫(附上gbk,gb2312中文乱码的解决方法)

好久没有更新博客了,现在前端web越来越火了,各种前端技术也层出不穷,不过有一些趋势是可以肯定的,前端现在越来越模块化,mvvm框架让前端用户只需要关注数据的变化,也让web端从webpage转为功能...

Node.js的简易爬虫

前几天,公司的一些网编和网推们需要扒某个页面内关于全国药店的店铺名、地址和电话,我一看,好家伙,四川省就足足有93页的数据量,一页60条数据,靠人工 Ctrl+C + Ctrl+V身为一名懒比,能偷懒...
  • aa34501
  • aa34501
  • 2017年07月28日 16:11
  • 72

教你一步一步用 Node.js 制作慕课网视频爬虫

转自:http://www.jianshu.com/p/d7631fc695af 开始 这个教程十分适合初学 Node.js 的初学者看(因为我也是一只初学的菜鸟~) 在这里,我就默认大家都已经在自己...

Node.js 实现简易爬虫

为什么选择利用node来写爬虫呢?就是因为cheerio这个库,全兼容jQuery语法,熟悉的话用起来真真是爽 依赖选择 cheerio: Node.js 版的jQueryhttp:封装了...

【Node.js】爬虫--抓取新闻标题、图片、文字描述,支持QQ、iFeng

先上效果图:图片上部分为待解析的网页新闻链接,支持一次输入多个.图片下部分为解析的进度日志打印。点击’Commit’之后,对比效果图如下。左边为腾讯新闻原网页,右边为抓取后的整合效果。GitHub源码...
  • sodino
  • sodino
  • 2016年05月31日 15:59
  • 5305
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何用 Node.js 爬虫?
举报原因:
原因补充:

(最多只允许输入30个字)