您现在的位置是: 网站首页> 学习笔记> JS逆向 JS逆向

汽车之家js逆向,css反爬

2022-08-03 [JS逆向] [css反爬] 7647人已围观

今天看了一下汽车之家,记录一下详情页的CSS反爬分析。 url:https://car.autohome.com.cn/config/series/6261.html

先记录一下大概情况与获取数据方法,再上代码。

1.响应的样子;

正常请求响应的内容未经过渲染,数据放在script标签里的js变量中,如图: config变量中放的就是当前车型各版本的配置数据; 细心一点就可以看到,这些数据中词不完整,且大量充斥着\<span>标签, 每一个标签中都带一个class属性,如hs_kw41_configNl;

这个span标签在渲染后呈现给我们的就是响应中缺失的词汇。 那么我们目标就明确了就是还原span标签在当前位置表示的词汇或字符。

2.还原方法;

首先肯定是全局搜span标签的class属性hs_kw41_configNl,看看有没有对应的样式。 明显是搜不到的,然后我们把hs_kw41_configNl拆开搜一下,比如搜"_config"会搜到 拼接hs_kw41_configNl的类似代码:

function $GetClassName$ ($index$)            {                 return '.hs_kw' + $index$ + '_configNl';            } 

打个script断点大概跑一下,就会发现有代码在生成词汇数组,而数组中的索引index对应的就样式名hs_kw41_configNl中kw41的41; 把生成数组的js代码扣出来直接生成词汇映射表,根据样式名hs_kw41_configNl中的数值取值批量替换即可还原。

因为这个映射表是动态生成的,每次都不一样,所以我们也动态扣js代码, js代码就在响应中,与数据一同返回的, 一共有3段js代码,分别为生成_baike、_config、_option相对应的映射表。 比较偷懒的方法就是整段整段的扣出来,然后稍微补一些环境; 补的环境比较简单,如下即可:

window = global;
window.ruleDict = [];
document = {
    createElement:function (){
        return {};
    },
    getElementsByTagName: function (){
      return [
          {
            appendChild: function (){}
          },
      ]
    },
};

下面贴代码,删了少量代码,避免可能造成的麻烦,有需要的可以自行补一下,就删了几行。

import json

import requests
import re
import execjs

url = "https://car.autohome.com.cn/config/series/6261.html#pvareaid=102189"

payload = {}
headers = {
    'authority': 'car.autohome.com.cn',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
    'accept-language': 'zh-CN,zh;q=0.9',
    'cache-control': 'no-cache',
    'pragma': 'no-cache',
    'sec-ch-ua': '".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    'sec-fetch-dest': 'document',
    'sec-fetch-mode': 'navigate',
    'sec-fetch-site': 'none',
    'sec-fetch-user': '?1',
    'upgrade-insecure-requests': '1',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}

response = requests.request("GET", url, headers=headers, data=payload)

# 取出生成字典映射关系的js
jscode = re.findall('<script>\(function\(.*?\(document\);</script>?', response.text)
baike_dict_code = ''
config_dict_code = ''
option_dict_code = ''
for _jscode in jscode:
    if re.search("'.hs_kw'\s?\+\s?\$index\$\s?\+\s?'_baike\w+';", _jscode):
        baike_dict_code = _jscode.replace('<script>', '').replace('</script>', '')
    elif re.search("'.hs_kw'\s?\+\s?\$index\$\s?\+\s?'_config\w+';", _jscode):
        config_dict_code = _jscode.replace('<script>', '').replace('</script>', '')
    elif re.search("'.hs_kw'\s?\+\s?\$index\$\s?\+\s?'_option\w+';", _jscode):
        option_dict_code = _jscode.replace('<script>', '').replace('</script>', '')

# js代码处理
env_code = """
window = global;
window.ruleDict = [];
document = {
    createElement:function (){
        return {};
    },
    getElementsByTagName: function (){
      return [
          {
            appendChild: function (){}
          },
      ]
    },
};
function get_dict(){
    return window.ruleDict
}
"""
to_replace_code = "替换js代码中生成数组的逻辑,自己定个变量window.ruleDict,把生成的结果赋给它直接导出"

raw_replace_code = re.search("正则找数组生成的代码块", baike_dict_code).group(1)
baike_dict_code = env_code + baike_dict_code.replace(raw_replace_code, to_replace_code)

raw_replace_code = re.search("正则找数组生成的代码块", config_dict_code).group(1)
config_dict_code = env_code + config_dict_code.replace(raw_replace_code, to_replace_code)

raw_replace_code = re.search("正则找数组生成的代码块", option_dict_code).group(1)
option_dict_code = env_code + option_dict_code.replace(raw_replace_code, to_replace_code)

# 获取内容替换映射表并转换为映射字典
ctx = execjs.compile(baike_dict_code)
baike_dict = ctx.call('get_dict')
baike_dict = {'{}'.format(idx): val for idx, val in enumerate(baike_dict)}

ctx = execjs.compile(config_dict_code)
config_dict = ctx.call('get_dict')
config_dict = {'{}'.format(idx): val for idx, val in enumerate(config_dict)}

ctx = execjs.compile(option_dict_code)
option_dict = ctx.call('get_dict')
option_dict = {'{}'.format(idx): val for idx, val in enumerate(option_dict)}


detail_raw = re.search('var config = (\{.*\});', response.text).group(1)
detail_replace_list = list(set(re.findall("<span class='hs_kw\d+_config\w+'></span>", detail_raw)))
for replace_str in detail_replace_list:
    detail_raw = detail_raw.replace(replace_str, config_dict.get(re.search('kw(\d+)', replace_str).group(1)))

detail_json = json.loads(detail_raw)



print(baike_dict, '\n', config_dict, '\n', option_dict)

文章评论

暂无评论

添加评论





本栏推荐

站点信息

  • 建站时间:2021-01-01
  • 网站程序:Django 3.1.2
  • 文章统计:53篇
  • 文章评论:36条
  • 统计数据