前情回顾:
有道翻译参数破解
百度翻译参数破解
破解JSON加密字符串
本次爬取网址:人口流动大数据
由于最近几天都没有数据,为更好地演示案例,将日期设定于2020-12-23。利用谷歌浏览器进行抓包,结果如下
从上图可知,最终返回的数据是一串加密字符串,且在字符串的末端出现了==
(标准的base64会用等号作后缀!且数目一定是0、1或者2个)。因此,可初步猜测原字符串是被base64进行加密的。将该部分字符串复制到在线base64解码进行解密,结果如下
从结果来看,原字符串的确是由base64进行加密的!但解码后,得到的仍然是加密的JSON字符串,接下来我们就按照上篇博客破解JSON加密字符串介绍的步骤进行解密吧。
经过上篇博客分析,我们知道像这种JSON加密的字符串,在Javascript中必定会有JSON.parse
函数。因此,这里我们可以直接以Json.parse
为关键词进行搜索(或者以var iv
搜索也是可以的,var
是JS中定义变量的方式),搜索结果如下
虽然搜索出5个JS文件,但是通过简单分析可知,我们需要的加密源码一定是在index.js
中(cityCodeList、flightCodeList等字段很明显是我们需要爬取的数据字段)点击进入index.js
文件后,依旧以json.parse
为关键词进行搜索,最终定位到110行,在此打断点,刷新页面,结果如下
从结果来看,dataDecode
就是我们找的入口函数!data
为一开始我们分析的base64加密字符串!因此,我们将此部分的JS代码复制下来,并存为pop.js
。
function dataDecode(data){
var base = new Base64();
var d = JSON.parse(base.decode(data));
var key = 'UVJgCE+OFIff3hK5BT5sPBbGZzjR6FwntjSCwOA9tUQ=';
var key1 = CryptoJS.enc.Base64.parse(key);
var iv1 = CryptoJS.enc.Base64.parse(d.iv);
var decrypted=CryptoJS.AES.decrypt(d.value,key1,{
iv : iv1,
mode : CryptoJS.mode.CBC,
padding : CryptoJS.pad.Pkcs7
});
var d = decrypted.toString(CryptoJS.enc.Utf8);
return JSON.parse(d);
}
接下来,就是查漏补缺的时候了。
同前几篇博客一样,这里依旧利用execjs库执行JS代码,该部分Python代码如下所示
import execjs
import requests
def get_jscode(file_path):
with open(file_path,'r',encoding='utf8') as f:
jscode = f.read()
return jscode
def get_data(url):
header = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
}
data = requests.get(url).text
return data
if __name__=='__main__':
url = 'https://unicom_trip.133.cn/api/v1/city/source-top/V0152900?date=20201223'
data = get_data(url)
jscode = get_jscode('c:/users/dell/Desktop/pop.js')
rst = execjs.compile(jscode).call('dataDecode',data)
print(rst)
第一个错误为Base64未定义,这里我们返回到网站中,点击Base64()
函数进行跳转到base64.js
文件,结果如下
考虑原JS过长,在这里不再展示。将其全部复制后,加入pop.js
文件中,再次执行Python代码如下所示
第二个错误为CryptoJS未定义,同样返回原网站,点击CryptoJS.enc.Base64.parse
函数进行跳转到cryto-js.js
文件
(注意:这里如果电脑没有安装nodejs会先报JSON未定义的错误!)
结果如下
注意观察,如果仅复制这一块JS代码,那只能解决原入口函数中CryptoJS.enc.Base64.parse
该部分。但入口函数中还涉及到CrytoJS.AES.decrypt
函数等与CrytoJS
有关的参数。这里为了方便起见,我们将整个CryptoJS
对象复制下来。
同样,考虑这部分JS代码过长,在此不再展示。将其加入pop.js
文件后,再次执行Python代码,结果如下:
虽然我们拿到了数据,但从返回的结果来看,却不知道source_city
对应的是哪个城市。还记得我们刚开始在index.js
文件中搜索出的cityCodeList
字段么?我们定位到cityCodeList
,在90行打下断点,进行刷新,如下图所示。cityList
就是我们寻找的数据!
在控制台输入cityList后,即可返回城市代码的JSON数据。将其复制后,存为JSON文件。
最终完整代码如下
import execjs
import requests
import json
import pandas as pd
def get_jscode(file_path):
with open(file_path,'r',encoding='utf8') as f:
jscode = f.read()
return jscode
def get_data(url):
header = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
}
data = requests.get(url).text
return data
def save_data(data,json_path):
with open(json_path,'r',encoding='utf8') as f:
citycode = json.load(f)
data_list = data['data']
df = []
for city in data_list:
code = city['source_city']
city_name = citycode[code]['city_name']
user_percent = city['user_percent']
df.append([city_name,user_percent])
df1 = pd.DataFrame(df,columns=['城市名','流入比例'])
df1.to_csv('c:/users/dell/desktop/flight.csv',index=False,encoding='gbk')
print(df1)
if __name__=='__main__':
url = 'https://unicom_trip.133.cn/api/v1/city/source-top/V0152900?date=20201223'
data = get_data(url)
jscode = get_jscode('c:/users/dell/Desktop/pop.js')
rst = execjs.compile(jscode).call('dataDecode',data)
save_data(rst,'c:/users/dell/Desktop/city_code.json')
爬取数据部分展示