node爬蟲進階之——登陸

在上一篇Node 爬蟲入門已經介紹過最簡單的 Node 爬蟲實現,本文在原先的基礎上更進一步,探討一下如何繞過登陸,爬取登陸區內的數據javascript

目錄

1、理論基礎

如何維持登陸態

Http 做爲一種無狀態的協議,客戶端和服務器端之間不會保持長鏈接。在一個一個相互獨立的請求響應之間,服務器如何識別哪些接口是來自同一個客戶端?聰明的你,很容易想到以下一種機制:css

sessionId.png

這種機制的核心在於會話id(sessionId):html

  1. 當客戶端請求服務器端的時候,服務端判斷該客戶端沒有傳入sessionId,好的,這傢伙是新來的,給它生成一個sessionId,存入內存,並把這個sessionId返回客戶端
  2. 客戶端拿到服務器端的sessionId保存在本地,下次請求的時候帶上這個seesionId,服務器檢查內存是否存在這個sessionId(若是在以前的某個步驟,用戶訪問了登陸接口,那麼此刻內存中已經以seesionId爲key,用戶數據爲value保存在了內存中),服務器就能夠根據sessionId這個惟一標識,返回該客戶端對應的數據
  3. 不管是客戶端仍是服務器端丟失了這個sessionId都會致使前面的步驟從新來過,誰也不認識誰了,從新開始

首先客戶端經過sessionId和服務器端創建一種關聯,而後用戶再經過客戶端與服務器端創建一種關聯(sessionId與用戶數據的鍵值對),從而維持了登陸態java

瀏覽器是怎麼作的

實際上,瀏覽器是否是按照上述的機制設計的呢?還真是!node

bs-sid.png

這其中瀏覽器作了哪些事情:
1、 瀏覽器在每一次http請求中,都會在http的請求頭中加上該請求地址域名對應的cookie(若是cookie沒有被用戶禁用的話),在上圖中,第一個次請求服務器請求頭中一樣有cookie,只是cookie中尚未sessionId
2、 瀏覽器根據服務器響應頭中的Set-Cookie設置cookie,爲此,服務器會將生成的sessionId放入Set-cookie中git

瀏覽器接收到Set-Cookie指令,就會以請求地址的域名爲key設置本地cookie,通常狀況下,服務器在返回Set-cookie的時候,對sessionId的過時時間默認設置爲瀏覽器關閉時失效,這就是瀏覽器從打開到關閉就是一次會話的由來(有些網站還能夠設置保持登陸,設置cookie長時間不失效爾爾)github

3、 當瀏覽器再次向後臺發起請求時,此時請求頭中的cookie已經包含了sessionId,若是在此以前用戶已經訪問過登陸接口,那麼就已經能夠根據sessionId來查詢到用戶數據了web

口說無憑,下面就以簡書爲例說明:
1). 首先用 Chrome 打開簡書的登陸頁面,在 Application 中找到 http://www.jianshu.com 下的所 Cookie,進入 Network 項中把 `Preserve log 勾選上(否則頁面發生了重定向以後將沒法看到以前的 log)api

簡書登陸

2). 而後刷新頁面,找到 Sign-in 接口,它的響應頭中有不少 Set-Cookie 有木有瀏覽器

簡書登陸

3). 再去查看 Cookie 的時候,Session-id 已經保存好了,下次再去請求簡書的其它接口的時候(例如獲取驗證碼、登陸),都會帶上這個 Session-id,登陸後用戶的信息也會跟 Session-id 關聯起來

簡書登陸

2、node實現

咱們須要模擬瀏覽器的工做方式,去爬去網站登陸區內的數據
找了一個沒有驗證碼的網站進行試驗,有驗證碼的又要涉及到驗證碼識別(簡書的登陸就不考慮了,驗證碼複雜程度感人),下節說明

// 瀏覽器請求報文頭部部分信息
    var browserMsg={
        "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
        'Content-Type':'application/x-www-form-urlencoded'
    };

    //訪問登陸接口獲取cookie
    function getLoginCookie(userid, pwd) {
        userid = userid.toUpperCase();
        return new Promise(function(resolve, reject) {
            superagent.post(url.login_url).set(browserMsg).send({
                userid: userid,
                pwd: pwd,
                timezoneOffset: '0'
            }).redirects(0).end(function (err, response) {
                //獲取cookie
                var cookie = response.headers["set-cookie"];
                resolve(cookie);
            });
        });
    }複製代碼
  1. 須要如今 Chrome 下捕獲一次請求,獲取一些請求頭的信息,由於服務器可能會對這些請求頭信息進行校驗。例如,在我實驗的網站上,起初我並無傳入 User-Agent,服務器發現並非來自服務器的請求,返回了一串錯誤信息,因此我以後設置 User-Agent,把本身假裝成 Chrome瀏覽器了~~

  2. Superagent是一個 client-side Http Request庫,使用它能夠跟輕鬆的發送請求,處理 Cookie(本身調用 Http.request 在操做 Header 字段數據上就沒有這麼方便,得到 Set-cookie 以後,還得本身拼裝成合適的格式 Cookie)。redirects(0) 主要是設置不進行重定向

請求登陸區內接口

function getData(cookie) {
        return new Promise(function(resolve, reject) {
            //傳入cookie
            superagent.get(url.target_url).set("Cookie",cookie).set(browserMsg).end(function(err,res) {
                var $ = cheerio.load(res.text);
                resolve({
                    cookie: cookie,
                    doc: $
                });
            });
        });
    }複製代碼

在上一步中拿到 Set-cookie 以後,傳入 getData 方法,在經過 Superagent 設置到請求當中(Set-cookie會格式化成 Cookie),就能夠正常拿到登陸去內的數據

在實際的場景中,未必會如此順利,由於不一樣的網站有不一樣的安全措施,例如:有些網站可能須要先請求一個 Token ,有些網站須要對參數進行加密處理,有些安全性更高的,還有防重放機制。在定向爬蟲中,這須要具體的去分析網站的處理機制,若是繞不過去,就適可而止吧~~
可是對付通常內容資訊類的網站仍是夠用的

經過以上方式請求到的只是一段 Html 字符串,這裏仍是老辦法,使用 Cheerio 庫將字符串載入,就能夠拿到一個相似於 Jquery dom 的對象,就能夠像 Jquery 同樣去操做 dom,這真的是一個神器,良心製做!

3、若是有驗證碼怎麼破

如今不須要輸驗證碼就能夠登陸的網站還有幾個?固然咱們就不企圖去識別12306的驗證碼了,簡書這種良心之做驗證碼也不奢望了,像知乎這種 too young too simple 的驗證碼仍是能夠挑戰下的

若是非要識別這些複雜的驗證碼也不是沒有辦法,花錢買專業打碼軟件的服務(搶票黃牛就是這麼幹的),畢竟人家是專業的

知乎登陸

Tesseract 是google開源的OCR識別工具,雖然跟node沒有什麼關係,可是能夠用node來調度使用,具體使用方式:用node.js實現驗證碼簡單識別

然而即使是使用graphicsmagick來對圖片進行預處理,也不能保證有很高的識別率,爲此還能夠對tesseract進行訓練,參考:利用jTessBoxEditor工具進行Tesseract3.02.02樣本訓練,提升驗證碼識別率

能不能作到高識別率,就看人品了~~~

4、延伸

還有一種更簡單的方式去繞過登陸態,就是使用PhantomJS,phantomjs是一個基於webkit開源的服務器js api,能夠認爲它就是一個瀏覽器,只是你能夠經過js腳原本操控它。

因爲其徹底模擬瀏覽器的行爲,因此你根本不須要關心set-cookie,cookie的事情,只須要模擬用戶的點擊操做就能夠了(固然若是有驗證碼,仍是得去識別的)

這種方式也並不是毫完好點,徹底模擬瀏覽器的行爲,意味者不放過任何一個請求,須要載入可能你並不須要的js、css等靜態資源,須要點擊多個頁面才能到達目的頁面,在效率上要比直接訪問target url要低

感興趣自行搜索phontomJS

5、總結

雖說的是node爬蟲的登陸,可是前面原理講了一大堆,目的是若是你想換一種語言實現,也能夠遊刃有餘,仍是那句話:理解原理很重要

乾貨不斷,期待您的關注~~

相關文章
相關標籤/搜索