文章预览
前言
俗话说得好:“人狠话不多,祝福要先上”。在这个春节与情人节交织的好日子,kimol君真诚祝福可爱的小伙伴们:
平安喜乐,万事顺意🌠🌠🌠~
蓦然回首,佳人便在灯火阑珊处~👩❤️👨
玫瑰花🌹作为一种传递爱意、互诉情长的礼物,在情人节的今天可谓是爆款。而我一直以来都有一个小小的疑惑:
“玫瑰花的销量究竟跟地区是否有关系呢?如果有,那么它在哪些城市最畅销呢?”
各位小伙伴,请系好安全带,咋们发车了🚗…(滴,学生卡)
一、思路分析
思路仍旧是
获取数据+数据分析
两步走战略,就是这么的简单粗暴~
分析的首要任务便是获取玫瑰花的销量情况,打开美团外卖我们可以看到这样的画面:
没有错,可以看到月销量数据。 那么,就决定是它了!
数据分析部分我决定利用pyecharts库基于每个城市的平均月销量制作一个热力图,这样便能直观地反映出受欢迎程度,最后效果是酱紫的:
其对应的数值如下:
我们大抵可以看出,玫瑰花在
川渝
、
江浙沪
、
京津冀
、
河南
一带的平均月销量更高,其更受欢迎。我想,这在一定程度上也反映出了这里的人们对生活的无尽热爱和对烂漫的质朴追求叭~
结论仅对本次实验数据负责,仅供参考哦~
二、数据爬取
1.数据搜索
通过Fiddler抓包获取美团外卖的搜索接口,其URL为:
url = 'https://wx-shangou.meituan.com/mtweapp/v2/search/v9/poiwithfilter?ui=xxx'
该请求为一个POST请求,对应的数据为:
data = { 'wm_dtype' : 'microsoft' ,
'wm_dversion' : '7.0.9' ,
'wm_uuid' : 'xxx' ,
'wm_visitid' : 'xxx' ,
'wm_appversion' : '5.13.26' ,
'wm_logintoken' : 'xxx' ,
'userToken' : 'xxx' ,
'req_time' : 1613274108532 ,
'waimai_sign' : '%2F' ,
'wm_longitude' : 116938974 ,
'wm_latitude' : 30109265 ,
'wm_actual_longitude' : 0 ,
'wm_actual_latitude' : 0 ,
'userid' : 'xxx' ,
'user_id' : 'xxx' ,
'uniqueid' : 'xxx' ,
'open_id' : 'xxx' ,
'openidcipher' : 'xxx' ,
'uuid' : 'xxx' ,
'rc_platform' : 13 ,
'platform' : 13 ,
'rc_app' : 0 ,
'partner' : 214 ,
'riskLevel' : 71 ,
'keyword' : '鲜花' ,
'page_index' : 0 ,
'category_type' : 101578 ,
'entrance_id' : 101578 ,
'sort_type' : 0 ,
'search_global_id' : '274108528141A972426FC37CA2E81D27BA604D85428455EA33E345156F93CDB59C024AE9F' ,
'wm_ctype' : 'mt_weapp' }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
注
:xxx代表用户登录状态以及校验等相关参数,我们大可不必深究它们是怎么生成的,直接从Fiddler中将其复制出来即可~
其中,
keyword
表示搜索的关键词,
page_index
表示搜索结果的页码(每次返回20条数据),
wm_longitude
和
wm_latitude
分别表示用户所在的经纬度。通过测试可以知道,我们只需要改变经纬度便能得到不同地区的数据,那么可以定义如下函数:
def get_info ( keyword, pos, page= 0 ) :
'''
获取外卖商品信息
'''
url = 'https://wx-shangou.meituan.com/mtweapp/v2/search/v9/poiwithfilter?ui=xxx'
headers = { }
data = { 'wm_dtype' : 'microsoft' ,
'wm_dversion' : '7.0.9' ,
'wm_uuid' : 'xxx' ,
'wm_visitid' : 'xxx' ,
'wm_appversion' : '5.13.26' ,
'wm_logintoken' : 'xxx' ,
'userToken' : 'xxx' ,
'req_time' : 1613274108532 ,
'waimai_sign' : '%2F' ,
'wm_longitude' : int ( pos[ 0 ] * 10 ** 6 ) ,
'wm_latitude' : int ( pos[ 1 ] * 10 ** 6 ) ,
'wm_actual_longitude' : 0 ,
'wm_actual_latitude' : 0 ,
'userid' : 'xxx' ,
'user_id' : 'xxx' ,
'uniqueid' : 'xxx' ,
'open_id' : 'xxx' ,
'openidcipher' : 'xxx' ,
'uuid' : 'xxx' ,
'rc_platform' : 13 ,
'platform' : 13 ,
'rc_app' : 0 ,
'partner' : 214 ,
'riskLevel' : 71 ,
'keyword' : keyword,
'page_index' : page,
'category_type' : 101578 ,
'entrance_id' : 101578 ,
'sort_type' : 0 ,
'search_global_id' : '274108528141A972426FC37CA2E81D27BA604D85428455EA33E345156F93CDB59C024AE9F' ,
'wm_ctype' : 'mt_weapp' }
res = requests. post( url, headers= headers, data= data)
res_json = res. json( )
return res_json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
然而,我们要怎样才能得到城市对应的经纬度呢?
2.获取城市经纬度
通过高德地图的坐标捡拾系统,便能实现地理位置与经纬度的转换。由于接口很简单,这里就不详细介绍了,同样是通过抓包分析,可以定义如下转换函数:
def get_lonlat ( keywords) :
'''
获取经纬度
'''
cookies = {
'cna' : '2voBF5IOjUUCAXWIWXVuwr8W' ,
'UM_distinctid' : '1767bba477b6bd-00c663bca533b3-1a347740-e1000-1767bba477c515' ,
'isg' : 'BGhoxgK9o-s-8I9R8e9xGWcsOlZ6kcybbxhnvCKZpePsfQjn1qD8K_v0cZWN1oRz' ,
'l' : 'eBOY0AmuO96VEuAdBOfalurza779_IOYYuPzaNbMiOCP_CCp5q8cWZ-AMOL9Cn1Vh6UXc37LhhQJBeYBqMIKnxvOKVLdi6Mmn' ,
'tfstk' : 'cFtVBg4K3mnq_Csdmisa5HrbndsAZ8QG8uWOoFwkl8RrRN_li2NOE50PU9UjqZf..' ,
}
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0' ,
'Accept' : '*/*' ,
'Accept-Language' : 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2' ,
'Referer' : 'https://lbs.amap.com/console/show/picker' ,
'Connection' : 'keep-alive' ,
}
params = (
( 's' , 'rsv3' ) ,
( 'children' , '' ) ,
( 'key' , 'e07ffdf58c8e8672037bef0d6cae7d4a' ) ,
( 'page' , '1' ) ,
( 'offset' , '10' ) ,
( 'city' , '110000' ) ,
( 'language' , 'zh_cn' ) ,
( 'callback' , 'jsonp_160108_' ) ,
( 'platform' , 'JS' ) ,
( 'logversion' , '2.0' ) ,
( 'sdkversion' , '1.3' ) ,
( 'appname' , 'https://lbs.amap.com/console/show/picker' ) ,
( 'csid' , '6DCF386C-8777-4724-AE49-8E688CCEF75A' ) ,
( 'keywords' , keywords) ,
)
res = requests. get( 'https://restapi.amap.com/v3/place/text' , headers= headers, params= params, cookies= cookies)
html = res. text
data = re. findall( '\((.*)\)' , html) [ 0 ]
data = json. loads( data)
location = data[ 'pois' ] [ 0 ] [ 'location' ]
lon = float ( location. split( ',' ) [ 0 ] )
lat = float ( location. split( ',' ) [ 1 ] )
return ( lon, lat)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
3.完整代码
从每个省级行政区中选出一个城市(即省会),创建一个txt用于将其存储:
完整的数据爬取代码如下:
"""
Created on Sun Feb 14 11:54:59 2021
@author: kimol_love
"""
import os
import re
import json
import requests
import pandas as pd
def get_info ( keyword, pos, page= 0 ) :
'''
获取外卖商品信息
'''
url = 'https://wx-shangou.meituan.com/mtweapp/v2/search/v9/poiwithfilter?ui=xxx'
headers = { 'Connection' : 'keep-alive' ,
'Content-Length' : '1191' ,
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat' ,
'_deferreds' : '[object Array]' ,
'content-type' : 'application/x-www-form-urlencoded' ,
'uuid' : 'xxx' ,
'wm-ctype' : 'mt_weapp' ,
'Accept-Encoding' : 'gzip, deflate, br' }
data = { 'wm_dtype' : 'microsoft' ,
'wm_dversion' : '7.0.9' ,
'wm_uuid' : 'xxx' ,
'wm_visitid' : 'xxx' ,
'wm_appversion' : '5.13.26' ,
'wm_logintoken' : 'xxx' ,
'userToken' : 'xxx' ,
'req_time' : 1613274108532 ,
'waimai_sign' : '%2F' ,
'wm_longitude' : int ( pos[ 0 ] * 10 ** 6 ) ,
'wm_latitude' : int ( pos[ 1 ] * 10 ** 6 ) ,
'wm_actual_longitude' : 0 ,
'wm_actual_latitude' : 0 ,
'userid' : 'xxx' ,
'user_id' : 'xxx' ,
'uniqueid' : 'xxx' ,
'open_id' : 'xxx' ,
'openidcipher' : 'xxx' ,
'uuid' : 'xxx' ,
'rc_platform' : 13 ,
'platform' : 13 ,
'rc_app' : 0 ,
'partner' : 214 ,
'riskLevel' : 71 ,
'keyword' : keyword,
'page_index' : page,
'category_type' : 101578 ,
'entrance_id' : 101578 ,
'sort_type' : 0 ,
'search_global_id' : 'xxx' ,
'wm_ctype' : 'mt_weapp' }
res = requests. post( url, headers= headers, data= data)
res_json = res. json( )
return res_json
def parse_info ( data) :
'''
提取所需数据
'''
result = [ ]
for poi in data[ 'data' ] [ 'search_poi_list' ] :
name = poi[ 'name' ]
sales = int ( poi[ 'month_sales_tip' ] [ 2 : ] )
address = poi[ 'address' ]
lon = int ( poi[ 'longitude' ] ) / 10 ** 6
lat = int ( poi[ 'latitude' ] ) / 10 ** 6
result. append( { '商店名' : name,
'月销量' : sales,
'地址' : address,
'经度' : lon,
'纬度' : lat} )
return result
def get_lonlat ( keywords) :
'''
获取经纬度
'''
cookies = {
'cna' : '2voBF5IOjUUCAXWIWXVuwr8W' ,
'UM_distinctid' : '1767bba477b6bd-00c663bca533b3-1a347740-e1000-1767bba477c515' ,
'isg' : 'BGhoxgK9o-s-8I9R8e9xGWcsOlZ6kcybbxhnvCKZpePsfQjn1qD8K_v0cZWN1oRz' ,
'l' : 'eBOY0AmuO96VEuAdBOfalurza779_IOYYuPzaNbMiOCP_CCp5q8cWZ-AMOL9Cn1Vh6UXc37LhhQJBeYBqMIKnxvOKVLdi6Mmn' ,
'tfstk' : 'cFtVBg4K3mnq_Csdmisa5HrbndsAZ8QG8uWOoFwkl8RrRN_li2NOE50PU9UjqZf..' ,
}
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0' ,
'Accept' : '*/*' ,
'Accept-Language' : 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2' ,
'Referer' : 'https://lbs.amap.com/console/show/picker' ,
'Connection' : 'keep-alive' ,
}
params = (
( 's' , 'rsv3' ) ,
( 'children' , '' ) ,
( 'key' , 'e07ffdf58c8e8672037bef0d6cae7d4a' ) ,
( 'page' , '1' ) ,
( 'offset' , '10' ) ,
( 'city' , '110000' ) ,
( 'language' , 'zh_cn' ) ,
( 'callback' , 'jsonp_160108_' ) ,
( 'platform' , 'JS' ) ,
( 'logversion' , '2.0' ) ,
( 'sdkversion' , '1.3' ) ,
( 'appname' , 'https://lbs.amap.com/console/show/picker' ) ,
( 'csid' , '6DCF386C-8777-4724-AE49-8E688CCEF75A' ) ,
( 'keywords' , keywords) ,
)
res = requests. get( 'https://restapi.amap.com/v3/place/text' , headers= headers, params= params, cookies= cookies)
html = res. text
data = re. findall( '\((.*)\)' , html) [ 0 ]
data = json. loads( data)
location = data[ 'pois' ] [ 0 ] [ 'location' ]
lon = float ( location. split( ',' ) [ 0 ] )
lat = float ( location. split( ',' ) [ 1 ] )
return ( lon, lat)
if __name__ == '__main__' :
with open ( 'citys.txt' , 'r' ) as f:
citys = f. readlines( )
citys = [ c. strip( ) for c in citys]
savePath = './data'
if not os. path. exists( savePath) :
os. mkdir( savePath)
for city in citys:
pos = get_lonlat( city)
result = [ ]
for page in range ( 5 ) :
data = get_info( '鲜花' , pos, page)
data = parse_info( data)
result. extend( data)
print ( '"%s"第%d页爬取完成!' % ( city, page+ 1 ) )
result = pd. DataFrame( result)
result. to_csv( '%s/%s.csv' % ( savePath, city) , index= False )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
最后,我们得到了每个城市对应的玫瑰花月销量数据:
其中,每个表格的数据格式如下:
三、热力分析
有了城市玫瑰花月销量的数据之后,我们便可对其热度进行分析。这里采用了一种较简单的方式,即计算每个城市月销量的平均值,随后用pyecharts库将其以热力图的方式展示出来。代码如下:
"""
Created on Sun Feb 14 15:25:19 2021
@author: kimol_love
"""
import os
import pandas as pd
from pyecharts. charts import Geo
from pyecharts import options as opts
if __name__ == '__main__' :
savePath = './data'
sales = [ ]
for file in os. listdir( savePath) :
city = file . split( '.' ) [ 0 ]
data = pd. read_csv( '%s/%s' % ( savePath, file ) )
sale = round ( data[ '月销量' ] . mean( ) , 2 )
sales. append( ( city, sale) )
max_sale = max ( [ s[ 1 ] for s in sales] )
min_sale = max ( [ s[ 1 ] for s in sales] )
geo = Geo( init_opts= opts. InitOpts( page_title= '鲜花平均销量' ) )
geo. add_schema( maptype= 'china' , is_roam= False , selected_mode= True , label_opts= opts. LabelOpts( is_show= True ) , itemstyle_opts= opts. ItemStyleOpts( color= '#FFD5CF' , border_color= '#111' ) )
geo. add( '' , sales, type_ = 'heatmap' )
geo. set_series_opts( label_opts = opts. LabelOpts( is_show = False ) )
geo. set_global_opts( title_opts = opts. TitleOpts( title= '各城市鲜花平均销量' , subtitle= '❤️情人节快乐❤️' , pos_left= 'center' ,
title_textstyle_opts= opts. TextStyleOpts( font_size= 23 ) ,
subtitle_textstyle_opts= opts. TextStyleOpts( font_size= 15 , font_weight= 'bold' , color= '#71CFEB' ) ) ,
visualmap_opts = opts. VisualMapOpts( max_= max_sale+ 10 ) )
geo. render( path= '月销量(热力).html' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
代码轻轻一跑,便有了上文的热力图。打完,收工~
四、写在最后
本次分析数据有限,所以结论可能稍显片面,仅作为娱乐参考,如有不足还请大家多多包涵。如果有感兴趣的小伙伴,也可以尝试着从更多的维度、更细的角度进行分析哦。
最后,再次祝大家伙春节及情人节双倍快乐呀🎈~
愿大家都能在奔波凡尘中找到属于自己的栖息之地
;
愿大家都能在灿烂烟火中找到属于自己的美丽风景
。
我是kimol君,咋们下次再会~
创作不易,大侠请留步… 动起可爱的双手,来个赞再走呗 (๑◕ܫ←๑)
………………………………