1. 程式人生 > 實用技巧 >爬取美團1024家烤肉店資料,看看為什麼那麼多人喜歡吃,祕訣在哪

爬取美團1024家烤肉店資料,看看為什麼那麼多人喜歡吃,祕訣在哪

前言

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

可是,想開烤肉店可沒那麼容易,首先你得了解市場。於是,打開了美團,一頓操作爬取了深圳所有的烤肉店資料,然後清洗資料並做視覺化分析,試圖摸到一點開烤肉店的門道。

PS:如有需要Python學習資料的小夥伴可以加下方的群去找免費管理員領取

可以免費領取原始碼、專案實戰視訊、PDF檔案等

資料獲取

美團網很明顯是動態網頁,需要通過解析介面或用Selenium爬取

美團網URL:

https://sz.meituan.com/

分析真實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 

主要引數:

  1. 30:城市id(30代表深圳)
  2. limit:每頁店鋪數量
  3. offset:翻頁引數(每增加32翻頁一次)
  4. q:關鍵字(本例為烤肉)

按上述介面爬取只能獲得1024個店鋪資料,為了獲得更全面資料,還需找到areaId引數(子地區),然後遍歷子地區,即可獲得完整資料。限於篇幅,僅給出核心程式碼。

def get_meituan():
    try:
        for areaId in areaId_list:
           for x in range(0, 2000, 32):
                time.sleep(random.uniform(2,4)) #設定睡眠時間
                print('正在提取areadId為%d的'%areaId,'第%d頁'%int((x+32)/32))  #列印爬取進度
                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)

資料處理

短短几分鐘就爬下了2萬多個烤肉店資訊,為了方便視覺化分析,還需要對爬取的資料進行簡單清洗。

匯入資料

匯入資料並新增列名,用sample()方法隨機抽取5個樣本資料預覽。

import pandas as pd
import numpy as np
df = pd.read_csv('/Users/wangjia/Documents/技術公號/公號專案/2.spider/美團/深圳烤肉1.csv',
                names = ['店鋪名稱', '店鋪地址', '人均消費', '店鋪評分', '評論人數', '所在商圈', '圖片連結','店鋪型別','聯絡方式'])
df.sample(5)

檢視資料型別

用Info()方法檢視各欄位資料型別,符合預期,無需轉換。

df.info()

刪除重複資料

df = df.drop_duplicates()

缺失值處理

由上文可知,僅聯絡方式欄位含有缺失值,用文字填充。

df = df.fillna('暫無資料')

店鋪地址清洗

通過店鋪地址欄位擷取所屬區縣,另外,“南澳大”屬於龍崗區,直接用replace()方法替換。

df['所屬區縣'] = df['店鋪地址'].str[:3].str.replace('南澳大','龍崗區')

店鋪評分清洗

根據美團評分方法,對店鋪評分欄位進行切分,獲得評分型別列。

cut = lambda x : '一般' if x <= 3.5 else ('不錯' if x <= 4.0 else('' if x <= 4.5 else '很好'))
df['評分型別'] = df['店鋪評分'].map(cut)

描述性統計

檢視基本統計量

df.describe()

計算相關係數

df.corr()

繪製迴歸圖

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams['font.sans-serif'] = ['SimHei']  # 設定載入的字型名
plt.rcParams['axes.unicode_minus'] = False   # 解決儲存影象是負號'-'顯示為方塊的問題
fig,axes=plt.subplots(2,1,figsize=(12,12))
sns.regplot(x='人均消費',y='店鋪評分',data=df,color='r',marker='+',ax=axes[0])
sns.regplot(x='評論人數',y='店鋪評分',data=df,color='g',marker='*',ax=axes[1])

通過繪製迴歸圖,我們發現人均消費與店鋪評分具有正相關,評論人數和店鋪評分具有正相關。這與我們的常識也較為接近。

資料分析

本文資料視覺化主要用到pyecharts庫,它能輕鬆實現酷炫的圖表效果。

地區分佈

深圳烤肉店主要分佈在龍崗區、龍華區、南山區和福田區,鹽田區和坪山區烤肉店較少。烤肉店的選址一個重要因素就是人流量,龍崗區和龍華區為深圳主要的生活居住區,而南山區和福田區為深圳的核心商業聚集地,巨大的需求為烤肉店的佈局奠定了基礎。

from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.globals import ThemeType  #引入主題
df1 = df.groupby('所屬區縣')['店鋪名稱'].count() #按所屬區縣分組,對店鋪名稱計數
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="資料來源:美團",pos_top="-1%", pos_left = 'center' ),
        visualmap_opts=opts.VisualMapOpts(max_=1000)
    )
    )
c.render_notebook()

所在商圈

僅僅知道烤肉店行政區分佈,對於烤肉店選址作用其實不大。於是,我們進一步細化到商圈,看看哪些商圈的烤肉店較多。在深圳所有商圈中,龍華區的民治和龍華、光明區的公明烤肉店數量都超過了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軸調換順序
    .set_global_opts(title_opts=opts.TitleOpts(title="商圈烤肉店數量top10",subtitle="資料來源:美團",pos_left = 'center'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫座標字型大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱座標字型大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
    )
c.render_notebook()

評分排行

烤肉店的評分在一定程度上反映了消費者對烤肉店的態度和看法。通過計算各個行政區烤肉店平均評分,我們發現,深圳烤肉店普遍評分不高,都在3分以下,且各地區評分差異不大。

df3 = df.groupby('所屬區縣')['店鋪評分'].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="各地區平均評分",subtitle="資料來源:美團",pos_left = 'center'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫座標字型大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱座標字型大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16))
    )
c.render_notebook()

評分型別

根據不同評分型別繪製餅圖,我們發現深圳評分為“一般”的烤肉店數量佔比高達73.9%。評分型別為“不錯”的烤肉店僅佔6.52%。烤肉店較低的評分意味著,作為市場的進入者,如果新開烤肉店能夠提供較好的質量和服務,且獲得消費者好評,將比較容易在眾多烤肉店中脫穎而出。

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="不同評分型別店鋪數量",subtitle="資料來源:美團",pos_top="-1%",pos_left = 'center'))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}:{d}%",font_size=18))
    )
c.render_notebook()

我們繼續將評分型別分析細化到深圳的各個行政區,羅湖區評分為“一般”的烤肉店佔比相對低一些。其他地區佔比都超過了一半。這進一步反映了深圳烤肉店評分的整體情況,排除了某個或某幾個行政區評分異常值的影響。

h = pd.pivot_table(df,index=['評分型別'],values=['店鋪名稱'],
               columns=['所屬區縣'],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="不同地區評分情況",subtitle="資料來源:美團"))

)
c.render_notebook()

人均消費

從深圳各行政區烤肉店人均消費來看,南山區和福田區人均消費較高,坪山區和光明區人均消費較低。在消費量一致的假設下,人均消費的多少取決於烤肉的價格。南山區和福田區高昂的開店成本以及消費者較強的消費能力,是烤肉人均消費較高的重要動因。

df5 = df.groupby('所屬區縣')['人均消費'].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軸調換順序
    .set_global_opts(title_opts=opts.TitleOpts(title="各地區人均消費",subtitle="資料來源:美團",pos_left = 'center'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫座標字型大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱座標字型大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
    )
c.render_notebook()

由上圖可知,深圳各行政區烤肉人均消費普遍低於50元,那是不是意味著如果要開烤肉店的話,定價不能太高。為此,我們可以篩選出人均消費大於1000元的烤肉店,看下消費者的評價情況。由下表可知,雖然三家烤肉店定價很高,卻獲得了消費者較高的評價。因此,烤肉的定價還需根據你的市場定位來,如果定位高階人群,那麼較高的價格消費者也是可以接受的。

df_1 = df[df['人均消費']>1000]
df_1[['店鋪名稱','人均消費','評分型別','所在商圈']]

店鋪型別

從深圳烤肉店店鋪型別來看,烤串、燒烤和融合烤肉最多,韓式烤肉、日式烤肉等店鋪相對更少一些。

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="不同店鋪型別店鋪數量",pos_top="-1%",pos_left = 'center'))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}",font_size=18))
    )
c.render_notebook()

從評分來看,串串香、牛排和懷石料理的烤肉評分較高。另外,日式自助烤肉評分也排到了前十名,日式烤肉對肉要求比較高,日式肉類也會稍微醃製,但是總體以體現肉的鮮美為主。精緻的日式烤肉,博得了眾多深圳消費者的青睞。

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軸調換順序
    .set_global_opts(title_opts=opts.TitleOpts(title="不同店鋪型別評分",subtitle="資料來源:美團",pos_left = 'center'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫座標字型大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱座標字型大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
    )
c.render_notebook()

評論人數

從評論人數來看,綜合自助和韓式烤肉店評論人數均在10萬左右,而評論人數在一定程度上反映了烤肉店的熱度。不同的綜合自助烤肉店一般價格和肉質差異較大,獲得較多的評論也不足為奇。而韓式烤肉通常會對肉類進行醃製,口感偏重,也被深圳消費者廣泛討論。

df7 = df.groupby('店鋪型別')['評論人數'].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軸調換順序
    .set_global_opts(title_opts=opts.TitleOpts(title="不同店鋪型別評論人數",subtitle="資料來源:美團",pos_left = 'center'),
                       xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改橫座標字型大小
                       yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=16)), #更改縱座標字型大小
                       )
    .set_series_opts(label_opts=opts.LabelOpts(font_size=16,position='right'))
    )
c.render_notebook()

店鋪取名

當然,開烤肉店除了要了解消費者的偏好以及競爭對手的優劣勢,還一個重要步驟就是給自己開的烤肉店取名了。一個響亮的烤肉店名字,能夠給消費者留下較深的記憶度,同時也能帶來品牌效應。於是,J哥對深圳所有烤肉店名進行分詞並繪製了詞雲圖,發現除了燒烤、烤肉等字樣,詞頻較高的還有音樂、木屋和炭火等。差異化市場定位,給烤肉搭配多樣化的元素,在店名中凸顯出來,不失為一個不錯的選擇。

import jieba
import stylecloud
from IPython.display import Image
# 定義分詞函式
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())

    # 新增關鍵詞
    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')

本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯絡我們以作處理。

以上文章來源於菜J學Python ,作者J哥