javascript
点击时候确定某个元素 js_某空气质量监测平台 JS反爬
目標(biāo):中國(guó)空氣質(zhì)量在線監(jiān)測(cè)分析平臺(tái)|城市分析 參考CSDN中文章,記錄一下學(xué)習(xí)過(guò)程
通過(guò)切換城市,頁(yè)面數(shù)據(jù)是通過(guò) Ajax 加載的,數(shù)據(jù)接口:https://www.aqistudy.cn/apinew/aqistudyapi.php
請(qǐng)求的POST Data、返回的數(shù)據(jù)都被加密了
分析網(wǎng)站接口的加密邏輯
js加密的一般處理思路:
- 加密url或某個(gè)post data參數(shù)時(shí),可以全局搜索對(duì)應(yīng)的參數(shù)名或者值,確定js函數(shù)
- 整個(gè)post data加密或無(wú)法搜索到參數(shù),可通過(guò)元素的事件監(jiān)聽(tīng),確定js函數(shù)
1. 這里搜索參數(shù)名 d 顯然不現(xiàn)實(shí),當(dāng)我們點(diǎn)擊切換城市或者搜索按鈕之后,后臺(tái)便會(huì)發(fā)出 Ajax 請(qǐng)求,說(shuō)明這個(gè)點(diǎn)擊動(dòng)作是被監(jiān)聽(tīng)的,所以我們可以找一下這個(gè)點(diǎn)擊事件對(duì)應(yīng)的處理代碼在哪里,這里可以借助于 Firefox 來(lái)實(shí)現(xiàn),它可以分析頁(yè)面某個(gè)元素的綁定事件以及定位到具體的代碼在哪一行
切換城市or點(diǎn)擊搜索
2.發(fā)現(xiàn)綁定的 click 事件調(diào)用了 getData() 函數(shù),顯然是獲取數(shù)據(jù)的js,搜索這個(gè)函數(shù)
在 city_detail.html 的第 463 行就找到了這個(gè)函數(shù)的聲明
3.發(fā)現(xiàn)它又調(diào)用了 getAQIData() 和 getWeatherData() ,這兩個(gè)方法的聲明就緊挨在下面,再進(jìn)一步分析發(fā)現(xiàn)這兩個(gè)方法都調(diào)用了 getServerData() 這個(gè)方法,并傳遞了參數(shù) method、param ,還有一個(gè)回調(diào)函數(shù)很明顯是對(duì)返回?cái)?shù)據(jù)進(jìn)行處理的,這說(shuō)明 Ajax 請(qǐng)求就是由這個(gè) getServerData() 方法發(fā)起的,如圖所示:
4.繼續(xù)搜索這個(gè)函數(shù) getServerData()
city_detail.html 中的是上面兩個(gè)方法調(diào)用了 getServerData() ,這個(gè)文件里面并沒(méi)有g(shù)etServerData() 的聲明
貌似在 https://www.aqistudy.cn/js/jquery-1.8.0.min.js?v=1.2 中 右鍵 選擇在Sources中打開(kāi),繼續(xù)搜
果然找到了,發(fā)現(xiàn)這里經(jīng)過(guò) JavaScript 混淆加密了,這個(gè)方法名后面怎么直接跟了一些奇怪的字符串,而且不符合一般的 JavaScript 寫法,而且這行代碼的開(kāi)頭為eval(function(p,a,c,k,e,d)這種形式。
5.利用在線反混淆網(wǎng)站(http://www.bm8.com.cn/jsConfusion/)將 jquery-1.8.0.min.js 中這行 eval 開(kāi)頭的混淆后的 JavaScript 代碼復(fù)制一下,然后粘貼到這個(gè)網(wǎng)站中進(jìn)行反混淆,就可以看到正常的 JavaScript 代碼了,搜索一下就可以找到 getServerData() 方法了,可以看到這個(gè)方法確實(shí)發(fā)出了一個(gè) Ajax 請(qǐng)求,請(qǐng)求了Ajax 加載的數(shù)據(jù)接口:
在這里發(fā)現(xiàn)了一個(gè)getParam()方法:它接受了 method 和 object 參數(shù),然后返回得到的 param 結(jié)果就作為加密后的 POST Data,也就是d:后面的那一堆字符串
這里面還有一個(gè)decodeData()方法:對(duì)服務(wù)器傳回的數(shù)據(jù)進(jìn)行解密
6.還是在這一堆反混淆代碼中,緊挨著上面代碼找到了getParam()和decodeData()
其中 POST Data 的加密過(guò)程是 Base64 + AES 加密,Response Data 的解密是 AES + DES + Base64 解密
代碼
PyExecJS 是一個(gè)可以使用 Python 來(lái)模擬運(yùn)行 JavaScript 的庫(kù)
pip install PyExecJS還需安裝JS運(yùn)行環(huán)境(推薦安裝 Node.js )
Go~
不需要用 Python 重寫一遍 JavaScript,直接用 Python 來(lái)模擬運(yùn)行 JavaScript 就好
將剛才反混淆的 JavaScript 保存成一個(gè)文件,叫做 encryption.js,然后用 PyExecJS 模擬運(yùn)行相關(guān)的方法即可。
首先我們來(lái)實(shí)現(xiàn)加密過(guò)程,這里 getServerData() 方法其實(shí)已經(jīng)幫我們實(shí)現(xiàn)好了,并實(shí)現(xiàn)了 Ajax 請(qǐng)求,但這個(gè)方法里面有獲取 Storage 的方法,Node.js 不適用,所以這里不用它也別管他, 添加一個(gè) getEncryptedData() 方法實(shí)現(xiàn)加密,在 encryption.js 最后面加入一段代碼,實(shí)現(xiàn)如下方法:
function getEncryptedData(method, city, type, startTime, endTime) {var param = {};param.city = city;param.type = type;param.startTime = startTime;param.endTime = endTime;return getParam(method, param); }用于傳遞數(shù)據(jù),調(diào)用參數(shù)加密函數(shù)
接下來(lái)用python模擬執(zhí)行這些方法即可:
import execjs import json import requests# Init environment # 通過(guò) execjs(即 PyExecJS)的 get() 方法聲明一個(gè)運(yùn)行環(huán)境 node = execjs.get()# Params # 換成'GETCITYWEATHER'獲取溫度,風(fēng)向等數(shù)據(jù) method = 'GETDETAIL' city = '重慶' type = 'HOUR' start_time = '2019-09-06 00:00:00' end_time = '2019-09-06 12:00:00'# Compile javascript file = 'encryption.js' # 調(diào)用 compile() 方法來(lái)執(zhí)行剛才保存下來(lái)的加密庫(kù) encryption.js,執(zhí)行一遍才能調(diào)用 with open(file, encoding=('utf-8')) as f:ctx = node.compile(f.read())# Get params # 調(diào)用一下 JavaScript 中的 getEncryptedData() 方法即可實(shí)現(xiàn)加密 # 通過(guò) eval() 方法來(lái)模擬執(zhí)行,得到的結(jié)果賦值為 params,這個(gè)就是 POST Data 的加密數(shù)據(jù) js = 'getEncryptedData("{0}", "{1}", "{2}", "{3}", "{4}")'.format(method, city, type, start_time, end_time) params = ctx.eval(js)# Get encrypted response text url = 'https://www.aqistudy.cn/apinew/aqistudyapi.php' response = requests.post(url, data={'d': params})# Decode data # 調(diào)用一下 JavaScript 中的 decodeData() 方法即可實(shí)現(xiàn)解密 js = 'decodeData("{0}")'.format(response.text) decrypted_data = ctx.eval(js)data = json.loads(decrypted_data) res = data.get('result').get('data').get('rows') for i in res:print(i)method = 'GETDETAIL' 可以獲得aqi(空氣質(zhì)量指數(shù)),pm2.5 等數(shù)據(jù)
換成'GETCITYWEATHER' 可以獲取溫度,風(fēng)向等數(shù)據(jù)
Github:https://github.com/Ingram7/AQI
總結(jié)
以上是生活随笔為你收集整理的点击时候确定某个元素 js_某空气质量监测平台 JS反爬的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mysql子分区多少层_MYSQL子分区
- 下一篇: 天水看子宫内膜异位症最好的医院推荐