中国空气质量在线检测平台数据爬取

中国空气质量在线检测平台数据爬取

平台网站:https://www.aqistudy.cn/html/city_detail.html

1.获取综合版块对应的数据:

将当前页面的搜索条件进行修改后,点击搜索按钮,

才可以通过抓包工具捕获到ajax请求的数据包,

数据包中提取出的ajax请求的url是:https://www.aqistudy.cn/apinew/aqistudyapi.php

2.ajax请求的数据包中响应数据是经过加密的密文数据data,

并且请求参数d所对应的请求参数d的值是动态变化.

3.找到搜索按钮点击所对应的点击事件,

通过火狐浏览器进行操作,操作结束后,发现搜索按钮有一个click事件,

该事件触发后执行了一个getData()的js函数,定位该函数的源码位置

function getData()
       {
       	  state = 0;
    		  city=$('#city').val();
    		  $.cookie('dcity', city, {expires : 30});
    		  //type = $('#type').combobox('getValue');
         	  type = $('input:radio[name=type]:checked').val();
    		  getTimeSel();

    		  if(type=="HOUR")
    		  {
    		  	 var timediff = converTimeFormat($('#dtbEndTime').datetimebox('getValue')).getTime()-converTimeFormat($('#dtbStartTime').datetimebox('getValue')).getTime();
    		  	 if(timediff >30*24*3600*1000)
    		  	 {
    		  	 	showMessage(false,"按小时查询仅支持查询一个月数据,查看长时间变化趋势请选择按日查询!");
    		  	 	return ;
    		  	 }
    		  }
    		  getAQIData();
    		  getWeatherData();
       }

在该函数内部有一个type=="HOUR"

还有两个重要的函数调用,分别是 getAQIData();getWeatherData();

function getAQIData()
       {
         var method = 'GETDETAIL';
         var param = {};
         param.city = city;
         param.type = type;
         param.startTime = startTime;
         param.endTime = endTime;
         getServerData(method, param, function(obj) {
function getWeatherData()
       {

         var method = 'GETCITYWEATHER';
         var param = {};
         param.city = city;
         param.type = type;
         param.startTime = startTime;
         param.endTime = endTime;
         getServerData(method, param, function(obj) {

​ getAQIData();getWeatherData()的实现内部取查找相关的蛛丝马迹:

​ 定义了method='GETDETAIL'和param这两个变量,并且param是一个字典,字典中有四个键值(city,type,startTime,endTime)

​ 还发现了另一个函数的调用getServerData(method,param,回调函数,0.5)

分析getServerData这个函数的定义,想要从中找到相关的蛛丝马迹:

​ 在谷歌抓包工具中做全局搜索,最终定位到了该函数的实现在jQuery-min.js文件中,

​ 来到了该文件中进行了getServerData的定义查找,发现找到的是经过加密的js函数的实现。

​ js代码块加密成为js混淆:我们必须将混淆的数据进行js反混淆。

js反混淆:通过该网站进行反混淆的操作http://www.bm8.com.cn/jsConfusion/

​ 经过反混淆后,我们终于看到了getServerData函数js实现的源码,对实现的源码进行分析:

  • 在该函数内部找到了ajax请求相关的操作

  • 找到了动态请求参数d值的来源:

    getParam(method, object); 返回的就是我们苦苦寻找的动态变化的post请求参数。

  • 找到了对ajax请求到的密文数据data进行解密的js函数

    decodeData(data),该函数参数data就是加密的响应数据,该函数的返回值就是经过解密的原文数据。

分析总结:点击查询按钮后,最终是触发了getServerData函数发起了ajax请求,请求参数是通过getParam进行的加密,响应回来的密文数据是通过decodeData函数进行解密处理的。

问题:找到的相关重要的信息对应的函数都是js写的,爬虫程序必须基于python实现

4.PyExecJS介绍

​ PyExecJS 是一个可以使用 Python 来模拟运行 JavaScript 的库。

我们需要pip install PyExecJS对其进行环境安装。

注意点:如果想在python中使用PyExecJS,必须事先安装好nodejs的环境

  • 将反混淆的js代码保存下来

  • 在该文件中添加自定义函数,getPostParamCode,该函数是为了获取且返回post请求的动态加密参数

    function getPostParamCode(method, city, type, startTime, endTime){
        var param = {};
        param.city = city;
        param.type = type;
        param.startTime = startTime;
        param.endTime = endTime;
        return getParam(method, param);
    }
    

在py文件中先获取node对象,设定参数值,再编译js文件

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 = 'js.js'
# 注意要加上编码,否则可能会出现编码问题报错
ctx = node.compile(open(file,encoding='utf-8').read())

py文件中执行js语句获取动态加密参数

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

访问url获取加密数据

url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
pm = {
    'd':params
}
#text就是请求到的加密的响应数据
text = requests.post(url,data=pm).text

执行js语句解密data数据

js = 'decodeData("{0}")'.format(text)
data = ctx.eval(js)
print(data)

成功代码:

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 = 'js.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)

url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
pm = {
    'd': params
}
# text就是请求到的加密的响应数据
text = requests.post(url, data=pm).text

js = 'decodeData("{0}")'.format(text)
data = ctx.eval(js)
print(data)

posted @ 2020-06-09 12:19  Hedger_Lee  阅读(1008)  评论(0编辑  收藏  举报