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

相關文章
相關標籤/搜索