Cookie相当于你浏览Web站点时,相对于这个站点的身份证号,如果说身份证号错误,肯定是不能正常访问这个站点的;这也是这次题目的考察内容
动态cookie,每过一段时间 ,就会重新加载cookie来重置页面,通过这种方式,达到反爬虫的效果,只有破解掉动态cookie的生成过程,才可以通过爬虫进行正常爬取
由于是动态Cookie,为了避免其他Cookie的影响,所以使用浏览器的无痕模式进行调试,按f12并选中【Preserve log】
【Preserve log】:保留请求日志,跳转页面的时候勾选上,可以看到跳转前的请求(可以让我看到更详细的请求)
这里抓包时依然要禁用debugger
这里分析抓到的包,第一个2是没有 返回任何数据的
并且谷歌也无法查看response
如下图所示:
第二个2的请求,是携带了cookie,并且也是请求到了有关的数据,如下图所示:
后面第三个2的XHR请求中,存在传输的数据,并且同样是携带了cookie的:
接下来,我们就来分析动态cookie的加载过程
既然谷歌抓包无法有效进行分析,那我们就用fiddler4,进行抓包分析,fiddler4是一款非常强大的抓包工具,可以配置抓取app的数据包,也可以抓取PC端的数据包,关于fiddler4的使用和配置,这里就不详细介绍了,自行百度即可。
使用fiddler4进行抓包,发现第一条/match/2的请求,原本在谷歌中无法查看的响应,在这里可以看到,可以发现,这是一段JS代码,这里,我们猜测这是进行动态cookie加密的代码(因为下一条/match/2紧接着获取了cookie,而且第一条的响应中也没有set-cookie)
我们对它进行解混淆后,复制到JS调试工具中进行分析(这里我使用的是pycharm分析,控制台进行测试)
这里代码量比较长,我们只首先关键的生成cookie的部分
与生成的cookie对比一下,发现"m" 和 “=” 之间应该是空字符串,但是这里还需要注意的是,这个函数可能通过eval执行其他操作,这里对_0x6a787a()函数进行简单分析
上代码:
function _0x6a787a(_0x5cd4c7, _0x24c494) {
var _0x1289d2 = _0x4c58de(this, function () {
var _0x55f098 = function () {
var _0x55df77 = _0x55f098["constructor"]("return /\" + this + \"/")()["compile"]("^([^ ]+( +[^ ]+)+)+[^ ]}");
return !_0x55df77["test"](_0x1289d2);
};
return _0x55f098();
});
_0x1289d2();
(function () {
_0x3878a0(this, function () {
var _0x261244 = new RegExp("function *\\( *\\)");
var _0x17ca1d = new RegExp("\\+\\+ *(?:[a-zA-Z_$][0-9a-zA-Z_$]*)", "i");
var _0x305294 = $dbsm_0x1f5ac5("init");
if (!_0x261244["test"](_0x305294 + "chain") || !_0x17ca1d["test"](_0x305294 + "input")) {
_0x305294("0");
} else {
$dbsm_0x1f5ac5();
}
})();
})();
_0x5d5fb0();
qz = [10, 99, 111, 110, 115, 111, 108, 101, 32, 61, 32, 110, 101, 119, 32, 79, 98, 106, 101, 99, 116, 40, 41, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 40, 115, 41, 32, 123, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 49, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 102, 111, 114, 40, 105, 61, 48, 59, 105, 60, 49, 49, 48, 48, 48, 48, 48, 59, 105, 43, 43, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 105, 115, 116, 111, 114, 121, 46, 112, 117, 115, 104, 83, 116, 97, 116, 101, 40, 48, 44, 48, 44, 105, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 125, 10, 10, 125, 10, 99, 111, 110, 115, 111, 108, 101, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 91, 111, 98, 106, 101, 99, 116, 32, 79, 98, 106, 101, 99, 116, 93, 39, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 402, 32, 116, 111, 83, 116, 114, 105, 110, 103, 40, 41, 32, 123, 32, 91, 110, 97, 116, 105, 118, 101, 32, 99, 111, 100, 101, 93, 32, 125, 39, 10];
eval(_0x55525f(qz));
try {
if (global) {
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
} else {
while (1) {
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
debugger;
}
}
} catch (_0x2455d3) {
return navigator["vendorSub"];
}
}
分析以上代码,执行了_0x1289d2()函数以及_0x5d5fb0(),这两个函数并且包含了eval(_0x55525f(qz))这段代码
我们先来看_0x1289d2()函数,放到控制台去执行
发现这个东西,跟加密没什么关系,先pass掉,记住有这样的东西
然后再来看_0x5d5fb0()这个函数
function _0x5d5fb0(_0x107682, _0x4d361d) {
if (_0x4d361d) {
return _0xfb1f8b(_0x107682);
}
return _0x4c0128(_0x107682);
}
function _0x55525f(_0x350007, _0x2fd05c) {
let _0x3aca5d = "";
for (let _0xa9a63 = 0; _0xa9a63 < _0x350007["length"]; _0xa9a63++) {
_0x3aca5d += String["fromCharCode"](_0x350007[_0xa9a63]);
}
return _0x3aca5d;
}
这个函数是需要传入参数的,没有参数估计也没什么用,我们先控制台运行一下试试:
最后就是这个特殊的eval(_0x55525f(qz))函数,我们来执行一下看看是否对结果cookie值有影响
好吧,只是一串字符串,仅此而已。
看剩下的其他代码:
try {
if (global) {
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
} else {
while (1) {
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
debugger;
}
}
} catch (_0x2455d3) {
return navigator["vendorSub"];
}
try…catch 这个语法,我相信稍微学了点编程的同学,都知道是什么意思,我这里也不再阐述,不懂的同学可以问问百度
try里面的内容还是有点意思,直接进来就报错
我为什么这么说呢,是因为,global这个变量根本就没有定义,所有会直接报错,进入catch里面,虽然说传入了变量,但是在下面的代码并没有引用,可以不管
最后,直接return navigator[“vendorSub”]
接下来,我们可以来删除无用函数,简化改变cookie的代码
function _0x83032f(_0x297bfd, _0x281a82) {
document["cookie"] = "m" + "=" + _0x53fd82(_0x297bfd) + "|" + _0x297bfd + "; path=/";
location["reload"]();
}
这样来看,很明显,加密是通过_0x53fd82(_0x297bfd)函数进行处理的,
接着分析_0x53fd82(_0x297bfd)函数,_0x297bfd是传入的参数,是由执行函数中_0x334d50()生成的,而 _0x53fd82()是一串很长的三元运算符,分析这个三元运算符,在执行函数时只给_0x3e4e6a传入了时间参数,其他的都是null值,因此直接跳入_0x5cd03d(_0x3e4e6a)来执行
_0x53fd82()代码如下所示:
function _0x53fd82(_0x3e4e6a, _0x31d569, _0x124094) {
_0x6a787a();
# 这里只执行_0x5cd03d(_0x3e4e6a) ,这里有一些三元运算符的计算技巧
return _0x31d569 ? _0x124094 ? _0x4c0128(_0x31d569, _0x3e4e6a) : y(_0x31d569, _0x3e4e6a) : _0x124094 ? _0x554afd(_0x3e4e6a) : _0x5cd03d(_0x3e4e6a);
}
_0x334d50()代码如下所示:
function _0x334d50(_0x53a223, _0xc9f38e) {
return Date["parse"](new Date());
}
然后又发现_0x5cd03d()函数依然调用了方法,调用的方法又调用了别的方法,我这里直接pass掉,直接放到控制台去运行调试。这里建议使用调试工具(博主正在找,找到给大家分享),将以上没用的代码进行删除,自定义一个get_m_value函数用来去到加密的值,如下所示:
# 这里是原来三元运算符的代码
function _0x53fd82(_0x3e4e6a, _0x31d569, _0x124094) {
return _0x5cd03d(_0x3e4e6a);
}
# 这是取到加密值
function _0x83032f(_0x297bfd, _0x281a82) {
return "m" + "=" + _0x53fd82(_0x297bfd) + "|" + _0x297bfd;
}
# 使用函数去调用代码
function get_m_value(){
return _0x83032f(_0x334d50());
}
我们看一下做题时的时间字符串:
把这个值复制后,放入修改后的代码中,进行加密验证,看看加密字符串有没有问题
#
接下来就可以愉快的敲python代码了
代码如下:
import requests
import execjs
import time
def get_res(page_num,parm):
url = 'http://match.yuanrenxue.com/api/match/2?page={}'.format(page_num)
headers = {
'Host': 'match.yuanrenxue.com',
'Referer': 'http://match.yuanrenxue.com/match/2',
'User-Agent': 'yuanrenxue.project',
'X-Requested-With': 'XMLHttpRequest',
'Cookie': parm
}
response = requests.get(url=url,headers=headers)
print(response.content.decode())
return response.json()
def calculate_m_value():
with open('22.js',mode='r',encoding='utf-8') as f:
JsData = f.read()
cookie_value = execjs.compile(JsData).call('get_m_value')
return cookie_value
if __name__ == '__main__':
sum_ = 0
for page_num in range(1,6):
print(page_num)
time.sleep(1)
cookie_value = calculate_m_value()
res = get_res(page_num,cookie_value)
for i in res['data']:
sum_ +=i['value']
print(sum_)