爬取存在js加密与js混淆的页面

本文以爬取中国空气质量在线监测分析平台为例进行分析。

需求

  • 地址: https://www.aqistudy.cn/html/city_detail.html

  • 爬取气象数据

分析

在页面中更换查找条件(城市)可以让抓包工具捕获到我们想要的数据包。而每个按钮只是把数据进行展示,并不会发起请求。

1.发送ajax请求

apistudyapi.php 该数据包就是我们最终定位到的爬取数据对应的数据包

  • 该数据包中可以提取到url和请求参数(请求参数不正常要么是动态加载的,要么是加密的,还可能是动态且加密的)(刷新后参数在变化也没在页面源码中找到,推测是动态且加密的)
  • 响应数据是经过加密的密文

2.发送的参数与响应数据是加密过的

当修改查询条件后,点击查询按钮后,发起 ajax 请求,url也没有变化,该请求可以请求到 apistudyapi.php 数据包

  • 想要捕获的数据是可以通过点击搜索按钮生成的,所以目标移动到这个按钮对应的事件。

3.按钮对应的事件

通过火狐浏览器的开发者工具可以找到搜索按钮绑定的点击事件对应的事件函数 getData()

分析 getData():

  • 在函数定义中找关于ajax请求相关的代码(含有url,解密方式)
  • type这个变量可以为 HOUR
  • 虽然没有找到ajax请求但是找到另外两个,getAQIData();getWeatherData();

4.getData定义

分析getAQIData(); getWeatherData();

这两个函数的实现除了method变量不同,剩下的都一致

  • method = (GETDETAIL或者是GETCITYWEATHER)
  • 在这两个函数的实现中也没有发现ajax请求对应的代码,但发现了一个叫做getServerData这个函数的实现中,猜测在这个getServerData包含着ajax请求
    • getServerData(method, param, 匿名函数, 0.5)
    • param是字典,有4组键值对(city,type,starttime,endtime)

getAQIData与getWeatherData

分析getServerData函数的实现

  • 最终通过抓包工具的全局搜索定位到了该函数的实现,但是实现的js代码被加密了,该种形式的加密被称为js混淆。

6.js混淆

如何破解js混淆

  • 地址:http://www.bm8.com.cn/jsConfusion/

在该函数的实现中终于找到了ajax请求对应的代码:

  • ajax请求的url
  • ajax请求方式
  • 请求参数的来源:getParam(method, object); object 是前面的param是字典
  • 对加密的响应数据解密:decodeData(密文)

基于python模拟js代码

  • PyExecJS模块可以让python模拟执行js代码
  • 环境安装:
    • pip install PyExecJS
    • 在本机安装node.js的开发环境
  1. 将解密后的代码写入本地,名为 test.js
  1. 获取ajax请求的动态变化且加密的请求参数(d:xxx)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#获取ajax请求的动态变化且加密的请求参数(d:xxx)
import execjs
node = execjs.get()

# Params
method = 'GETCITYWEATHER'
city = '北京'
type = 'HOUR'
start_time = '2018-01-25 00:00:00'
end_time = '2018-01-25 23:00:00'

# Compile javascript
file = 'test.js'
ctx = node.compile(open(file,encoding='utf-8').read())

# Get params
js = 'getPostParamCode("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time)
params = ctx.eval(js)
print(params)
  1. 携带捕获到请求参数进行请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#携带捕获到请求参数进行请求
import execjs
import requests

node = execjs.get()

# Params
method = 'GETCITYWEATHER'
city = '北京'
type = 'HOUR'
start_time = '2018-01-25 00:00:00'
end_time = '2018-01-25 23:00:00'

# Compile javascript
file = 'test.js'
ctx = node.compile(open(file,encoding='utf-8').read())

# Get params
js = 'getPostParamCode("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time)
params = ctx.eval(js)

#发起post请求
url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
response_text = requests.post(url, data={'d': params}).text
print(response_text)
  1. 对捕获到的加密的响应数据进行解密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 对捕获到的加密的响应数据进行解密
import execjs
import requests

node = execjs.get()

# Params
method = 'GETDETAIL'
city = '北京'
type = 'HOUR'
start_time = '2018-01-25 00:00:00'
end_time = '2018-01-25 23:00:00'

# Compile javascript
file = 'test.js'
ctx = node.compile(open(file,encoding='utf-8').read())

# Get params
js = 'getPostParamCode("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time)
params = ctx.eval(js)

#发起post请求
url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
response_text = requests.post(url, data={'d': params}).text

#对加密的响应数据进行解密
js = 'decodeData("{0}")'.format(response_text)
decrypted_data = ctx.eval(js)
print(decrypted_data)
-------------The End-------------

本文标题:爬取存在js加密与js混淆的页面

文章作者:Naqin

发布时间:2019年10月05日 - 20:10

最后更新:2019年11月05日 - 01:11

原始链接:https://chennq.top/网络爬虫/20191005-Web_Spider_11.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Naqin wechat
欢迎看官加我微信!
坚持原创技术分享,您的支持将鼓励我继续创作!
0%