node模拟登录segmentfault

前言

前段时间看的爬虫都是不需要登录直接爬取数据,这回就试试爬取需要登录的网站信息吧,说干就干,直接就拿segmentfault做为目标!

一、爬虫所需模块

  • superagent
  • async

二、分析

我们首先用chrome或者其他浏览器打开segmentfault的主页,找到它的登录接口,点击登录接口,记得把Preserve log勾上,否则跳转之后找不到接口,如图(重要信息打了马赛克):

图片描述

显而易见这是一个post请求,三个参数分别是用户名、密码、和是否记住密码的标记。

获取Cookie里的PHPSESSID

仔细看请求头header里的cookie,在请求发送的时候就已经有了,我们直接把整个请求头拿过来,就直接用图中的接口和header登录,逐一删除cookie中的项,测试登录结果,最终发现只有PHPSESSID是必须的。这个PHPSESSID如何获取呢?我们可以在登录之前先访问segmentfault主页,将返回的cookie拿到,再在登录的时候加上这个cookie即可。
获取cookie的代码如下:

(cb) => {
    superagent
      .get('https://segmentfault.com')
      .end((err, res) => {
        if (err) console.log(err)
        cookie = res.headers['set-cookie'].join(',').split(';')[0]   // 获取PHPSESSID
        cb(null)
      })
  }

获取Query String Paramsters里的 _ 参数

还有一个参数需要注意:接口中的Query String Paramsters_参数,那么这个参数是怎么来的呢?在返回的responseheader里寻找并没有找到它的踪迹,所以猜想它应该是隐藏在源码里,我们直接在chrome控制台的source下全局搜索_=source顶部右键选择search in all files即可出现全局搜索框),逐一排查可能性:

图片描述

图片描述
排查过程中发现箭头所指的ajaxSend函数好像和我们需要的有关系:它紧邻的下面的delegate函数内容应该就是登陆有关的内容,通过/api/user/?do=loginsubmit等就可以清楚的看出,这个函数中的url是从n.attr('action')拿到的,猜测这个n.__肯定和请求中的Query String参数脱不了关系。正好这个ajaxSend函数中就有n.__,也正好验证了我们刚才的推测,分析这行代码:

n.url.indexOf("?") === -1 ? n.url = n.url + "?_=" + i._ : n.url = n.url + "&_=" + i._

n.url默认是n.url + "?_=" + i._ ,那么这个i.__应该就是最终boss,就在这个文件中找到定义i的代码,如上图箭头所指,继续全局搜索SF.token,最终在index.html中找了生成它的代码,包含在一个script中,如图:

图片描述

找到来源就简单了,我们仍然是在登录直接先访问主页,将整个主页的html代码拿到,然后将这个script的内容取出来不就行了,哈哈,好开心~
获取script的代码如下:

var cheerio = require('cheerio')
function getRandom(s) {
  let $ = cheerio.load(s)
  let script = $('script').eq(8).html()
  let fn = new Function('window', script + ';return window.SF.token')
  let token = fn({})
  $ = null
  return token
}
exports.getRandom = getRandom

到这里,登录就算完成了一大半了,接下来就是简单的用superagent调用接口啦,这里的请求头出了cookie的其他部分也是必须要设置的,可以直接从浏览器上copy下来,代码如下:

(cb) => {
    const username = process.argv[2]
    const password = process.argv[3]
    console.log(cookie)
    console.log(random)
    let header = {
      'accept': '*/*',
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'zh-CN,zh;q=0.9',
      'content-length': '47',
      'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
      'cookie': `PHPSESSID=${cookie};`,
      'origin': 'https://segmentfault.com',
      'referer': 'https://segmentfault.com/',
      'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
      'x-requested-with': 'XMLHttpRequest'
    }
    superagent
      .post(`https://segmentfault.com/api/user/login`)
      .query({'_': random})
      .set(header)
      .type('form')
      .send({
        username: username,
        password: password,
        remember: 1
      })
      .end(function(err, res) {
        if (err) {
          console.log(err.status);
        } else {
          console.log('返回状态码: ' +  res.status)
          cb(null)
        }
      })
  },

终于返回200了,美滋滋,然后我们继续~比如我我想用代码修改个人主页的个人描述内容,首先我们先找到相关接口,如图:
图片描述

这个post请求的参数description就是个人描述的所填写的新的内容,我们直接用superagent调用这个接口

(cb) => {
    superagent
      // 编辑右上角个人说明
      .post('https://segmentfault.com/api/user/homepage/description/edit')
      .query({'_': random})
      .set(header)
      .type('form')
      .send({
        description: '努力coding的小喵~~~'
      })
      .end((err, res) => {
        if(err) throw err
        let result = JSON.parse(res.text)
        if (result.status === 0) {
          console.log('编辑成功')
        } else {
          console.log('编辑失败:' + result.data)
        }
      })
    cb(null, 1)
  }

返回状态码200,然后直接去浏览上的主页刷新下,可以看到个人描述的内容已经成功更新了!

图片描述

总结

  1. 打开segmentfault主页并登陆,找到登录请求的接口并分析
  2. node登录之前,先请求主页接口,目的是拿到PHPSESSID和源代码中的生成Query String的函数
  3. 带着这两个参数去请求登录接口,记得设置请求头
  4. 登录成功之后就可以干任何你想干的事情啦

整个登录过程耗费了很久的时间,有空就研究这个Query String的来源,好不容易登录成功想干点事情,又没注意到设置请求头,以为是sf_remember参数的问题,又折腾了许久,还好,最终总算是成功了!感谢自己的不放弃~

源码

github地址:https://github.com/fighting12...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值