在上一篇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爬虫的登陆,可是前面原理讲了一大堆,目的是若是你想换一种语言实现,也能够游刃有余,仍是那句话:理解原理很重要
干货不断,期待您的关注~~