Python爬虫:某网站cookie参数__jsl_clearance_s生成分析
逛论坛发现一个求助帖,想获取数据但网站有cookie反爬,闲来无事就分析了一下cookie参数生成方法~
目标:生成cookie中的__jsl_clearance_s参数
工具:chrome/firefox浏览器、fiddler、pychram、python3.7、解混淆专解测试版V0.1
模块:requests、re、execjs、json
分析:
首先打开浏览器,和fiddler抓包工具,发现浏览器进行了三次请求,前两次响应的状态码为521,响应内容都是一段js代码,第三次请求响应得到正常内容,并且携带了两个cookie参数;
通过三次请求对比,发现第三次请求cookie中的__jsl_clearance_s参数和第二次请求中的并不一样;
先看看第一次响应的结果,为一段js,这段js代码为浏览器设置了一个cookie;
这里直接利用正则将这段代码提取出来,再利用execjs模块执行,即可得到这个cookie,当然这个cookie并不是最终的cookie;
# 提取js代码
js_clearance = re.findall('cookie=(.*?);location.href=', response.text)[0]
# 执行后获得cookie参数js_clearance
result = execjs.eval(js_clearance).split(';')[0]
通过观察第二个请求,第二个请求再次得到一段js代码,并且携带了两个cookie参数,一个__jsluid_s、一个__jsl_clearance_s,而__jsl_clearance_s就是刚刚利用js生成的,所以和第三次请求的__jsl_clearance_s不一样,__jsluid_s是第一次请求后服务器为浏览器设置的;
继续分析得知第二次请求需要携带这两个cookie参数才能得到第二段js代码。这段js代码是混淆过的,利用解混淆专解测试版V0.1进行解混淆,得到正确的js代码(js代码就不放出来了);
简单解读cookie生成方法就是调用go方法并传入一段参数,最后该方法为浏览器设置一个cookie。那么思路就简单了,直接将js代码保存为本地文件,利用execjs模块执行代码调用go方法并传入需要的参数就能得到cookie;不过需要修改一下js代码,先将js代码中go方法调用删除再将为浏览器设置cookie的代码修改为直接返回;
setTimeout(function () {
document["cookie"] = _0x1c7f44["tn"] + "=" + _0x3227c3[0] + ";Max-age=" + _0x1c7f44["vt"] + "; path = /";
location["href"] = location["pathname"] + location["search"];
}, _0x528bb0);
} else {
alert("\u8BF7\u6C42\u9A8C\u8BC1\u5931\u8D25");
将上面代码改为:
return _0x1c7f44["tn"] + "=" + _0x3227c3[0] + ";Max-age=" + _0x1c7f44["vt"] + "; path = /";
另外代码中go方法内部这个方法读取了浏览器参数,应该是判断是否为爬虫用的,经过测试可以删除,不影响cookie生成;
function _0xa5b8cd() {
var _0x5ddf29 = window["navigator"]["userAgent"],
_0x15ad8f = ["Phantom"];
for (var _0x152237 = 0; _0x152237 < _0x15ad8f["length"]; _0x152237++) {
if (_0x5ddf29["indexOf"](_0x15ad8f[_0x152237]) != -1) {
return true;
}
}
if (window["callPhantom"] || window["_phantom"] || window["Headless"] || window["navigator"]["webdriver"] || window["navigator"]["__driver_evaluate"] || window["navigator"]["__webdriver_evaluate"]) {
return true;
}
}
if (_0xa5b8cd()) {
return;
}
js代码修改完成后保存到本地,js测试后发现有时会报错,多次刷新观察响应的js代码发现,该网站有三套cookie生成方式,而传入参数中的ha的值有三种,分别为md5、sha1、sha256,应该是加密方式,ha的值不同,js代码不同。那么思路有了,按上面的方法分别保存三套js代码,通过提取参数中的ha值判断使用哪一套代码,执行即可正确得到cookie;
# 提取js代码中的参数并转字典
parameter = json.loads(re.findall(r'};go\((.*?)\)</script>', response.text)[0])
js_file = ''
# 判断需要使用的js代码
if parameter['ha'] == 'sha1':
js_file = 'sha1.js'
elif parameter['ha'] == 'sha256':
js_file = 'sha256.js'
elif parameter['ha'] == 'md5':
js_file = 'md5.js'
最后将前面已经得到的__jsluid_s参数和最后生成的cookie一起携带去进行第三次请求,即可得到正确响应内容。
代码:
import re
import execjs
import requests
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 关闭ssl验证提示
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
}
url = 'https://www.yidaiyilu.gov.cn/xwzx/gnxw/87373.htm'
def get_page():
response = requests.get(url, headers=headers, verify=False)
return response
def get_parameter(response):
# 获取cookie参数jsluid
jsluid = response.headers.get('set-cookie').split(';')[0]
# 提取js代码
js_clearance = re.findall('cookie=(.*?);location.href=', response.text)[0]
# 执行后获得cookie参数js_clearance
result = execjs.eval(js_clearance).split(';')[0]
global headers
headers.update({'cookie': jsluid + '; ' + result})
response = get_page()
# 提取参数并转字典
parameter = json.loads(re.findall(r'};go\((.*?)\)</script>', response.text)[0])
js_file = ''
# 判断cookie生成方式
if parameter['ha'] == 'sha1':
js_file = 'sha1.js'
elif parameter['ha'] == 'sha256':
js_file = 'sha256.js'
elif parameter['ha'] == 'md5':
js_file = 'md5.js'
return parameter, js_file, jsluid
def get_cookie(param, file):
parameter = {
"bts": param['bts'],
"chars": param['chars'],
"ct": param['ct'],
"ha": param['ha'],
"tn": param['tn'],
"vt": param['vt'],
"wt": param['wt']
}
with open(file, 'r') as f:
js = f.read()
cmp = execjs.compile(js)
# 执行js代码传入参数
clearance = cmp.call('go', parameter)
return clearance
def run():
response = get_page()
parameter, js_file, jsluid = get_parameter(response)
clearance = get_cookie(parameter, js_file)
global headers
headers.update({'cookie': jsluid + '; ' + clearance})
html = requests.get(url, headers=headers, verify=False)
print(html.content.decode())
run()
总结:这个__jsl_clearance_s生成方式比较简单,懂一点js即可搞定。
本文地址:https://blog.csdn.net/YungGuo/article/details/109818327
下一篇: 译文 | 为什么软件架构如此重要?