Python爬虫系列之爬取美团美食板块商家数据(二)
今天为大家重写一个美团美食板块小爬虫,说不定哪天做旅游攻略的时候也可以用下呢。废话不多说,让我们愉快地开始吧~
开发工具
Python版本:3.6.4
相关模块:
requests模块;
argparse模块;
pyquery模块;
jieba模块;
pyecharts模块;
wordcloud模块;
以及一些Python自带的模块。
环境搭建
安装Python并添加到环境变量,pip安装需要的相关模块即可。
原理简介
前期准备:
因为我想让这个小爬虫可以爬取美团上任意城市美食板块的数据,但是每个城市的URL是不一样的,其格式为:
https://{城市拼音缩写}.meituan.com/
不同的城市需要不同的URL来构造请求从而爬取我们所需要的数据,于是现在的问题就变成了:如何获取所有城市对应的城市拼音缩写呢?
其实很简单,点击网页上的切换城市按钮:
然后查看网页源代码:
于是我们很easy地就可以爬取所有城市对应的城市拼音缩写了,代码实现如下:
'''城市名-拼音码爬取'''
def downCitynamesfile(citynamesfilepath):
url = 'https://www.meituan.com/changecity/'
doc = PyQuery(requests.get(url).text)
cities_dict = dict()
[cities_dict.update({city.text(): city.attr('href').replace('.', '/').split('/')[2]}) for city in doc('.cities a').items()]
with open(citynamesfilepath, 'w', encoding='utf-8') as f:
f.write(json.dumps(cities_dict, indent=2, ensure_ascii=False))
爬虫主程序:
现在随便切换到一个城市,以杭州为例。简单抓个包,可以发现美食商家的数据可以通过请求下图这个URL获得:
其构造方式为上图红框框出的baseURL加上下图所示的一堆参数:
其中变量为:
cityName:城市名
page:页码
uuid:uuid
_token:_token
其他均为不变量,直接copy过来就行了。前面两个变量很明显是什么,就不多说了。变量uuid在网页源代码里就能找到:
至于_token,稍微麻烦一点。考虑到_token结尾出现了=,所以猜测是base64编码,但是解码后发现是一堆16进制ASCII码,所以考虑原数据是先进行二进制压缩然后base64编码的。反向操作一波,发现果然是这样的:
全局搜索找生成相关参数的源代码:
一顿分析之后就可以开始写_token生成的代码了,具体如下:
'''获取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
'''获取_token参数'''
def getToken(brfilepath, city_code, uuid, page, cityname):
ts = int(time.time() * 1000)
with open(brfilepath, 'r') as f:
brs_dict = json.load(f)
key = random.choice(list(brs_dict.keys()))
info = brs_dict[key]
_token = {
'rId': 100900,
'ver': '1.0.6',
'ts': ts,
'cts': ts + random.randint(100, 120),
'brVD': info.get('barVD'),
'brR': [info.get('brR_one'), info.get('brR_two'), 24, 24],
'bI': ['https://{}.meituan.com/meishi/'.format(city_code),''],
'mT': [],
'kT': [],
'aT': [],
'tT': [],
'aM': '',
'sign': getSIGN(cityname, page, uuid, city_code)
}
return base64.b64encode(zlib.compress(str(_token).encode())).decode()
OK,知道了baseURL,获得了所有参数,我们就可以愉快地写主程序了:
'''主函数'''
def MTSpider(cityname, maxpages=50):
data_pages = {}
citynamesfilepath, uafilepath, uuidfilepath, brfilepath, savedatapath = initialProgram(cityname)
base_url = 'https://{}.meituan.com/meishi/api/poi/getPoiList?'.format(cityname2CODE(cityname, citynamesfilepath))
try:
for page in range(1, maxpages+1):
print('[INFO]: Getting the data of page<%s>...' % page)
data_page = None
while data_page is None:
params = getGETPARAMS(cityname, page, citynamesfilepath, uuidfilepath, brfilepath)
url = base_url + urlencode(params)
headers = {
'Accept': 'application/json',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'User-Agent': getRandomUA(uafilepath),
'Connection': 'keep-alive',
'Host': 'bj.meituan.com',
'Referer': 'https://{}.meituan.com/'.format(cityname2CODE(cityname, citynamesfilepath))
}
res = requests.get(url, headers=headers)
data_page = parsePage(json.loads(res.text))
if data_page is None:
time.sleep(random.random()+random.randint(3, 6))
initialProgram(cityname)
data_pages.update(data_page)
if page != maxpages:
time.sleep(random.random()+random.randint(3, 6))
except:
print('[Warning]: Something wrong...')
with open(savedatapath, 'wb') as f:
pickle.dump(data_pages, f)
其中解析返回的json数据的函数如下:
'''解析一页数据'''
def parsePage(data_page):
data_parse = dict()
infos = data_page.get('data')
if infos is None:
return None
else:
infos = infos.get('poiInfos')
for info in infos:
# 店名: 地址, 评论数量, 平均得分, 平均价格
data_parse[info.get('title')] = [info.get('address'), info.get('allCommentNum'), info.get('avgScore'), info.get('avgPrice')]
return data_parse
一些细节和tricks就不细说了。
All Done****!完整源代码详见主页个人介绍获取相关文件。
数据可视化
按惯例随手可视化一波,以抓取的杭州美食数据为例吧(这里只爬取了前50页),省的重新爬了。
先来搞个词云玩玩吧,用爬到的所有商家名/商家地址来搞个词云:
然后我们假设美食性价比的定义为(这个假设很可能是不合理,这里只是为了方便自己做下简单的数据分析随便假设了一下。):
性价比 = 评论数量 x 平均得分 / 平均价
于是我们可以得到"杭州性价比最高的十家店"为(只是个小例子,不供参考,如有雷同,不胜荣幸。):
为了帮助学习Python进步慢的伙伴们,在这里为大家准备了丰富的学习大礼包
OK。完整源代码详见主页中个人介绍获取相关文件。****
Python爬虫系列之爬取美团美食板块商家数据(二)的更多相关文章
- Python爬虫系列之爬取美团美食板块商家数据(一)
主要思路 目的: 根据输入的城市名,爬取该城市美团美食板块所有商家的数据.数据包括: 店名.评分.评论数量.均价.地址, 并将这些数据存入Excel中. 最后尝试对爬取到的数据做一个简单的分析. 克服 ...
- Python爬虫训练:爬取酷燃网视频数据
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 项目目标 爬取酷燃网视频数据 https://krcom.cn/ 环境 Py ...
- python爬虫系列之爬取多页gif图像
python爬取多页gif图像 作者:vpoet mail:vpoet_sir@163.com #coding:utf-8 import urllib import ur ...
- 【转载】教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
原文:教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神 本博文将带领你从入门到精通爬虫框架Scrapy,最终具备爬取任何网页的数据的能力.本文以校花网为例进行爬取,校花网:http:/ ...
- Python爬虫实例:爬取B站《工作细胞》短评——异步加载信息的爬取
很多网页的信息都是通过异步加载的,本文就举例讨论下此类网页的抓取. <工作细胞>最近比较火,bilibili 上目前的短评已经有17000多条. 先看分析下页面 右边 li 标签中的就是短 ...
- Python爬虫实例:爬取猫眼电影——破解字体反爬
字体反爬 字体反爬也就是自定义字体反爬,通过调用自定义的字体文件来渲染网页中的文字,而网页中的文字不再是文字,而是相应的字体编码,通过复制或者简单的采集是无法采集到编码后的文字内容的. 现在貌似不少网 ...
- Python爬虫实例:爬取豆瓣Top250
入门第一个爬虫一般都是爬这个,实在是太简单.用了 requests 和 bs4 库. 1.检查网页元素,提取所需要的信息并保存.这个用 bs4 就可以,前面的文章中已经有详细的用法阐述. 2.找到下一 ...
- python爬虫-基础入门-爬取整个网站《3》
python爬虫-基础入门-爬取整个网站<3> 描述: 前两章粗略的讲述了python2.python3爬取整个网站,这章节简单的记录一下python2.python3的区别 python ...
- python爬虫-基础入门-爬取整个网站《2》
python爬虫-基础入门-爬取整个网站<2> 描述: 开场白已在<python爬虫-基础入门-爬取整个网站<1>>中描述过了,这里不在描述,只附上 python3 ...
随机推荐
- npm-run-all
npm-run-all npm scripts https://www.npmjs.com/package/npm-run-all A CLI tool to run multiple npm-scr ...
- Webpack 4.x 默认支持 ES6 语法
Webpack 4.x 默认支持 ES6 语法 Q: 为什么 webpack4 默认支持 ES6 语法的压缩? A: terser 里面实现了 ES6 语法的 AST解析. webpack 4 里使用 ...
- onsen & UI & vue & mobile UI
onsen & UI vue & mobile UI $ npm i onsenui vue-onsenui # OR $ npm i -S onsenui vue-onsenui h ...
- vue router & query params
vue router & query params vue router get params from url https://zzk.cnblogs.com/my/s/blogpost-p ...
- Axios all in one
Axios all in one https://github.com/axios/axios#example GET const axios = require('axios'); // Make ...
- 「NGK每日快讯」12.31日NGK第58期官方快讯!
- java安全管理器SecurityManager
本文转载自java安全管理器SecurityManager 导语 这是一篇对Java安全管理器入门的文章,目的是简单了解什么是SecurityManager,对管理器进行简单配置,解决简单问题. 比如 ...
- 1053 Path of Equal Weight——PAT甲级真题
1053 Path of Equal Weight 给定一个非空的树,树根为 RR. 树中每个节点 TiTi 的权重为 WiWi. 从 RR 到 LL 的路径权重定义为从根节点 RR 到任何叶节点 L ...
- C++入门教程:大白话讲解,新手基础篇⭐⭐⭐(附源码及详解、视频课程资料推荐)
目录 C++教程 前言 视频教程 文字教程 集成开发环境(IDE) 编译器 工作原理 学习指南 入门书籍 进阶书籍 算法.竞赛书籍 教程 标准构建 程序解释 第一个C++程序--"hello ...
- Iterative learning control for linear discrete delay systems via discrete matrix delayed exponential function approach
对于一类具有随机变迭代长度的问题,如功能性电刺激,用户可以提前结束实验过程,论文也是将离散矩阵延迟指数函数引入到状态方程中. 论文中关于迭代长度有三个定义值:\(Z^Ta\) 为最小的实验长度,\(Z ...