逛论坛发现一个求助帖,想获取数据但网站有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