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

第一次請(qǐng)求.png

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

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

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

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

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

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

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

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

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

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

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

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

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

t.png
理一下最終的代碼
import json
import time
import hashlib
import requests
# ------------------------------------------采集5號(hào)線所有站點(diǎn)的經(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):
"""請(qǐng)求鏈接"""
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ǎn)調(diào)試,調(diào)試時(shí)重點(diǎn)關(guān)注輸入、輸出以及一些特殊名字(比如rsa、md5、base64等常用加密)
2.到加密部分,搞清楚使用的是哪種加密方式,優(yōu)先使用python庫代替
3.了解常用的加密原理很重要