1、项目介绍
技术栈:
Python语言、Django框架、Echarts可视化、HTML、Prophet时间序列算法预测模型
本文利用了Python爬虫技术对空气质量网站的数据进行获取,获取之后把数据生成CSV格式的文件,然后再存入数据库方便保存。再从之前九个月的AQI(空气质量指数)的值中进行分析,把数据取出来后,对数据进行数据清洗,最后将数据提取出来做可视化的分析。
在使用requests模块爬取空气质量网站的数据,网站存在严重的加密反爬,使用execjs运行JavaScript加密函数,拿到数据,然后解析存入文档。拿到自己需要的一些空气质量的数据,并且同时写入CSV文件。在对数据进行存储、分类时,利用了Python的sqlalchemy这个库,对写入CSV的数据去存进数据库,更简单直接的保存大群数据,然后再使用pandas这个库去读取数据库里面的数据,并且读取的数据可以直接去清洗、分类。
在数据可视化的步骤中,则用Django自带的库去将想要分析的数据进行可视化,绘制成条形图,方便比较各个城市的空气质量差异,将当天空气最好的前十五个城市可视化出来,并且通过时间序列模型等去分析城市的一些空气质量受到影响的原因,以及对应的治理措施。使用django框架实现的后端,dajngo-allauth实现的登陆注册,前端使用ntmC5,css3,JavaScript,bootstrap2响应式框架。
2、项目界面
(1)北京空气质量可视化分析
(2)北京空气质量可视化分析2-----可选择城市
(3)各城市空气质量预测
(4)上海空气质量分析
(5)空气质量数据查看
(6)后台数据管理
(7)注册登录界面
3、项目说明
本篇文章利用了Python爬虫技术对空气质量网站的数据进行获取,获取之后把数据生成CSV格式的文件,然后再存入数据库方便保存。再从之前九个月的AQI(空气质量指数)的值中进行分析,把数据取出来后,对数据进行数据清洗,最后将数据提取出来做可视化的分析。
在使用requests模块爬取空气质量网站的数据,网站存在严重的加密反爬,使用execjs运行JavaScript加密函数,拿到数据,然后解析存入文档。拿到自己需要的一些空气质量的数据,并且同时写入CSV文件。在对数据进行存储、分类时,利用了Python的sqlalchemy这个库,对写入CSV的数据去存进数据库,更简单直接的保存大群数据,然后再使用pandas这个库去读取数据库里面的数据,并且读取的数据可以直接去清洗、分类。
在数据可视化的步骤中,则用Django自带的库去将想要分析的数据进行可视化,绘制成条形图,方便比较各个城市的空气质量差异,将当天空气最好的前十五个城市可视化出来,并且通过时间序列模型等去分析城市的一些空气质量受到影响的原因,以及对应的治理措施。使用django框架实现的后端,dajngo-allauth实现的登陆注册,前端使用ntmC5,css3,JavaScript,bootstrap2响应式框架。
关键词:Python;爬虫;数据分析;数据库;数据可视化
4、核心代码
import os, django
import sys
path = os.path.dirname(os.path.abspath(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(path)
# print(sys.path)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "kongqi.settings") # project_name 项目名称
django.setup()
from web.models import XinXi
import random
import time
import re
import hashlib
import urllib3
from django.db.models import Q
urllib3.disable_warnings()
import execjs
import requests
import base64
import json
from urllib.parse import urljoin
def des_js(js_str):
keys = re.findall(f'DES\.encrypt\((\w+)\s?,\s?(\w+)\s?,\s?(\w+)\)', js_str)
text_name, key_name, iv_name = keys[0]
key = re.findall(f'const\s+?{key_name}\s+?=.*?"(.*?)"', js_str)[0]
iv = re.findall(f'const\s+?{iv_name}\s+?=.*?"(.*?)"', js_str)[0]
appid_name = re.findall("appId:.*?(\w+),", js_str)[0]
appId = re.findall(f"var\s?{appid_name}\s?=.*?'(.*?)'", js_str)[0]
param_name = re.findall("data:\s?\{\s?(\w+):.*?}", js_str)[0]
des_keys = re.findall(f'DES\.decrypt\(data,\s?(\w+),\s?(\w+)\);', js_str)
des_dec_key_name, des_dec_iv_name = des_keys[0]
des_dec_key = re.findall(f'const\s+?{des_dec_key_name}\s+?=.*?"(.*?)"', js_str)[0]
des_dec_iv = re.findall(f'const\s+?{des_dec_iv_name}\s+?=.*?"(.*?)"', js_str)[0]
aes_keys = re.findall(f'AES\.decrypt\(data,\s?(\w+),\s?(\w+)\);', js_str)
aes_dec_key_name, aes_dec_iv_name = aes_keys[0]
aes_dec_key = re.findall(f'const\s+?{aes_dec_key_name}\s+?=.*?"(.*?)"', js_str)[0]
aes_dec_iv = re.findall(f'const\s+?{aes_dec_iv_name}\s+?=.*?"(.*?)"', js_str)[0]
method = "GETDAYDATA"
obj = {"city": "济南", "month": '201702'}
timestamp = int(time.time() * 1000)
clienttype = 'WEB'
form_data = {
"appId": appId,
"method": method,
"timestamp": timestamp,
"clienttype": clienttype,
"object": obj,
"secret": hashlib.md5(
f'{appId}{method}{timestamp}{clienttype}{str(obj)}'.replace("'", '"').replace(' ', '').encode(
'utf-8')).hexdigest()
}
base64_d = base64.b64encode(str(form_data).replace("'", '"').replace(' ', '').encode('utf-8')).decode('utf-8')
result = js.call("des_encrypt", base64_d, key, iv)
data = {param_name: result}
print(data)
url = "https://www.aqistudy.cn/historydata/api/historyapi.php"
resp = requests.post(url=url, headers=headers, data=data)
print(resp.text)
dec_data = js.call('dec_func', resp.text, des_dec_key, des_dec_iv, aes_dec_key, aes_dec_iv)
print(json.loads(dec_data))
def aes_js(js_str):
keys = re.findall(f'AES\.encrypt\((\w+)\s?,\s?(\w+)\s?,\s?(\w+)\)', js_str)
text_name, key_name, iv_name = keys[1]
key = re.findall(f'const\s+?{key_name}\s+?=.*?"(.*?)"', js_str)[0]
iv = re.findall(f'const\s+?{iv_name}\s+?=.*?"(.*?)"', js_str)[0]
appid_name = re.findall("appId:.*?(\w+),", js_str)[0]
appId = re.findall(f"var\s?{appid_name}\s?=.*?'(.*?)'", js_str)[0]
param_name = re.findall("data:\s?\{\s?(\w+):.*?}", js_str)[0]
des_keys = re.findall(f'DES\.decrypt\(data,\s?(\w+),\s?(\w+)\);', js_str)
des_dec_key_name, des_dec_iv_name = des_keys[0]
des_dec_key = re.findall(f'const\s+?{des_dec_key_name}\s+?=.*?"(.*?)"', js_str)[0]
des_dec_iv = re.findall(f'const\s+?{des_dec_iv_name}\s+?=.*?"(.*?)"', js_str)[0]
aes_keys = re.findall(f'AES\.decrypt\(data,\s?(\w+),\s?(\w+)\);', js_str)
aes_dec_key_name, aes_dec_iv_name = aes_keys[0]
aes_dec_key = re.findall(f'const\s+?{aes_dec_key_name}\s+?=.*?"(.*?)"', js_str)[0]
aes_dec_iv = re.findall(f'const\s+?{aes_dec_iv_name}\s+?=.*?"(.*?)"', js_str)[0]
method = "GETDAYDATA"
obj = {"city": "济南", "month": '201702'}
timestamp = int(time.time() * 1000)
clienttype = 'WEB'
form_data = {
"appId": appId,
"method": method,
"timestamp": timestamp,
"clienttype": clienttype,
"object": obj,
"secret": hashlib.md5(
f'{appId}{method}{timestamp}{clienttype}{str(obj)}'.replace("'", '"').replace(' ', '').encode(
'utf-8')).hexdigest()
}
base64_d = base64.b64encode(str(form_data).replace("'", '"').replace(' ', '').encode('utf-8')).decode('utf-8')
result = js.call("aes_encrypt", base64_d, key, iv)
data = {param_name: result}
print(data)
url = "https://www.aqistudy.cn/historydata/api/historyapi.php"
resp = requests.post(url=url, headers=headers, data=data)
dec_data = js.call('dec_func', resp.text, des_dec_key, des_dec_iv, aes_dec_key, aes_dec_iv)
print(json.loads(dec_data))
def bs64_js(js_str):
appid_name = re.findall("appId:.*?(\w+),", js_str)[0]
appId = re.findall(f"var\s?{appid_name}\s?=.*?'(.*?)'", js_str)[0]
param_name = re.findall("data:\s?\{\s?(\w+):.*?}", js_str)[0]
method = "GETDAYDATA"
obj = {"city": "济南", "month": '202112'}
timestamp = int(time.time() * 1000)
clienttype = 'WEB'
form_data = {
"appId": appId,
"method": method,
"timestamp": timestamp,
"clienttype": clienttype,
"object": obj,
"secret": hashlib.md5(
f'{appId}{method}{timestamp}{clienttype}{str(obj)}'.replace("'", '"').replace(' ', '').encode(
'utf-8')).hexdigest()
}
base64_d = base64.b64encode(str(form_data).replace("'", '"').replace(' ', '').encode('utf-8')).decode('utf-8')
data = {param_name: base64_d}
print(data)
url = "https://www.aqistudy.cn/historydata/api/historyapi.php"
resp = requests.post(url=url, headers=headers, data=data)
des_keys = re.findall(f'DES\.decrypt\(data,\s?(\w+),\s?(\w+)\);', js_str)
des_dec_key_name, des_dec_iv_name = des_keys[0]
des_dec_key = re.findall(f'const\s+?{des_dec_key_name}\s?=.*?"(.*?)"', js_str)[0]
des_dec_iv = re.findall(f'const\s+?{des_dec_iv_name}\s?=.*?"(.*?)"', js_str)[0]
aes_keys = re.findall(f'AES\.decrypt\(data,\s?(\w+),\s?(\w+)\);', js_str)
aes_dec_key_name, aes_dec_iv_name = aes_keys[0]
aes_dec_key = re.findall(f'const\s+?{aes_dec_key_name}\s?=.*?"(.*?)"', js_str)[0]
aes_dec_iv = re.findall(f'const\s+?{aes_dec_iv_name}\s?=.*?"(.*?)"', js_str)[0]
dec_data = js.call('dec_func', resp.text, des_dec_key, des_dec_iv, aes_dec_key, aes_dec_iv)
print(json.loads(dec_data))
if __name__ == '__main__':
url = "https://www.aqistudy.cn/historydata/daydata.php?city=%E4%BF%9D%E5%AE%9A&month=201910"
headers = {
}
req = requests.get(url, headers=headers)
js_url = re.findall(r'src="(resource/js/.*?.min.js\?v=\d+)"', req.text)[0]
js_req = requests.get(url=urljoin(url, js_url), headers=headers)
print(js_req.url)
js_code = open('airHistory_2108.js', 'r').read()
js_bs64_bs64_code = js_req.text[5:-2]
js_code = js_code.replace('jscode_pattern', js_bs64_bs64_code)
js = execjs.compile(js_code)
res = js.call("get_full_js", js_bs64_bs64_code)
# print(res)
type_len = len(re.findall("dweklxde", res))
print(type_len)
base64_str = re.findall("'(.*?)'", res)[0]
if type_len == 2:
target_js = base64.b64decode(base64.b64decode(base64_str)).decode('utf-8')
des_js(js_str=target_js)
elif type_len == 1:
target_js = base64.b64decode(base64_str).decode('utf-8')
aes_js(js_str=target_js)
elif type_len == 0:
bs64_js(js_str=res)