Python系列爬虫之美团美食板块商家数据抓取(三)


image.png

昨天分享了一个美团美食板块的小爬虫。很多人私信说不明白_token参数到底怎么来的,真的没时间一一回复,干脆再推送一篇文章,来详细讲讲_token参数到底是怎么搞出来的。这次,我尽量写的详细一些。

image

详解

_token参数:

image

上回我们说到我们猜测_token参数是原数据先进行二进制压缩然后进行base64编码获得的,反向操作一波:

image

证实了我们的猜测,即_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吧。所以我们可以搞个文件,保存这些参数的常见值:

image

然后每次随机获取一个就行了,代码体现为:

'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进行了一样的操作,试试看:

image

还真是。猜都可以猜到需要的变量是:

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代码慢慢分析。大概就是这样,完。

image

以上就是今天为大家带来的Python爬虫美团美食商家数据抓取的全部内容了,关注我持续输出干货,咱们下期内容再见。

image