一般情况下,我们要获取一些登录后的数据,就需要通过代码去模拟登录。那么响应某位朋友的留言请求,啥时候讲讲JS呀!于是乎我就选择了一个考点非常 nice 的网站——人人网。那今天我们通过模拟登录人人网,来跟大家唠唠大家都非常期待的JS反爬。
解析人人网
那么爬虫的第一步千万不要着急写代码,而是对页面进行分析。此处我们选择使用谷歌的无痕浏览器(每次重新打开都会清理缓存)
如何打开谷歌无痕:
- 1.打开谷歌浏览器
- 2.如图
然后通过无痕浏览器打开人人网
- 人人网url:http://www.renren.com/
接下来需要对登录页面做解析,所以可以通过以下几种方式打开谷歌开发者工具
- F12 键
- 鼠标右键下的检查
然后我们需要去进行登录测试,如下GIF
- 输入伪账号与密码
- 点击登录
- 并观察右侧的 Network 中的请求地址变化
- 看到 http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020641655904
- 点击进去,看到其 headers
进行剖析,发现以下结果
- 登录请求为 Post 请求
- Post 请求所携带的参数
我们会发现用户输入的 用户名及密码 奥哟~居然是明文,并且这个请求的参数也没有什么加密的或者说变化的参数。
按照这个推理,实际上我们直接通过 requests 库发送 Post 请求,并将 From Data 中的值传过去不就 OK了?伪代码如下:
import requests
url = "http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020641533756"
data = {
"email": "Logic_Juran",
"password": "123456",
"icode": "origURL: http://www.renren.com/home",
"domain": "renren.com",
"key_id": 1,
"captcha_type": "web_login"
}
requests.post(url=url, data=data)
但是,真相真的如此简单吗?当然不是。
首先,我填入真实的账号密码[额,不要给我打电话]…大家会发现页面进行了跳转,所以我们找不到 login 所对应的网站
那要怎么做到页面跳转时,Network 中的 url 不进行刷新而是添加呢?小技巧,勾上以下选项。
再退出重新登录会发现如下
- 密码加密为:****32e0725f6d0566f8c04c773467a10cea3411adda345d2656b348e6683585
- rkey 登场:a63d4c171d299d57332099687542d201
也就说是,在不清理缓存的情况下不是第一次登录时密码就会加密以及 rkey 会出现。此刻,我们需要了解 rkey 是否是每次都变化的。
- rkey 不变:则直接拷贝到 data 中请求即可
- rkey 变:我们就需要来破解 rkey 是如何生成的
经过对比,我们发现 password 与 rkey 在每次登录的时候都会发生变化。但是怎么找到与其相关的文件呢?
首先我们可以观察登录按钮是否有绑定JS事件
- 回到登录页面
- 输入账号密码
- 打开开发者工具中的 elements
- 点击 登录 观察开发者工具中的 Event Listeners
- 加载出 bi-sdk.1.2.1.js
往 bi-sdk.1.2.1.js 里头搜索 rkey
再全局搜索 rkey ,也没有找到~
这可咋整呢?此时,我们需要切换思路,如果说 PC 端严防把守,那我们可以选择使用 APP 端来做这个事情。如下图,选中按钮。
在进行伪登录,我们会发现出现了 rKey 以及 clog 两个文件,并且其 initiator 为celllog.js
于是,点击进去看到其 js 代码,并且双击 {} 将 js 代码进行 js 格式化,方便我们后续操作。
观察Js的执行过程
既然找到了 js 的位置,我们就可以来通过观察 js,找到 js 具体在如何执行,再通过 python 程序来模拟 js 的执行,或者是使用类似 js2py 直接把 js 代码转化为 python 程序去执行,来模拟 rkey 以及 password 的变动情况。
观察 js 的执行过程最简单的方式是添加断点
在左边行号点击即可添加,对应的右边 BreakPoints 中会出现现有的所有断点,然后继续点击登录,每次程序在断点位置都会停止,通过如果该行有变量产生,都会把变量的结果展示在Scoope中
在上图的右上角有1,2,3三个功能,分别表示:
- 1:继续执行到下一个断点
- 2:进入调用的函数中 (由此可以发现 password 加密的 js 文件
- 3:从调用的函数中跳出来
破解JS
在知道了 js 如何生成我们想要的数据之后,那么接下来我们就需要想方设法的去使用 Python代码 模拟 JS 代码 对数据的加密。但是,果真需要我们一行一行的模拟吗?并不需要,强大的 Python 已经封装了很多对 JS 代码块进行翻译的工具,今天我们着重讲解 js2py。
js2py介绍
js2py是一个js的翻译工具,也是一个通过纯python实现的js的解释器,github上源码与示例
使用它需要通过 pip install js2py 进行安装。
使用 js2py 获取参数
虽然不需要一行一行的去解析 JS 代码,但是实现 JS 的破解,仍然需要大家有基本的 JS 阅读能力。所以,我们现在来剖析一下登录的 JS 代码
formSubmit: function() {
var e, t = {};
$(".login").addEventListener("click", function() {
t.phoneNum = $(".phonenum").value,
t.password = $(".password").value,
e = loginValidate(t),
t.c1 = c1 || 0,
e.flag ? ajaxFunc("get", "http://activity.renren.com/livecell/rKey", "", function(e) {
var n = JSON.parse(e).data;
if (0 == n.code) {
t.password = t.password.split("").reverse().join(""),
setMaxDigits(130);
var o = new RSAKeyPair(n.e,"",n.n)
, r = encryptedString(o, t.password);
t.password = r,
t.rKey = n.rkey
} else
toast("公钥获取失败"),
t.rKey = "";
ajaxFunc("post", "http://activity.renren.com/livecell/ajax/clog", t, function(e) {
var e = JSON.parse(e).logInfo;
0 == e.code ? location.href = localStorage.getItem("url") || "" : toast(e.msg || "登录出错")
})
}) : toast(e.msg)
})
}
从以上代码我们得知一下信息:
- 我们要登录需要对密码进行加密和获取rkey字段的值
- rkey字段的值我们直接发送请求rkey请求就可以获得
- 密码是先反转然后使用RSA进行加密, js代码很复杂, 我们希望能通过在python中执行js来实现
具体实现思路
- 使用 session 发送 rKey 获取登录需要信息
- url: http://activity.renren.com/livecell/rKey
- 方法: get
- 根据获取信息对密码进行加密
- 准备用户名和密码
- 使用 js2py 生成 js 的执行环境:context
- 拷贝使用到 js 文件的内容到本项目中
- 读取 js 文件的内容,使用 context 来执行它们
- 向 context 环境中添加需要数据
- 使用 context 执行加密密码的js字符串
- 通过 context 获取加密后密码信息
- 使用 session 发送登录请求
- URL: http://activity.renren.com/livecell/ajax/clog
- 请求方法: POST
- 数据:
phoneNum: xxxxxxx
password: (加密后生产的)
c1: 0
rKey: rkey请求获取的
分析就到这里了奥~具体代码请关注公众号:极客夜读
或者直接扫码关注奥~