教你如何用nodejs爬掘金(一)

前言,此文章仅做教学用途,若是有人拿去干别的事情,我概不负责,若是该文章侵害到了掘金社区的利益,请膜法小编马上联系我删除.node

这是我在掘金的第一篇文章,遂想写个爬虫教程吧,目标就是掘金,嘿嘿git

本文用到的三个工具为

  • cheerio:jQuery语法,帮助你在非浏览器环境下解析网页用的
  • qs 序列化成url的查询字符串,(不知道说没说对...)例:{a:1,b2} => a=1&b=2
  • request 一个封装好的好用的请求库,我本身把它promise化了一下

所有代码见githubgithub

开始我是尝试直接请求掘金首页,而后用cheerio解析,而后拿到网页继续干活的。。但是事情并无这么简单,经过这个方法爬取的网页跟咱们正常浏览的首页不同(有多是我哪姿式不对) 没办法,只能从接口出发了web

首先打开网页版掘金, 而后打开chrome的network,查看相关请求chrome

咦!recommend?推荐?好了,进去一看,果真是首页热门文章,可是。。。
请求参数suid是什么?查看请求调用堆栈,,再看源码,emmmm 源码已经被混淆压缩了

这可怎么办?我没有登录 查看完全部请求响应都没看到跟suid有关的,这可咋整?数据库

直接进入请求网址,再更改suid,发现随便更改均可以获得相应 可是。。。这并无什么用啊!就10条信息还须要爬吗?json

没办法了,只能老套路了。先登录再说promise

为了防止页面跳转后登录请求消失,须要先勾选Preserve log,使页面跳转后前面的请求不会消失浏览器

差点忘打码了,qwqbash

模拟登录

我是使用邮箱注册的,可能使用其它帐号注册的接口会不同

let data = await request.create({
    url: 'https://juejin.im/auth/type/email',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({email: '155com', password: 'cfdsd.'}) //帐号密码
  });
复制代码

直接一个请求搞定,获得以下相应,问题的关键就在于cookie

好了,接下来该找接口了,点击最新,发现network多了下面这个请求,其响应数据就是最新板块的文章

相关参数有来源,设备id,用户id,token等,其中最重要的就是token,id什么的随便改两个字符好像也没问题,可是token错了它会报illegal token,请求方法错了,就算参数对了也会报missing src。

当你看到token的时候,你会发现,哪都找不到这个数据

可是你仔细看第5张图的时候,你会发现这auth后面这串字符很像base64编码

获取token

打开相关网站,尝试解码

答案呼之欲出啊,最重要的三个参数全在这了,那么问题来了,node如何解析base64编码呢?

一行代码解决,buffer对象自己提供了base64的解码功能,最后调用toString方法,转成字符串,最后parse获得对象

buffer用法浅析nodejs的buffer类

const cookie = data.headers['set-cookie'];
  const encodeToken = cookie[0]
    .split(';')[0]
    .split('=')[1];
  const decodeToken = JSON.parse(new Buffer(encodeToken, 'base64').toString())
复制代码

有了token,你就能够为所欲为的爬了,爬图片?主题?标题?文章内容?彻底o98k

爬图片

async function getPictureUrl(request, url) {
  let data = await request.get({ url });
  console.log(data.body.match(/(https:\/\/user-gold-cdn).+?\/ignore-error\/1/g)); //匹配出图片url,这里掘金使用了cdn来存储图片
}
复制代码

爬最新文章

async function getTopics(request, typeKey) {
  const { token, clientId, userId } = require('./user.json');
  const querystring = qs.stringify({
    src: 'web',
    uid: userId,
    device_id: clientId,
    token: token,
    limit: 20,
    category: 'all',
    recomment: 1
  });
  const types = {
    timeline: 'get_entry_by_timeline', //最新
    comment: 'get_entry_by_comment',   //评论
    rank: 'get_entry_by_rank'          //热门
  };
  const data = await request.get({
    url: `https://timeline-merger-ms.juejin.im/v1/${types[typeKey]}?${querystring}`,
    headers: {
      host: 'timeline-merger-ms.juejin.im',
      referer: 'https://juejin.im/timeline?sort=comment'
    }
  });
  const body = data.body;
  if (body.s !== 1) {     //出错时清空信息
    fs.writeFileSync('./user.json', JSON.stringify({}));
    throw { type: 'token', message: body.m };
  } else {
    return body.d.entrylist;
  }
}
复制代码

简单的处理错误

try {
  (async function() {
    const request = new Riven();
    request.setDefaultOptions({
      headers: {
        Cookie:
          'gr_user_id=44868117-2a80-49e8-ba2b-2acd2a77a887; ab={}; _ga=GA1.2.1234597644.150' +
          '6904166; MEIQIA_EXTRA_TRACK_ID=0uMtBISQ3EoiMICJMjpaZedfTBz; _gid=GA1.2.100579701' +
          '2.1523672771; Hm_lvt_93bbd335a208870aa1f296bcd6842e5e=1521573516,1521573752,1522' +
          '270605,1523672771; gr_session_id_89669d96c88aefbc=d54a635e-cece-4f16-aca4-808ae9' +
          '2ee559; gr_cs1_d54a635e-cece-4f16-aca4-808ae92ee559=objectId%3A5a974f6ef265da4e8' +
          '53d8d52; auth=; auth.sig=25Jg_aucc6SpX1VH8RlCoh6azLU; Hm_lpvt_93bbd335a208870aa1' +
          'f296bcd6842e5e=1523675329; QINGCLOUDELB=165e4274d6090771b096025ed82d52a1ab7e48fb' +
          '3972913efd95d72fe838c4fb|WtFwy|WtFwr'
      }
    }); //设不设置cookie都OK的
    if (!isLogin()) {
      login(request);
    }
    const topics = await getTopics(request, 'commnet');
     for (let i = 0; i < topics.length; ++i) {
      //await getDetailData(request, topics[i].objectId);
      getPictureUrl(request, topics[i].originalUrl);
      await sleep(2000); //伪线程挂起
    }
  })();
 process.on('unhandledRejection', error => {
    if (error.type === 'token') {
      login();
    }
    console.log(error.message);
  });
} catch (error) {
  console.log(error.message);
}

复制代码

固然,我没有使用数据库来保存数据,这只是教你们爬取原理,到这里,一个超级简单的爬虫就完成了

到最后好像也没用到cheerio了 ◔ ‸◔?

以上代码或言论若有错误,还望你们指出

最后,我要吐槽一句编辑器,竟然不支持粘贴图片???

相关文章
相关标签/搜索