通過鏈家的地鐵找房功能爬取地鐵線路以及小區(qū)數(shù)據(jù)時,會碰到一個authorization參數(shù),這個參數(shù)每次請求都會變化,而且不帶也會請求失敗,因此可初步判斷是一個js加密參數(shù)。

第一次請求.png

第二次請求.png
我們通過chrome瀏覽器的斷點功能找authorization的加密js代碼
首先,抓包找到鏈接地址,點進(jìn)去

抓包找到j(luò)s文件.png
然后,格式化代碼并打上斷點

格式化代碼并打上斷點.png
點擊地鐵路線,進(jìn)行網(wǎng)頁刷新

點擊旁邊的地鐵線路.png
Call Stack為函數(shù)框,Local為參數(shù)框,進(jìn)入debugger模式后,重點是找到加密函數(shù)所在位置,一般邏輯是看在某個函數(shù)之前,我們所找的參數(shù)不存在,那這個函數(shù)就是我們要找的(函數(shù)調(diào)用是從下到上)

函數(shù)與參數(shù)所在位置.png
最后一個函數(shù)為send,參數(shù)欄沒有發(fā)現(xiàn)authorization,但是我們在console中把t打印出來,發(fā)現(xiàn)t中是包含了authorization的,因此需往前推繼續(xù)找加密函數(shù)

console輸出參數(shù).png
通過這樣往前遞歸查找,我們發(fā)現(xiàn)第二個ajax函數(shù)之后,就不再出現(xiàn)我們的authorization參數(shù)了,因此可定位authorization的加密代碼在第二個ajax里

加密代碼.png
同時發(fā)現(xiàn)ajax中存在l.authorization = s,var s = this.getMd5(l)兩行代碼,那么可確定authorization是被這個this.getMd5函數(shù)加密的了

點擊函數(shù).png
點擊進(jìn)入這個函數(shù),加上斷點,并重新進(jìn)入debugger模式

加上斷點繼續(xù)運行.png
可以看到輸入時一個字典,中間參數(shù)i是一個字符串,且i需要繼續(xù)被n函數(shù)處理

加上斷點重新運行.png
進(jìn)入n函數(shù),發(fā)現(xiàn)是一系列的匿名函數(shù)與嵌套調(diào)用,繼續(xù)研究需要耗費大量時間。我們仔細(xì)看一下n的名字,發(fā)現(xiàn)是md5加密,而python本身自帶md5加密庫,我們只需記錄js代碼的輸入與輸出,并與python的md5加密結(jié)果比對是否一致即可

n函數(shù).png
js中md5函數(shù)的輸入與輸出

js輸入與輸出.png
python中md5加密結(jié)果

python輸入與輸出.png
比較發(fā)現(xiàn)結(jié)果一致,再繼續(xù)運行斷點到send,輸出t,發(fā)現(xiàn)參數(shù)與我們計算出的一致

t.png
理一下最終的代碼
import json
import time
import hashlib
import requests
# ------------------------------------------采集5號線所有站點的經(jīng)緯度--------------------------------------------------
def get_md5(txt):
"""md5加密函數(shù)"""
m = hashlib.md5()
m.update(txt.encode('utf-8'))
return m.hexdigest()
def get_line_site(url):
"""請求鏈接"""
headers = {'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Host': 'ajax.lianjia.com',
'Referer': 'https://gz.lianjia.com/ditu/',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'}
r = requests.get(url, headers=headers)
print(r.status_code)
return r
def get_url():
"""拼接鏈接"""
url = 'https://ajax.lianjia.com/map/subway/station/?city_id=440100&line_id=110460685&request_ts={' \
'request_ts}&source=ljpc&authorization={authorization}'
request_ts = int(time.time() * 1000)
md5_data = "vfkpbin1ix2rb88gfjebs0f60cbvhedlcity_id=440100line_id=110460685request_ts={request_ts}".format(
request_ts=request_ts)
authorization = get_md5(md5_data)
url = url.format(request_ts=request_ts, authorization=authorization)
return url
if __name__ == '__main__':
line_url = get_url()
print(line_url)
res = get_line_site(line_url)
items = res.json()['data']
with open('lon_and_lat.txt', 'w') as f:
json.dump(items, f)
print(items)
總結(jié)
1.多用斷點調(diào)試,調(diào)試時重點關(guān)注輸入、輸出以及一些特殊名字(比如rsa、md5、base64等常用加密)
2.到加密部分,搞清楚使用的是哪種加密方式,優(yōu)先使用python庫代替
3.了解常用的加密原理很重要