在上一篇Node 爬蟲入門已經介紹過最簡單的 Node 爬蟲實現,本文在原先的基礎上更進一步,探討一下如何繞過登陸,爬取登陸區內的數據javascript
Http 做爲一種無狀態的協議,客戶端和服務器端之間不會保持長鏈接。在一個一個相互獨立的請求響應之間,服務器如何識別哪些接口是來自同一個客戶端?聰明的你,很容易想到以下一種機制:css
這種機制的核心在於會話id(sessionId):html
首先客戶端經過sessionId和服務器端創建一種關聯,而後用戶再經過客戶端與服務器端創建一種關聯(sessionId與用戶數據的鍵值對),從而維持了登陸態java
實際上,瀏覽器是否是按照上述的機制設計的呢?還真是!node
這其中瀏覽器作了哪些事情:
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 關聯起來
咱們須要模擬瀏覽器的工做方式,去爬去網站登陸區內的數據
找了一個沒有驗證碼的網站進行試驗,有驗證碼的又要涉及到驗證碼識別(簡書的登陸就不考慮了,驗證碼複雜程度感人),下節說明
// 瀏覽器請求報文頭部部分信息
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);
});
});
}複製代碼
須要如今 Chrome 下捕獲一次請求,獲取一些請求頭的信息,由於服務器可能會對這些請求頭信息進行校驗。例如,在我實驗的網站上,起初我並無傳入 User-Agent,服務器發現並非來自服務器的請求,返回了一串錯誤信息,因此我以後設置 User-Agent,把本身假裝成 Chrome瀏覽器了~~
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,這真的是一個神器,良心製做!
如今不須要輸驗證碼就能夠登陸的網站還有幾個?固然咱們就不企圖去識別12306的驗證碼了,簡書這種良心之做驗證碼也不奢望了,像知乎這種 too young too simple 的驗證碼仍是能夠挑戰下的
若是非要識別這些複雜的驗證碼也不是沒有辦法,花錢買專業打碼軟件的服務(搶票黃牛就是這麼幹的),畢竟人家是專業的
Tesseract 是google開源的OCR識別工具,雖然跟node沒有什麼關係,可是能夠用node來調度使用,具體使用方式:用node.js實現驗證碼簡單識別
然而即使是使用graphicsmagick來對圖片進行預處理,也不能保證有很高的識別率,爲此還能夠對tesseract進行訓練,參考:利用jTessBoxEditor工具進行Tesseract3.02.02樣本訓練,提升驗證碼識別率
能不能作到高識別率,就看人品了~~~
還有一種更簡單的方式去繞過登陸態,就是使用PhantomJS,phantomjs是一個基於webkit開源的服務器js api,能夠認爲它就是一個瀏覽器,只是你能夠經過js腳原本操控它。
因爲其徹底模擬瀏覽器的行爲,因此你根本不須要關心set-cookie,cookie的事情,只須要模擬用戶的點擊操做就能夠了(固然若是有驗證碼,仍是得去識別的)
這種方式也並不是毫完好點,徹底模擬瀏覽器的行爲,意味者不放過任何一個請求,須要載入可能你並不須要的js、css等靜態資源,須要點擊多個頁面才能到達目的頁面,在效率上要比直接訪問target url要低
感興趣自行搜索
phontomJS
雖說的是node爬蟲的登陸,可是前面原理講了一大堆,目的是若是你想換一種語言實現,也能夠遊刃有餘,仍是那句話:理解原理很重要
乾貨不斷,期待您的關注~~