爬虫cookie反爬------加速乐(jsl)
加速乐
反爬虫技术:加速乐采用了包括OB混淆、动态加密算法和多层Cookie获取等高级反爬虫技术,确保整体校验的严密性。关键校验字段位于Cookie中的 __jsl_clearance_s
,其验证过程通常涉及三次关键的请求,有效抵御恶意爬虫的侵扰。
特点
加速乐的特点是一般有三次请求:
第一次请求网站返回的状态码是521,响应返回的数据经过了AAEncode混淆
第二次请求网站返回的状态码也是521,响应返回的数据经过了OB混淆
第三次请求网站返回的状态码是正常的200,成功访问网页
1. 逆向目标
-
首页:https://www.mafengwo.cn/i/5376978.html
-
目标:cookie: __jsl_clearance_s
2. 逆向分析
-
加速乐cookie加密的特性
-
cookie关键字的名称:
__jsl_clearance_s
里面会有jsl
的字样 -
会对网址请求3次,前两次都是512的响应状态码,后面会响应正确的200
逆向思路
根据加速乐的特点,思路分为以下三点:第一次请求响应头中会返回__jsluid_s参数,响应内容解密后得到第一次__jsl_clearance_s参数
第二次请求携带上第一次请求得到的cookie值,响应内容解密后得到第二次__jsl_clearance_s参数
第三次请求携带上最终的cookie,即可成功访问网页
逆向分析
先对目标网站抓个包分析一下,可以看到请求同一个页面发生了三次请求,前两次都是返回521状态码,最后一次是200,符合加速乐特征我们自己请求一下第一个包:
发现他是一段混淆的代码
-
我们执行一下:
response = requests.get(url, headers=headers) coo = re.findall("document.cookie=(.*?);location", response.text)[0] # cookie取值之后前面的不用 __jsl_clearance_s = execjs.eval(coo).split('ance_s=')[-1] __jsluid_s = response.cookies.get('__jsluid_s') # print(response.text) # print(response) print(__jsl_clearance_s, __jsluid_s)
-
发现能够得到参数
-
我们带上这个的cookie,请求第二遍
cookies = {'__jsluid_s': __jsluid_s, '__jsl_clearance_s': __jsl_clearance_s} res = requests.get(url, headers=headers, cookies=cookies) # 确保响应内容使用 UTF-8 编码 print(res.text)
-
发现他是一段混淆的代码
-
格式化之后分析这段代码,在网页打脚本断点,已经hook这个cookie
-
//当前版本hook工具只支持Content-Type为html的自动hook //下面是一个示例:这个示例演示了hook全局的cookie设置点 (function() { //严谨模式 检查所有错误 'use strict'; //document 为要hook的对象 这里是hook的cookie var cookieTemp = ""; Object.defineProperty(document, 'cookie', { //hook set方法也就是赋值的方法 set: function(val) { if(val.indexOf("__jsl_clearance_s") != -1){ debugger; } //这样就可以快速给下面这个代码行下断点 //从而快速定位设置cookie的代码 console.log('Hook捕获到cookie设置->', val); cookieTemp = val; return val; }, //hook get方法也就是取值的方法 get: function() { return cookieTemp; } }); })();
-
每断一下在重新hook
-
第一次断住的位置,前一栈是
-
不是我们想要的那个
-
第二次断住才是正确的入口,看前一个栈
-
发现是在这个地方生成的,我们打上断点,发现但是是段不住的,因为网页数据是动态生成的
-
我们得本地替换啥的,先将代码本地保存一份到notepad++,因为该js代码是动态变化的,方便我们调试。我们直接在开发者工具新建代码片段进行调试,记得清除cookie再断点调试
-
为了不必呀麻烦,先把这个else删掉
-
放在本地运行,发现需要补环境
-
方法一,慢慢来
-
补到这里发现没有报错了,下面是如何导出的问题,发现加密的那个是document。cookie赋值的
-
我们打印
-
发现是先打印空数据再执行下面的,原因在于是个异步,比如这个里面的settimeout函数
方法就是直接把settimeout删掉,变成自执行方法
-
直接ok
-
或者方法二,全部补完:
-
window = global; document = { cookie: '' }; navigator = { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', webdriver: false, }; location = {}; setTimeout = function setTimeout(code, time ){ console.log('开启定时器'); code(); }
-
也可以
-
继续深入研究
- 了解jsl内部实现原理,https://articles.zsxq.com/id_i1r0fe0emjz2.html
-
代码:
import requests
import re
import execjs
headers = {
'Referer': 'https://www.mafengwo.cn/i/5376978.html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0'
}
url = 'https://www.mafengwo.cn/i/5376978.html'
def first_request():
response = requests.get(url, headers=headers)
coo = re.findall("document.cookie=(.*?);location", response.text)[0]
# cookie取值之后前面的不用
__jsl_clearance_s = execjs.eval(coo).split('ance_s=')[-1]
__jsluid_s = response.cookies.get('__jsluid_s')
return __jsluid_s, __jsl_clearance_s
def second_request():
__jsluid_s, __jsl_clearance_s = first_request()
cookies = {'__jsluid_s': __jsluid_s, '__jsl_clearance_s': __jsl_clearance_s}
res = requests.get(url, headers=headers, cookies=cookies)
go_code = execjs.eval(re.findall(';go\((.*?)\)</s', res.text)[0])
# print(go_code)
js = execjs.compile(open('test.js', encoding='utf-8').read())
__jsl_clearance_s = js.call('go', go_code).split('ance_s=')[-1]
# print(__jsl_clearance_s)
cookies['__jsl_clearance_s'] = __jsl_clearance_s
return cookies
def third_request():
cookies = second_request()
res = requests.get(url, headers=headers, cookies=cookies)
print(res.text)
print(res.request.headers)
third_request()
完结。撒花~