node模拟登陆segmentfault

前言

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

1、爬虫所需模块

  • superagent
  • async

2、分析

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

图片描述

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

获取Cookie里的PHPSESSID

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

(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便可出现全局搜索框),逐一排查可能性:ajax

图片描述

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

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中,如图:segmentfault

图片描述

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

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了,美滋滋,而后咱们继续~好比我我想用代码修改我的主页的我的描述内容,首先咱们先找到相关接口,如图:
图片描述cookie

这个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...

相关文章
相关标签/搜索