昨天分享了一個美團美食板塊的小爬蟲。很多人私信說不明白_token參數到底怎么來的,真的沒時間一一回復,干脆再推送一篇文章,來詳細講講_token參數到底是怎么搞出來的。這次,我盡量寫的詳細一些。
詳解
_token參數:
上回我們說到我們猜測_token參數是原數據先進行二進制壓縮然后進行base64編碼獲得的,反向操作一波:
證實了我們的猜測,即_token參數包括以下內容:
"rId":100900,
"ver":"1.0.6",
"ts":1559028105019,
"cts":1559028105097,
"brVD":[1536,150],
"brR":[[1536,864],[1536,824],24,24],
"bI":["https://bj.meituan.com/meishi/","https://bj.meituan.com/"],
"mT":[],
"kT":[],
"aT":[],
"tT":[],
"aM":"",
"sign":"eJwljk1uwjAQhe/CwkvHSZNAkLyoWCGh7jiATSYwbfyj8bgSd2DPJTgB52nvgYHdp6dP772FITDbUStxMAxvQD5/GQf6/3L9u9/EiN4DbUL2/MlMxREhMrqcNmEEXYtAeES/p1mfmGNaV5X9lg6Qs/HyEFxVOJ2wEtEcn340xKVR100v4mx4CuRKTJh+dvALc+EUiLXICV5zOWM5ZtXQttOwbHvbjoNdTXYl664bVNP1zYespZJq8QBcYkdy"
一共13個變量,刷新幾次並結合相關的js源碼(在rohr.min.js文件夾中,上一篇文章也截圖了):
var iP = {
rId: Rohr_Opt.Flag,
ver: _$_543c[138],
ts: new Date().getTime(),
cts: new Date().getTime(),
brVD: iN(),
brR: iM(),
bI: iL(),
mT: [],
kT: [],
aT: [],
tT: [],
aM: iK()
};
我們推斷不變量為:
--rId:
刷新幾次發現都不變;
--ver:
刷新幾次發現都不變;
--mT:
顯然是[];
--kT:
顯然是[];
--aT:
顯然是[];
--tT:
顯然是[];
--aM:
找到函數iK:
var iK = function() {
if (window._phantom || window.phantom || window.callPhantom) {
return _$_543c[135]
}
;return iQ.getWebdriver()
};
所以我們可以直接把aM當作不變量""。
至於ts和cts,很顯然是時間戳嘛。不過測試之后發現cts一直比ts大一丟丟。所以ts和cts的獲取方式可以寫成這樣:
ts = int(time.time() * 1000)
cts = ts + random.randint(100, 120)
至於為什么cts比ts大一丟丟,好像是因為后面代碼又執行了一次:
iP.cts = newDate().getTime();
接下來考慮brVD和brR這兩個參數,其生成函數分別為iN()和iM()。在同一個js文件里搜索一下可以發現以下代碼:
var iN = function() {
var hR = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var hK = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
return [hR, hK]
};
var iM = function() {
var iZ = [screen.width, screen.height];
var iW = [screen.availWidth, screen.availHeight];
var iX = screen.colorDepth;
var iY = screen.pixelDepth;
return [iZ, iW, iX, iY]
};
很顯然,iM就是返回你用的電腦屏幕的一些信息,其含義分別為:
screen.availWidth:屏幕可用工作區寬度
screen.availHeight:屏幕可用工作區高度
screen.width:屏幕分辨率的寬
screen.height:屏幕分辨率的高
screen.colorDepth:屏幕的顏色深度,根據CSSOM(CSS對象模型)視圖,為兼容起見,該值總為24。
screen.pixelDepth:返回屏幕的位深度/色彩深度,根據CSSOM(CSS對象模型)視圖,為兼容起見,該值總為24。
iN也差不多,具體什么含義自己Google吧。所以我們可以搞個文件,保存這些參數的常見值:
然后每次隨機獲取一個就行了,代碼體現為:
'brVD': info.get('barVD'),
'brR': [info.get('brR_one'), info.get('brR_two'), 24, 24],
接下來看bI的生成函數iL:
var iL = function() {
var jb = document.referrer;
var ja = window.location.href;
return [ja, jb]
};
其含義為(Google一大堆,隨手復制粘貼一個):
document.referrer:獲取前一個訪問頁面的URL地址
window.location.href:返回當前頁面的URL
當時忘記加第二個了,不過按我之前的代碼那么寫似乎也沒出錯:
'bI': ['https://{}.meituan.com/meishi/'.format(city_code),''],
OK,目前為止,我們已經知道了:
rId
ver
ts
cts
brVD
brR
bI
mT
kT
aT
tT
aM
唯獨不知道sign的:
eJwljk1uwjAQhe/CwkvHSZNAkLyoWCGh7jiATSYwbfyj8bgSd2DPJTgB52nvgYHdp6dP772FITDbUStxMAxvQD5/GQf6/3L9u9/EiN4DbUL2/MlMxREhMrqcNmEEXYtAeES/p1mfmGNaV5X9lg6Qs/HyEFxVOJ2wEtEcn340xKVR100v4mx4CuRKTJh+dvALc+EUiLXICV5zOWM5ZtXQttOwbHvbjoNdTXYl664bVNP1zYespZJq8QBcYkdy
看sign這個鬼樣子估計是和_token進行了一樣的操作,試試看:
還真是。猜都可以猜到需要的變量是:
uuid:上篇文章已經說了獲取方式了
cityname:顯然是城市名
page:顯然是頁碼
originUrl:顯然就是諸如https://{城市拼音縮寫}.meituan.com/meishi/&page=1,按以往經驗,這個page有沒有其實無所謂。
於是獲取sign參數的函數可寫為:
def getSIGN(cityname, page, uuid, city_code):
url = 'https://{}.meituan.com/meishi/'.format(city_code)
sign = 'areaId=0&cateId=0&cityName={}&dinnerCountAttrId=&optimusCode=1&originUrl={}&page={}&partner=126&platform=1&riskLevel=1&sort=&userId=&uuid={}'
sign = sign.format(cityname, url, page, uuid)
return sign
當然你也可以在那個js文件里搜索sign,然后看js代碼慢慢分析。大概就是這樣,完。
以上就是今天為大家帶來的Python爬蟲美團美食商家數據抓取的全部內容了,關注我持續輸出干貨,咱們下期內容再見。