如果不借助他人的数据,你能自己算出瑞幸咖啡和星巴克咖啡其各自的门店数量吗?
让你自己算出一个精确的值,你会使用什么方法进行计算一线城市门店数量?
难度高一点点,你怎么样才能知道二线城市的门店总数,甚至是全国的门店数量?
用我们今天的方法,你可以知道,瑞幸咖啡在一线城市的数量是:1634间,而星巴克则为:1587间。
往下看答案之前,你可以想想有几种方法可以实现我们的目的。
1.准备
开始之前,你要确保Python和pip已经成功安装在电脑上噢,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。
Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),准备开始输入命令安装依赖。
当然,我更推荐大家用VSCode编辑器,把本文代码Copy下来,在编辑器下方的终端装依赖模块,多舒服的一件事啊:Python 编程的最好搭档—VSCode 详细指南。
输入以下命令安装我们所需要的依赖模块:
pip install requests
看到 Successfully installed xxx 则说明安装成功。你可以在Python实用宝典公众号后台回复:咖啡门店数 获得本文完整数据和代码。
2.获取门店数
怎么样,文章开头提出的问题你想到答案了吗?
其实很简单,那就是调用地图的接口进行门店搜索。 通过这个方法,我们不仅可以算出门店的数量,还能得到每个门店的对应位置,并且可以用来做后续的数据分析:
所以现在问题就转化为找到有提供搜索接口的地图供应商,而且这个接口得是免费的,因此我找了腾讯地图的接口:
你只需要上去注册账号,申请Key即可调用相关的接口,申请完了记得开webserviceAPI,选择签名校验的形式调用接口:
2.1 初始化
为了使用API,我们得先初始化请求链接及其所需要的参数:
class LocationSearch(object):
def __init__(self, keyword: str):
self.keyword = keyword
self.key = '你的Key'
self.sk = '你的校验sk'
self.url = (
'https://apis.map.qq.com/ws/place/v1/search?'
'boundary=region({},0)&key={}&keyword={}'
'&page_index={}&page_size=20'
)
Key是在你申请API权限的时候就会分配给你的,而sk是在你选择 签名校验 的形式调用接口时分配给你的。
那么我们如何用这两个数据请求接口呢?请看下面这个函数:
def request_data(self, location: str, page: int):
"""
请求接口数据
Arguments:
location {str} -- 地点
page {int} -- 第几页
Returns:
{list} -- 该页该地点的数据
{int} -- 该地点结果总数
"""
# 拼接链接
url = self.url.format(location, self.key, self.keyword, page)
# 获得数字签名,并将签名加到链接后面进行请求
wait_sig = url.split('qq.com')[1] + str(self.sk)
sig = hashlib.md5(wait_sig.encode('utf-8')).hexdigest()
res = requests.get(url + '&sig=' + sig)
# 获得数据返回
pois = res.json()['data']
# 避免请求上限
time.sleep(0.2)
return pois, res.json()['count']
首先是将初始化的请求链接拼接起来,然后由于需要签名校验,因此我们得如下进行操作:
GET请求分为:域名,请求路径和参数三个部分,用于签名计算的有:
请求路径: /ws/place/v1/search?
请求参数: boundary=region({},0)&key={}&keyword={} &page_index={}&page_size=20
注意{}是待填充的
1. 首先对参数进行排序:按参数名升序(本例结果为 boundary 在前,key在后,如果第一个字母相同,要依据第二个字母升序):
boundary=region({},0)&key={}(…后面略)
2. 签名计算(sig):
请求路径+”?”+请求参数+SK进行拼接,并计算拼接后字符串md5值,即为签名(sig):
要求:请求参数必须是未进行任何编码(如urlencode)的原始数据
md5(" /ws/place/v1/search?boundary=region({},0)&key={}&keyword={} &page_index={}&page_size=20**你的SK**")
计算得到结果类似为:22dxxxxxxxxxxxxxx2b0bcc0e50
**3. 生成最终请求:**将计算得到的签名sig,放到请求中(参数名即为:sig):
https://apis.map.qq.com/ws/place/v1/search? boundary=region({},0)&key={}&keyword={} &page_index={}&page_size=20&sig= 22dxxxxxxxxxxxxxx2b0bcc0e50
注意:计算 sig 要使用原始参数值,不要进行任何编码,但最终发送时的参数,是需要时行url编码的
最后拿到返回的值,里面带有所有结果的地理位置及结果的数量。
2.2 按地点返回结果
这一部分其实很简单,就是调用2.1的函数,然后实现分页保存变量,最后输出门店数量,返回数据。
def get_single_location(self, location: str):
"""
获得单个地点的数据
Arguments:
location {str} -- 地点
Returns:
{list} -- 该地点某关键词的所有数据
{int} -- 该地点某关键词的所有数量
"""
page = 1
location_data = []
pois, total = self.request_data(location, page)
for poisition in pois:
location_data.append(poisition)
# 如果有多页
while (total / 20) > page:
pois, _ = self.request_data(location, page)
for poisition in pois:
location_data.append(poisition)
page += 1
print(f'{self.keyword} {location} 门店总数为:{total}')
return location_data, total
计算一线城市的结果如下:
F:\\push\\20200315>python scrapy.py
瑞幸咖啡 北京 门店总数为:492
瑞幸咖啡 上海 门店总数为:581
瑞幸咖啡 广州 门店总数为:301
瑞幸咖啡 深圳 门店总数为:260
2.3 汇总结果并保存
接下来我们需要汇总2.2计算到的每个城市的数据,保存到json文件,并计算总数。
def get_cities_data(self, cities: str):
"""
获得所有城市某关键词的数据
Arguments:
cities {list} -- 城市列表
"""
result = []
keyword_count = 0
for city in cities:
# 获得该城市的所有门店和总数
data, count = self.get_single_location(city)
keyword_count += count
result.extend(data)
print(f'{self.keyword} 一线城市门店总数为:{keyword_count}')
# 导出数据
with open(f'{self.keyword}.json', 'w') as my_file:
json.dump(result, my_file, ensure_ascii=False)
最终可以获得一个 瑞幸咖啡.json 的文件,里面存有每个城市的咖啡店精确位置,并输出一个总数,这样调用即可:
if __name__ == '__main__':
cities = ['北京', '上海', '广州', '深圳']
loc = LocationSearch('瑞幸咖啡')
loc.get_cities_data(cities)
loc = LocationSearch('星巴克咖啡')
loc.get_cities_data(cities)
F:\\push\\20200315>python scrapy.py
瑞幸咖啡 北京 门店总数为:492
瑞幸咖啡 上海 门店总数为:581
瑞幸咖啡 广州 门店总数为:301
瑞幸咖啡 深圳 门店总数为:260
瑞幸咖啡 一线城市门店总数为:1634
星巴克 北京 门店总数为:380
星巴克 上海 门店总数为:797
星巴克 广州 门店总数为:209
星巴克 深圳 门店总数为:201
星巴克 一线城市门店总数为:1587
看来瑞幸咖啡一线城市里的门店数量已经超过星巴克了,不愧是割资本主义国家韭菜,造福中国老百姓的企业啊!
3.扩展
就像文章开头所提到的,如果你需要算出每个城市的咖啡店数量其实也很简单,咱可以调用下面这个接口请求腾讯地图的所有行政区数据,获得所有城市的名称:
https://apis.map.qq.com/ws/district/v1/list
不过我已经dump了一个,大家在Python实用宝典公众号后台回复:咖啡门店数 即可获得。
使用这一个,你只需要读取该csv文件提取所有城市名,然后放入cities变量中进行计算,如下代码所示:
if __name__ == '__main__':
with open('cities.csv', 'r', encoding='utf-8') as csvfile:
reader = csv.reader(csvfile)
cities = [row[0] for row in reader]
loc = LocationSearch('瑞幸咖啡')
loc.get_cities_data(cities)
loc = LocationSearch('星巴克咖啡')
loc.get_cities_data(cities)
不过,请注意一些特殊情况,比如说那个城市没有数据的时候,接口可能不会返回date数据,这时候要用字典的get方法进行处理:
# pois = res.json()['data']
pois = res.json().get('data', [])
不过如果你要计算全国的数据的话,这个方法并不可靠,因为无法避免山寨店的存在,山寨店一样也会被记入到腾讯地图中,而一线城市的监管严格,比较少出现山寨店的情况,因此可以用这个方法计算。
我们的文章到此就结束啦,如果你喜欢我们今天的Python 实战教程,请持续关注我们,如果对你有帮助,麻烦在下面点一个赞/在看哦,有任何问题都可以在下方留言区留言,我们都会耐心解答的!
Python实用宝典
不只是一个宝典
欢迎关注公众号:Python实用宝典
原文来自Python实用宝典:Python 计算 瑞幸和星巴克 谁的门店最多