欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python爬虫:某网站cookie参数__jsl_clearance_s生成分析

程序员文章站 2022-03-18 16:38:20
逛论坛发现一个求助帖,想获取数据但网站有cookie反爬,闲来无事就分析了一下cookie参数生成方法~目标:生成cookie中的__jsl_clearance_s参数工具:chrome/firefox浏览器、fiddler、pychram、python3.7、解混淆专解测试版V0.1模块:requests、re、execjs、json分析:首先打开浏览器,和fiddler抓包工具,发现浏览器进行了三次请求,前两次响应的状态码为521,响应内容都是一段js代码,第三次请求响应得到正常内...

逛论坛发现一个求助帖,想获取数据但网站有cookie反爬,闲来无事就分析了一下cookie参数生成方法~

目标:生成cookie中的__jsl_clearance_s参数

工具:chrome/firefox浏览器、fiddler、pychram、python3.7、解混淆专解测试版V0.1

模块:requests、re、execjs、json

分析:

首先打开浏览器,和fiddler抓包工具,发现浏览器进行了三次请求,前两次响应的状态码为521,响应内容都是一段js代码,第三次请求响应得到正常内容,并且携带了两个cookie参数;
Python爬虫:某网站cookie参数__jsl_clearance_s生成分析
Python爬虫:某网站cookie参数__jsl_clearance_s生成分析
通过三次请求对比,发现第三次请求cookie中的__jsl_clearance_s参数和第二次请求中的并不一样;
先看看第一次响应的结果,为一段js,这段js代码为浏览器设置了一个cookie;
Python爬虫:某网站cookie参数__jsl_clearance_s生成分析
这里直接利用正则将这段代码提取出来,再利用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是第一次请求后服务器为浏览器设置的;
Python爬虫:某网站cookie参数__jsl_clearance_s生成分析
Python爬虫:某网站cookie参数__jsl_clearance_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