用Python爬取美團(tuán)烤肉店數(shù)據(jù)并分析
回復(fù)“書籍”即可獲贈Python從入門到進(jìn)階共10本電子書

美國作家杜魯門·卡波特曾說:“夢是心靈的思想,是我們的秘密真情。”在J哥的內(nèi)心深處,也曾有一個小小的夢想,那就是開一家烤肉店。幾串烤肉、一杯美酒,即可享受深夜路邊的自由得意與平凡熱辣的市井人生。

可是,想開烤肉店可沒那么容易,首先你得了解市場。于是,J哥打開了美團(tuán),一頓操作爬取了深圳所有的烤肉店數(shù)據(jù),然后清洗數(shù)據(jù)并做可視化分析,試圖摸到一點(diǎn)開烤肉店的門道。
數(shù)據(jù)獲取
美團(tuán)網(wǎng)很明顯是動態(tài)網(wǎng)頁,需要通過解析接口或用Selenium爬取,如果您對動態(tài)網(wǎng)頁爬蟲感興趣,可查看J哥往期原創(chuàng)文章「實(shí)戰(zhàn)|Python輕松實(shí)現(xiàn)動態(tài)網(wǎng)頁爬蟲(附詳細(xì)源碼)」,本文通過解析接口的方法爬取數(shù)據(jù)。
找到真實(shí)URL
美團(tuán)網(wǎng)URL:https://sz.meituan.com/

尋找流程
分析真實(shí)URL
https://apimobile.meituan.com/group/v4/poi/pcsearch/30?uuid=你的&userid=-1&limit=32&offset=32&cateId=-1&q=%E7%83%A4%E8%82%89?
主要參數(shù):
30:城市id(30代表深圳) limit:每頁店鋪數(shù)量 offset:翻頁參數(shù)(每增加32翻頁一次) q:關(guān)鍵字(本例為烤肉)
按上述接口爬取只能獲得1024個店鋪數(shù)據(jù),為了獲得更全面數(shù)據(jù),還需找到areaId參數(shù)(子地區(qū)),然后遍歷子地區(qū),即可獲得完整數(shù)據(jù)。限于篇幅,僅給出核心代碼。
def get_meituan():
try:
for areaId in areaId_list:
for x in range(0, 2000, 32):
time.sleep(random.uniform(2,4)) #設(shè)置睡眠時(shí)間
print('正在提取areadId為%d的'%areaId,'第%d頁'%int((x+32)/32)) #打印爬取進(jìn)度
url = 'https://apimobile.meituan.com/group/v4/poi/pcsearch/30?uuid=你的&userid=-1&limit=32&offset={0}&cateId=-1&q=%E7%83%A4%E8%82%89&areaId={1}'.format(x,areaId)
print(url)
headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Cookie':'你的',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
'Host': 'apimobile.meituan.com',
'Origin': 'https://sr.meituan.com',
'Referer': 'https://sr.meituan.com/s/%E7%83%A4%E8%82%89/'
}
response = requests.get(url, headers=headers)
print(response.status_code)
數(shù)據(jù)處理
短短幾分鐘就爬下了2萬多個烤肉店信息,為了方便可視化分析,還需要對爬取的數(shù)據(jù)進(jìn)行簡單清洗。
本文數(shù)據(jù)清洗主要用到Python的Pandas庫,如果您對Pandas感興趣,可查看J哥往期原創(chuàng)專輯「Pandas基礎(chǔ)系列」,共五篇。
導(dǎo)入數(shù)據(jù)
導(dǎo)入數(shù)據(jù)并添加列名,用sample()方法隨機(jī)抽取5個樣本數(shù)據(jù)預(yù)覽。
import pandas as pd
import numpy as np
df = pd.read_csv('/Users/wangjia/Documents/技術(shù)公號/公號項(xiàng)目/2.spider/美團(tuán)/深圳烤肉1.csv',
names = ['店鋪名稱', '店鋪地址', '人均消費(fèi)', '店鋪評分', '評論人數(shù)', '所在商圈', '圖片鏈接','店鋪類型','聯(lián)系方式'])
df.sample(5)

查看數(shù)據(jù)類型
用Info()方法查看各字段數(shù)據(jù)類型,符合預(yù)期,無需轉(zhuǎn)換。
df.info()
RangeIndex: 21925 entries, 0 to 21924
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 店鋪名稱 21925 non-null object
1 店鋪地址 21925 non-null object
2 人均消費(fèi) 21925 non-null float64
3 店鋪評分 21925 non-null float64
4 評論人數(shù) 21925 non-null int64
5 所在商圈 21925 non-null object
6 圖片鏈接 21925 non-null object
7 店鋪類型 21925 non-null object
8 聯(lián)系方式 19154 non-null object
dtypes: float64(2), int64(1), object(6)
memory usage: 1.5+ MB
刪除重復(fù)數(shù)據(jù)
df = df.drop_duplicates()
缺失值處理
由上文可知,僅聯(lián)系方式字段含有缺失值,用文本填充。
df = df.fillna('暫無數(shù)據(jù)')
店鋪地址清洗
通過店鋪地址字段截取所屬區(qū)縣,另外,“南澳大”屬于龍崗區(qū),直接用replace()方法替換。
df['所屬區(qū)縣'] = df['店鋪地址'].str[:3].str.replace('南澳大','龍崗區(qū)')
店鋪評分清洗
根據(jù)美團(tuán)評分方法,對店鋪評分字段進(jìn)行切分,獲得評分類型列。
cut = lambda x : '一般' if x <= 3.5 else ('不錯' if x <= 4.0 else('好' if x <= 4.5 else '很好'))
df['評分類型'] = df['店鋪評分'].map(cut)
描述性統(tǒng)計(jì)
查看基本統(tǒng)計(jì)量
df.describe()

計(jì)算相關(guān)系數(shù)
df.corr()

繪制回歸圖
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams['font.sans-serif'] = ['SimHei'] # 設(shè)置加載的字體名
plt.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負(fù)號'-'顯示為方塊的問題
fig,axes=plt.subplots(2,1,figsize=(12,12))
sns.regplot(x='人均消費(fèi)',y='店鋪評分',data=df,color='r',marker='+',ax=axes[0])
sns.regplot(x='評論人數(shù)',y='店鋪評分',data=df,color='g',marker='*',ax=axes[1])

通過繪制回歸圖,我們發(fā)現(xiàn)人均消費(fèi)與店鋪評分具有正相關(guān),評論人數(shù)和店鋪評分具有正相關(guān)。這與我們的常識也較為接近。
數(shù)據(jù)分析
本文數(shù)據(jù)可視化主要用到pyecharts庫,它能輕松實(shí)現(xiàn)酷炫的圖表效果。如果您對可視化感興趣,可查看J哥往期原創(chuàng)文章「數(shù)據(jù)可視化分析系列」,涉及地產(chǎn)、電商、招聘等各領(lǐng)域。
地區(qū)分布
深圳烤肉店主要分布在龍崗區(qū)、龍華區(qū)、南山區(qū)和福田區(qū),鹽田區(qū)和坪山區(qū)烤肉店較少。烤肉店的選址一個重要因素就是人流量,龍崗區(qū)和龍華區(qū)為深圳主要的生活居住區(qū),而南山區(qū)和福田區(qū)為深圳的核心商業(yè)聚集地,巨大的需求為烤肉店的布局奠定了基礎(chǔ)。
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.globals import ThemeType #引入主題
df1 = df.groupby('所屬區(qū)縣')['店鋪名稱'].count() #按所屬區(qū)縣分組,對店鋪名稱計(jì)數(shù)
df1 = df1.sort_values(ascending=False) #降序
regions = df1.index.to_list()
values = df1.to_list()
c = (
Map(init_opts=opts.InitOpts(theme = ThemeType.WONDERLAND)) #PURPLE_PASSION
.add(
"",
zip(regions, values),
maptype="深圳"
)
.set_global_opts(
title_opts=opts.TitleOpts(title="深圳烤肉店分布",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_top="-1%", pos_left = 'center' ),
visualmap_opts=opts.VisualMapOpts(max_=1000)
)
)
c.render_notebook()

所在商圈
僅僅知道烤肉店行政區(qū)分布,對于烤肉店選址作用其實(shí)不大。于是,我們進(jìn)一步細(xì)化到商圈,看看哪些商圈的烤肉店較多。在深圳所有商圈中,龍華區(qū)的民治和龍華、光明區(qū)的公明烤肉店數(shù)量都超過了150家。
df2 = df.groupby('所在商圈')['店鋪名稱'].count()
df2 = df2.sort_values(ascending=True)[-10:]
df2 = df2.round(2)
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(df2.index.to_list())
.add_yaxis("",df2.to_list()).reversal_axis() #X軸與y軸調(diào)換順序
.set_global_opts(title_opts=opts.TitleOpts(title="商圈烤肉店數(shù)量top10",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_left = 'center'),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫坐標(biāo)字體大小
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱坐標(biāo)字體大小
)
.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
)
c.render_notebook()

評分排行
烤肉店的評分在一定程度上反映了消費(fèi)者對烤肉店的態(tài)度和看法。通過計(jì)算各個行政區(qū)烤肉店平均評分,我們發(fā)現(xiàn),深圳烤肉店普遍評分不高,都在3分以下,且各地區(qū)評分差異不大。
df3 = df.groupby('所屬區(qū)縣')['店鋪評分'].mean()
df3 = df3.sort_values(ascending=False)
df3 = df3.round(2)
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(df3.index.to_list())
.add_yaxis("",df3.to_list())
.set_global_opts(title_opts=opts.TitleOpts(title="各地區(qū)平均評分",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_left = 'center'),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫坐標(biāo)字體大小
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱坐標(biāo)字體大小
)
.set_series_opts(label_opts=opts.LabelOpts(font_size=16))
)
c.render_notebook()

評分類型
根據(jù)不同評分類型繪制餅圖,我們發(fā)現(xiàn)深圳評分為“一般”的烤肉店數(shù)量占比高達(dá)73.9%。評分類型為“不錯”的烤肉店僅占6.52%。烤肉店較低的評分意味著,作為市場的進(jìn)入者,如果新開烤肉店能夠提供較好的質(zhì)量和服務(wù),且獲得消費(fèi)者好評,將比較容易在眾多烤肉店中脫穎而出。
df4 = df.groupby('評分類型')['店鋪名稱'].count()
df4 = df4.sort_values(ascending=False)
regions = df4.index.to_list()
values = df4.to_list()
c = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add("", zip(regions,values))
.set_global_opts(title_opts=opts.TitleOpts(title="不同評分類型店鋪數(shù)量",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_top="-1%",pos_left = 'center'))
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:go7utgvlrp%",font_size=18))
)
c.render_notebook()

我們繼續(xù)將評分類型分析細(xì)化到深圳的各個行政區(qū),羅湖區(qū)評分為“一般”的烤肉店占比相對低一些。其他地區(qū)占比都超過了一半。這進(jìn)一步反映了深圳烤肉店評分的整體情況,排除了某個或某幾個行政區(qū)評分異常值的影響。
h = pd.pivot_table(df,index=['評分類型'],values=['店鋪名稱'],
columns=['所屬區(qū)縣'],aggfunc=['count'])
k = h.droplevel([0,1],axis=1) #刪除指定的索引/列級別
c = (
Polar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_schema(angleaxis_opts=opts.AngleAxisOpts(data=k.columns.tolist(), type_="category"))
.add("一般",h.values.tolist()[0], type_="bar", stack="stack0")
.add("不錯",h.values.tolist()[1], type_="bar", stack="stack0")
.add("好", h.values.tolist()[2], type_="bar", stack="stack0")
.add("很好", h.values.tolist()[3], type_="bar", stack="stack0")
.set_global_opts(title_opts=opts.TitleOpts(title="不同地區(qū)評分情況",subtitle="數(shù)據(jù)來源:美團(tuán)"))
)
c.render_notebook()

人均消費(fèi)
從深圳各行政區(qū)烤肉店人均消費(fèi)來看,南山區(qū)和福田區(qū)人均消費(fèi)較高,坪山區(qū)和光明區(qū)人均消費(fèi)較低。在消費(fèi)量一致的假設(shè)下,人均消費(fèi)的多少取決于烤肉的價(jià)格。南山區(qū)和福田區(qū)高昂的開店成本以及消費(fèi)者較強(qiáng)的消費(fèi)能力,是烤肉人均消費(fèi)較高的重要動因。
df5 = df.groupby('所屬區(qū)縣')['人均消費(fèi)'].mean()
df5 = df5.sort_values(ascending=True)
df5 = df5.round(2)
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(df5.index.to_list())
.add_yaxis("",df5.to_list()).reversal_axis() #X軸與y軸調(diào)換順序
.set_global_opts(title_opts=opts.TitleOpts(title="各地區(qū)人均消費(fèi)",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_left = 'center'),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫坐標(biāo)字體大小
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱坐標(biāo)字體大小
)
.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
)
c.render_notebook()

由上圖可知,深圳各行政區(qū)烤肉人均消費(fèi)普遍低于50元,那是不是意味著如果要開烤肉店的話,定價(jià)不能太高。為此,我們可以篩選出人均消費(fèi)大于1000元的烤肉店,看下消費(fèi)者的評價(jià)情況。由下表可知,雖然三家烤肉店定價(jià)很高,卻獲得了消費(fèi)者較高的評價(jià)。因此,烤肉的定價(jià)還需根據(jù)你的市場定位來,如果定位高端人群,那么較高的價(jià)格消費(fèi)者也是可以接受的。
df_1 = df[df['人均消費(fèi)']>1000]
df_1[['店鋪名稱','人均消費(fèi)','評分類型','所在商圈']]

店鋪類型
從深圳烤肉店店鋪類型來看,烤串、燒烤和融合烤肉最多,韓式烤肉、日式烤肉等店鋪相對更少一些。
df6 = df.groupby('店鋪類型')['店鋪名稱'].count()
df6 = df6.sort_values(ascending=False)[:10]
df6 = df6.round(2)
regions = df6.index.to_list()
values = df6.to_list()
c = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add("", zip(regions,values),radius=["40%", "75%"])
.set_global_opts(title_opts=opts.TitleOpts(title="不同店鋪類型店鋪數(shù)量",pos_top="-1%",pos_left = 'center'))
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}",font_size=18))
)
c.render_notebook()

從評分來看,串串香、牛排和懷石料理的烤肉評分較高。另外,日式自助烤肉評分也排到了前十名,日式烤肉對肉要求比較高,日式肉類也會稍微腌制,但是總體以體現(xiàn)肉的鮮美為主。精致的日式烤肉,博得了眾多深圳消費(fèi)者的青睞。
df6 = df.groupby('店鋪類型')['店鋪評分'].mean()
df6 = df6.sort_values(ascending=True)
df6 = df6.round(2)
df6 = df6.tail(10)
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(df6.index.to_list())
.add_yaxis("",df6.to_list()).reversal_axis() #X軸與y軸調(diào)換順序
.set_global_opts(title_opts=opts.TitleOpts(title="不同店鋪類型評分",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_left = 'center'),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫坐標(biāo)字體大小
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱坐標(biāo)字體大小
)
.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
)
c.render_notebook()

評論人數(shù)
從評論人數(shù)來看,綜合自助和韓式烤肉店評論人數(shù)均在10萬左右,而評論人數(shù)在一定程度上反映了烤肉店的熱度。不同的綜合自助烤肉店一般價(jià)格和肉質(zhì)差異較大,獲得較多的評論也不足為奇。而韓式烤肉通常會對肉類進(jìn)行腌制,口感偏重,也被深圳消費(fèi)者廣泛討論。
df7 = df.groupby('店鋪類型')['評論人數(shù)'].sum()
df7 = df7.sort_values(ascending=True)
df7 = df7.tail(10)
c = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.WONDERLAND))
.add_xaxis(df7.index.to_list())
.add_yaxis("",df7.to_list()).reversal_axis() #X軸與y軸調(diào)換順序
.set_global_opts(title_opts=opts.TitleOpts(title="不同店鋪類型評論人數(shù)",subtitle="數(shù)據(jù)來源:美團(tuán)",pos_left = 'center'),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫坐標(biāo)字體大小
yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱坐標(biāo)字體大小
)
.set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
)
c.render_notebook()

店鋪取名
當(dāng)然,開烤肉店除了要了解消費(fèi)者的偏好以及競爭對手的優(yōu)劣勢,還一個重要步驟就是給自己開的烤肉店取名了。一個響亮的烤肉店名字,能夠給消費(fèi)者留下較深的記憶度,同時(shí)也能帶來品牌效應(yīng)。于是,J哥對深圳所有烤肉店名進(jìn)行分詞并繪制了詞云圖,發(fā)現(xiàn)除了燒烤、烤肉等字樣,詞頻較高的還有音樂、木屋和炭火等。差異化市場定位,給烤肉搭配多樣化的元素,在店名中凸顯出來,不失為一個不錯的選擇。
import jieba
import stylecloud
from IPython.display import Image
# 定義分詞函數(shù)
def get_cut_words(content_series):
# 讀入停用詞表
stop_words = []
with open("./stop_words.txt", 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
stop_words.append(line.strip())
# 添加關(guān)鍵詞
my_words = ['', '']
for i in my_words:
jieba.add_word(i)
# 自定義停用詞
my_stop_words = ['東北', '福田','公園','車公廟','梅林','購物']
stop_words.extend(my_stop_words)
# 分詞
word_num = jieba.lcut(content_series.str.cat(sep='。'), cut_all=False)
# 條件篩選
word_num_selected = [i for i in word_num if i not in stop_words and len(i)>=2]
return word_num_selected
# 繪制詞云圖
text1 = get_cut_words(content_series=df['店鋪名稱'])
stylecloud.gen_stylecloud(text=' '.join(text1), max_words=1000,
collocations=False,
font_path='字酷堂清楷體.ttf',
icon_name='fas fa-shopping-bag',
size=653,
output_name='./烤肉.png')
Image(filename='./烤肉.png')

聲明
1.本數(shù)據(jù)分析只做學(xué)習(xí)研究之用途,提供的結(jié)論僅供參考,烤肉店的開設(shè)涉及的影響因素還有很多,請獨(dú)立思考;
2.作者與美團(tuán)無任何瓜葛,只是他家數(shù)據(jù)比較全面且干凈,便于數(shù)據(jù)分析,大家也可以去其他美食平臺看看;
3.作者對烤肉了解甚微,相關(guān)描述可能存在不盡完善之處,請勿對號入座。
-------------------?End?-------------------
往期精彩文章推薦:
手把手用Python教你如何發(fā)現(xiàn)隱藏wifi
手把手教你用Python做個可視化的“剪刀石頭布”小游戲
Python基礎(chǔ)語法——代碼規(guī)范&判斷語句&循環(huán)語句

歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持
想加入Python學(xué)習(xí)群請?jiān)诤笈_回復(fù)【入群】
萬水千山總是情,點(diǎn)個【在看】行不行
/今日留言主題/
隨便說一兩句吧~~
