python_空氣質量爬取

原文鏈接:https://cuiqingcai.com/5024.html#comments

JavaScript加密邏輯分析與Python模擬執行實現數據爬取

1、參考文章講解
2、分析js流程步驟
  • (1)網站數據接口通信已被加密:頁面數據是通過 Ajax 加載的,數據接口地址是:https://www.aqistudy.cn/apinew/aqistudyapi.php ,是一個 POST 形式訪問的接口,這個接口的請求數據和返回數據都被加密了,即 POST 請求的 Data、返回的數據都被加密了,下圖是數據接口的 Form Data 部分,可見傳輸數據是一個加密後的字符串:
    在這裏插入圖片描述
  • (2)下圖是該接口返回的內容,同樣是經過加密的字符串:
    在這裏插入圖片描述
  • (3)首先找到突破口,當我們點擊了這個搜索按鈕之後,後臺便會發出 Ajax 請求,說明這個點擊動作是被監聽的,所以我們可以找一下這個點擊事件對應的處理代碼在哪裏,這裏可以藉助於 Firefox 來實現,它可以分析頁面某個元素的綁定事件以及定位到具體的代碼在哪一行。如圖所示, click 事件是調用了 getData() 函數。:
    在這裏插入圖片描述
  • (4)接着藉助Chrome瀏覽器,找到getData()函數定義的位置。
    在這裏插入圖片描述在這裏插入圖片描述
  • (5)經過分析發現它又調用了 getAQIData() 和 getWeatherData() 兩個方法,而這兩個方法的聲明就在下面,再進一步分析發現這兩個方法都調用了 getServerData() 這個方法,並傳遞了 method、param 等參數,然後還有一個回調函數很明顯是對返回數據進行處理的,這說明 Ajax 請求就是由這個 getServerData() 方法發起的,如圖所示:
    在這裏插入圖片描述
  • (6)所以這裏我們只需要再找到 getServerData() 方法的定義即可分析它的加密邏輯了。
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
  • (7)那麼到這裏我們又可以發現一個很關鍵的方法,那就是 getParam(),它接受了 method 和 object 參數,然後返回得到的 param 結果就作爲 POST Data 參數請求接口了,所以 param 就是加密後的 POST Data,一些加密邏輯都在 getParam() 方法裏面,其方法實現如下:

在這裏插入圖片描述

  • (8)可以看到這裏使用了 Base64 和 AES 加密。加密之後的字符串便作爲 POST Data 傳送給服務器了,然後服務器再進行解密處理,然後進行邏輯處理,然後再對處理後的數據進行加密,返回了加密後的數據,那麼 JavaScript 再接收到之後再進行一次解密,再渲染才能得到正常的結果。所以這裏還需要分析服務器傳回的數據是怎樣解密的。順騰摸瓜,很容易就找到一個 decodeData() 方法,其定義如下:
    在這裏插入圖片描述
  • (9)這裏又經過了三層解密,才把正常的明文數據解析出來。
    所以一切都清晰了,我們需要實現兩個過程才能正常使用這個接口,即實現 POST Data 的加密過程和 Response Data 的解密過程。其中 POST Data 的加密過程是 Base64 + AES 加密,Response Data 的解密是 AES + DES + Base64 解密。加密解密的 Key 也都在 JavaScript 文件裏能找到,我們用 Python 實現這些加密解密過程就可以了。
    在這裏插入圖片描述
3、藉助 PyExecJS 庫來實現 JavaScript 模擬,用python爬取數據。
  • (1)安裝PyExecJS庫,pip install PyExecJS
  • (2)安裝Node,下載: https://nodejs.org/en/ ;下載得node-v10.15.3-x64.msi,然後一路next即可;最後添加環境變量。最後打開cmd輸入node -v;出現版本號即安裝成功

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

  • (3)保存js代碼:將剛纔反混淆的 JavaScript 保存成一個文件 air.js,然後用 PyExecJS 模擬運行相關的方法即可。 getServerData() 方法實現加密過程,並實現了 Ajax 請求,但這個方法裏面有獲取 Storage 的方法,Node.js 不適用,所以這裏我們直接改寫下,實現一個 getEncryptedData() 方法實現加密,在 air.js 裏面實現如下方法。即將getServerData() 方法替換成如下代碼;
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);
}

在這裏插入圖片描述

  • (4)python代碼實現爬取:
    • 首先定義一些參數,如 method、city、start_time 等。
      在這裏插入圖片描述
    • 然後通過 execjs(即 PyExecJS)調用 compile() 方法來執行剛纔保存下來的加密庫 air.js文件,因爲這裏麪包含了一些加密方法和自定義方法,所以只有執行一遍才能調用。
    • 接着我們再構造一個 js 字符串,傳遞這些參數,然後通過 eval() 方法來模擬執行,得到的結果賦值爲 params,這個就是 POST Data 的加密數據。
    • 再接着我們直接用 requests 庫來模擬 POST 請求就好。這樣 response 的內容就是服務器返回的加密的內容了。接下來我們再調用一下 JavaScript 中的 decodeData() 方法即可實現解密。
    • 最後獲得PM 2.5、AQI 等數據。代碼地址: https://github.com/Shirmay1/Python3_Case/tree/master/SpiderCase/AirQuality
import requests
import execjs
import json

# Params
method = 'GETDETAIL'  # method = 'GETCITYWEATHER'
city = '蘇州'
type1 = 'HOUR'
start_time = '2019-08-10 00:00:00'
end_time = '2019-08-10 23:00:00'

# Compile javascript
with open('air.js', 'r', encoding='utf8') as file:
    js_text = file.read()
    ctx = execjs.compile(js_text)

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

# Get encrypted response text
header = {
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Host": "www.aqistudy.cn",
    "Origin": "https://www.aqistudy.cn",
    "Referer": "https://www.aqistudy.cn/html/city_detail.html?v=1.8",
    "User-Agent": 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                  'Chrome/75.0.3770.100 Safari/537.36',
    "X-Requested-With": "XMLHttpRequest"}
api = 'https://www.aqistudy.cn/apinew/aqistudyapi.php'
response = requests.post(api, data={'d': params}, headers=header)

# Decode data
js = 'decodeData("{0}")'.format(response.text)
decrypted_data = ctx.eval(js)
data = json.loads(decrypted_data)
data_rows = data['result']['data']['rows']
for row in data_rows:
    print(row)

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章