李佳琪為湖北帶貨,Python分析全網(wǎng)哪家熱干面最暢銷(xiāo)!
作者:Mika數(shù)據(jù):真達(dá)??后期:澤龍?
來(lái)源 :CDA數(shù)據(jù)分析師
Show me data,用數(shù)據(jù)說(shuō)話(huà)
今天我們聊聊 熱干面
點(diǎn)擊下方視頻,先睹為快:
面條在滾水里汆燙,起鍋盛入碗中,淋上事先調(diào)制好的濃稠麻醬,加上醬油、辣椒油、蔥花,再配上新鮮的酸豆角和蘿卜丁,一碗傳統(tǒng)的熱干面就做好了。剛端上桌的面條,冒著熱氣,拿筷子一攪拌,香氣隨著四溢開(kāi)來(lái),充滿(mǎn)了一股人間煙火的味道。
?
4月8日零時(shí)起,在封城76天后,武漢與外界的通道重新開(kāi)啟。

伴隨著復(fù)工復(fù)產(chǎn)的有序進(jìn)行,一碗碗熱氣騰騰、醬香彈牙的熱干面也回來(lái)了。
?
01
瞬間被搶購(gòu)一空的
熱干面
4月6日晚, 在為湖北帶貨的直播中,央視主持人“段子手”朱廣權(quán)與“帶貨一哥”李佳琦,在歷時(shí)兩個(gè)小時(shí)的直播中,累計(jì)賣(mài)出了 4014萬(wàn) 的湖北商品!其中熱干面等湖北產(chǎn)品更是賣(mài)瘋了,上架僅僅幾分鐘都被搶購(gòu)一空。

?
那么都是誰(shuí)家賣(mài)的熱干面最火,最好吃?吃貨們都怎么看?我們搜集整理了淘寶上關(guān)于熱干面店鋪的數(shù)據(jù),今年就教你,怎么用Python來(lái)爬取和分析。
02
?全網(wǎng)熱干面銷(xiāo)售情況
首先我們來(lái)看到結(jié)論,具體的代碼實(shí)現(xiàn)本文請(qǐng)看第三部分。
店鋪銷(xiāo)量排行
?

在熱干面店鋪銷(xiāo)量數(shù)據(jù)可以看到:
蔡林記旗艦店拔得頭籌,以月銷(xiāo)量28萬(wàn)+遙遙領(lǐng)先。其次天貓超市的銷(xiāo)量也不少,以17萬(wàn)+位居第二。之后是阿寬旗艦店和韓太旗艦店,月銷(xiāo)量都在10萬(wàn)+左右。值得注意的是,李子柒家的熱干面銷(xiāo)量也不錯(cuò),在top10店鋪中占據(jù)一席之地。
?
各省店鋪銷(xiāo)量排行

再看到熱干面銷(xiāo)售最多的店鋪省份,作為熱干面的發(fā)源地,湖北當(dāng)仁不讓位居第一。其次是上海、四川分別位居第二和第三。
?

?
熱干面都賣(mài)多少錢(qián)呢?

我們分析了淘寶上銷(xiāo)售熱干面的價(jià)格區(qū)間,一份熱干面一般有5-6包左右。其中定價(jià)在20-50元一份的產(chǎn)品最多,也是全網(wǎng)銷(xiāo)量最好的,占比達(dá)到58.37%。緊接著0-20元價(jià)格區(qū)間的熱干面產(chǎn)品占比第二,在全網(wǎng)銷(xiāo)量占比為35.29%。
?

買(mǎi)熱干面,大家都看重什么?

看到熱干面的評(píng)論詞云,我們發(fā)現(xiàn):
在購(gòu)買(mǎi)熱干面時(shí),大家評(píng)論時(shí)對(duì)口味特別看重,“芝麻醬”“調(diào)料”“花生醬”口味是否“正宗”等都是關(guān)注的焦點(diǎn)。
?
此外,熱干面在制作上是否方便也是大家關(guān)注的重點(diǎn),“速食”“免煮”也是吃貨們常常提到的詞。
?
同時(shí),“包郵”也是很關(guān)鍵的。對(duì)于消費(fèi)者們來(lái)說(shuō),商品是否包郵在選擇購(gòu)買(mǎi)方面占了很大的比重。
03
?用Python 分析?
誰(shuí)家的熱干面買(mǎi)的最火
那么如何用Python來(lái)獲取這些數(shù)據(jù)的呢?
??
我們搜集整理了淘寶網(wǎng)關(guān)于熱干面的100頁(yè)商品數(shù)據(jù),使用Python進(jìn)行整理分析。整個(gè)數(shù)據(jù)分析的過(guò)程分為以下三步:
數(shù)據(jù)獲取
數(shù)據(jù)清洗
數(shù)據(jù)可視化
1.? 數(shù)據(jù)獲取
使用selenium抓取淘寶商品
首先確定爬蟲(chóng)的策略,淘寶的商品頁(yè)面數(shù)據(jù)是通過(guò)Ajax加載的,但是這些Ajax接口和參數(shù)比較復(fù)雜,可能會(huì)包含加密秘鑰等,所以想要自己分析Ajax并構(gòu)造參數(shù),還是比較困難的。對(duì)于這種頁(yè)面,最方便快捷的方法就是通過(guò)Selenium。
因此,在此次項(xiàng)目項(xiàng)目中,我們利用selenium抓取淘寶商品并使用Xpath解析得到商品的名稱(chēng)、價(jià)格、購(gòu)買(mǎi)人數(shù)、店鋪名稱(chēng)、和店鋪所在地的信息,并將數(shù)據(jù)保存在本地。具體爬蟲(chóng)思路如下:
代碼實(shí)現(xiàn):
#?導(dǎo)入所需包
import?pandas?as?pd
import?re
import?parsel
import?time
from?selenium?import?webdriver
from?selenium.common.exceptions?import?TimeoutException
from?selenium.webdriver.common.by?import?By
from?selenium.webdriver.support.ui?import?WebDriverWait
from?selenium.webdriver.support?import?expected_conditions?as?EC
#?打開(kāi)瀏覽器
browser?=?webdriver.Chrome()
wait?=?WebDriverWait(browser,?10)
#?定義函數(shù)登錄淘寶
def?login_taobao_acount():
????#?登錄URL
????login_url?=?'https://login.taobao.com/member/login.jhtml'
????#?打開(kāi)網(wǎng)頁(yè)
????browser.get(login_url)
????#?支付寶登錄
????log?=?wait.until(
????????EC.element_to_be_clickable((By.CSS_SELECTOR,?'#login-form?>?div.login-blocks.sns-login-links?>?a.alipay-login'))
????)
????log.click()
#?定義函數(shù)搜索商品
def?search(key_word):
????try:
????????browser.get('https://www.taobao.com')
????????input?=?wait.until(
????????????EC.presence_of_element_located((By.CSS_SELECTOR,?'#q'))
????????)
????????submit?=?wait.until(
????????????EC.element_to_be_clickable((By.CSS_SELECTOR,?'#J_TSearchForm?>?div.search-button?>?button')))
????????input.send_keys(key_word)
????????submit.click()
????????total?=?wait.until(
????????????EC.presence_of_element_located((By.CSS_SELECTOR,?'#mainsrp-pager?>?div?>?div?>?div?>?div.total')))
????????return?total.text
????except?TimeoutException:
????????return?search(key_word)
#?定義函數(shù)獲取單頁(yè)的商品信息
def?get_products():
????wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,?'#mainsrp-itemlist?.items?.item')))
????#?解析數(shù)據(jù)
????html?=?parsel.Selector(browser.page_source)
????#?獲取數(shù)據(jù)
????goods_name?=?html.xpath('//div[@class="grid?g-clearfix"]//img/@alt').extract()
????shop_name?=?html.xpath('//div[@class="grid?g-clearfix"]//div[@class="shop"]/a/span[2]/text()').extract()
????price?=?html.xpath('//div[@class="grid?g-clearfix"]//div[contains(@class,"price")]/strong/text()').extract()
????purchase_num?=?[re.findall(r'(.*?)',?i)
????????????????????for?i?in?html.xpath('//div[@class="grid?g-clearfix"]//div[@class="row?row-1?g-clearfix"]').extract()]
????location?=?html.xpath('//div[@class="grid?g-clearfix"]//div[@class="location"]/text()').extract()
????#?存儲(chǔ)數(shù)據(jù)
????df_one?=?pd.DataFrame({
????????'goods_name':?goods_name,
????????'shop_name':?shop_name,
????????'price':?price,
????????'purchase_num':?purchase_num,
????????'location':?location
????})
????return?df_one
#?定義函數(shù)進(jìn)行翻頁(yè)
def?next_page(page_number):
????print('正在翻頁(yè)',?page_number)
????try:
????????input?=?wait.until(
????????????EC.presence_of_element_located((By.CSS_SELECTOR,?'#mainsrp-pager?>?div?>?div?>?div?>?div.form?>?input'))
????????)
????????submit?=?wait.until(EC.element_to_be_clickable(
????????????(By.CSS_SELECTOR,?'#mainsrp-pager?>?div?>?div?>?div?>?div.form?>?span.btn.J_Submit')))
????????input.clear()
????????input.send_keys(page_number)
????????submit.click()
????????wait.until(EC.text_to_be_present_in_element(
????????????(By.CSS_SELECTOR,?'#mainsrp-pager?>?div?>?div?>?div?>?ul?>?li.item.active?>?span'),?str(page_number)))
????????#?運(yùn)行函數(shù)
????????df_product?=?get_products()
????except?TimeoutException:
????????next_page(page_number)
????return?df_product
#?獲取所有頁(yè)信息
def?main():
????try:
????????total?=?search(key_word='熱干面')
????????total?=?int(re.compile('(\d+)').search(total).group(1))
????????#?存儲(chǔ)數(shù)據(jù)
????????df_all?=?pd.DataFrame()
????????for?i?in?range(1,?total?+?1):
????????????df_one?=?next_page(i)
????????????df_all?=?df_all.append(df_one,?ignore_index=True)
????????????#?打印進(jìn)度
????????????print('我正在獲取第{}頁(yè)的數(shù)據(jù)'.format(i))
????????????time.sleep(3)
????except?Exception:
????????print('出錯(cuò)啦')
????finally:
????????browser.close()
????return?df_all
#?從此處運(yùn)行
if?__name__?==?'__main__':
????#?登錄
????login_taobao_acount()
????time.sleep(10)
????df_all?=?main()
#?保存數(shù)據(jù)
df_all.to_excel('熱干面數(shù)據(jù).xlsx',?index=False)
爬取出來(lái)的數(shù)據(jù)以數(shù)據(jù)框的形式存儲(chǔ),結(jié)果如下圖所示。
df_all.head()?

查看一下數(shù)據(jù)框的大小,可以看到一共有4404個(gè)樣本。
df_all.shape
(4404,?5)
2. 數(shù)據(jù)探索和數(shù)據(jù)清洗
此處我們對(duì)數(shù)據(jù)進(jìn)行以下的處理以方便后續(xù)的數(shù)據(jù)分析和可視化工作:
去除重復(fù)數(shù)據(jù)
去除購(gòu)買(mǎi)人數(shù)為空的記錄
類(lèi)型轉(zhuǎn)換:將購(gòu)買(mǎi)人數(shù)轉(zhuǎn)換為數(shù)值型數(shù)據(jù)
字段擴(kuò)充:增加收入列,價(jià)格*購(gòu)買(mǎi)人數(shù)=收入
字段擴(kuò)充:增加商品價(jià)格分箱數(shù)據(jù)
提取省份名稱(chēng)字段。
對(duì)商品名稱(chēng)進(jìn)行分詞處理。
代碼實(shí)現(xiàn):
#?讀入數(shù)據(jù)
df_all?=?pd.read_excel('熱干面數(shù)據(jù).xlsx')?
df?=?df_all.copy()
#?去除重復(fù)值
df.drop_duplicates(inplace=True)
#?刪除購(gòu)買(mǎi)人數(shù)為空的記錄
df?=?df[df['purchase_num'].str.contains('人付款')]
#?提取數(shù)值
df['num']?=?[re.findall(r'(\d+\.{0,1}\d*)',?i)[0]?for?i?in?df['purchase_num']]??#?提取數(shù)值
df['num']?=?df['num'].astype('float')??#?轉(zhuǎn)化數(shù)值型
#?提取單位
df['unit']?=?[''.join(re.findall(r'(萬(wàn))',?i))?for?i?in?df['purchase_num']]??#?提取單位
df['unit']?=?df['unit'].apply(lambda?x:10000?if?x=='萬(wàn)'?else?1)
#?計(jì)算真實(shí)金額
df['purchase_num']?=?df['num']?*?df['unit']
#?提取省份
df['province_name']?=?df['location'].str.split('?').apply(lambda?x:x[0])
#?刪除多余的列
df.drop(['num',?'unit'],?axis=1,?inplace=True)
#?重置索引
df?=?df.reset_index(drop=True)
df.head()?

#?分詞
import?jieba
import?jieba.analyse
txt?=?df['goods_name'].str.cat(sep='。')
#?添加關(guān)鍵詞
jieba.add_word('熱干面')?
#?讀入停用詞表
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())
#?添加停用詞
stop_words.extend(['10',?'12',?'20',?'200g',?'500g',?'900g',?'300g'])??
#?評(píng)論字段分詞處理
word_num?=?jieba.analyse.extract_tags(txt,
??????????????????????????????????????topK=100,
??????????????????????????????????????withWeight=True,
??????????????????????????????????????allowPOS=())
#?去停用詞
word_num_selected?=?[]
for?i?in?word_num:
????if?i[0]?not?in?stop_words:
????????word_num_selected.append(i)
key_words?=?pd.DataFrame(word_num_selected,?columns=['words','num'])
3. 數(shù)據(jù)分析和可視化
此處我們使用pyecharts進(jìn)行動(dòng)態(tài)數(shù)據(jù)可視化展示。我們主要對(duì)以下幾個(gè)方面信息進(jìn)行分析。
- 店鋪銷(xiāo)量排名Top10,看看哪些店鋪銷(xiāo)量高。
- 各省份店鋪數(shù)量排名Top10,看看銷(xiāo)量最高的熱干面都來(lái)自哪里。
- 全國(guó)省份銷(xiāo)量地區(qū)分布
- 商品標(biāo)題文本分析,看看熱干面搜索的結(jié)果頁(yè)面,哪種種類(lèi)關(guān)鍵詞出現(xiàn)的比較多。
- 商品價(jià)格分布和各價(jià)格區(qū)間的銷(xiāo)量表現(xiàn)。
店鋪銷(xiāo)量排名top10 - 柱形圖

代碼實(shí)現(xiàn):
#?導(dǎo)入包
from?pyecharts.charts?import?Bar
from?pyecharts?import?options?as?opts?
#?計(jì)算top10店鋪
shop_top10?=?df.groupby('shop_name')['purchase_num'].sum().sort_values(ascending=False).head(10)
#?繪制柱形圖
bar1?=?Bar(init_opts=opts.InitOpts(width='1350px',?height='750px'))?
bar1.add_xaxis(shop_top10.index.tolist())
bar1.add_yaxis('sales_num',?shop_top10.values.tolist())?
bar1.set_global_opts(title_opts=opts.TitleOpts(title='熱干面店鋪商品銷(xiāo)量Top10'),
?????????????????????xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)),
?????????????????????visualmap_opts=opts.VisualMapOpts(max_=shop_top10.values.max()))?
bar1.render()?
全國(guó)各省份銷(xiāo)量排名Top10 - 柱形圖

代碼實(shí)現(xiàn):
#?計(jì)算銷(xiāo)量top10
province_top10?=?df.groupby('province_name')['purchase_num'].sum().sort_values(ascending=False).head(10)
#?條形圖
bar2?=?Bar(init_opts=opts.InitOpts(width='1350px',?height='750px'))?
bar2.add_xaxis(province_top10.index.tolist())
bar2.add_yaxis('sales_num',?province_top10.values.tolist())?
bar2.set_global_opts(title_opts=opts.TitleOpts(title='熱干面商品銷(xiāo)量省份排名Top10'),
?????????????????????visualmap_opts=opts.VisualMapOpts(max_=province_top10.values.max()))?
bar2.render()?
全國(guó)省份銷(xiāo)量地區(qū)分布-地圖

代碼實(shí)現(xiàn):
from?pyecharts.charts?import?Map?
#?計(jì)算銷(xiāo)量
province_num?=?df.groupby('province_name')['purchase_num'].sum().sort_values(ascending=False)?
#?繪制地圖
map1?=?Map(init_opts=opts.InitOpts(width='1350px',?height='750px'))
map1.add("",?[list(z)?for?z?in?zip(province_num.index.tolist(),?province_num.values.tolist())],
?????????maptype='china'
????????)?
map1.set_global_opts(title_opts=opts.TitleOpts(title='國(guó)內(nèi)各省份熱干面銷(xiāo)量分布'),
?????????????????????visualmap_opts=opts.VisualMapOpts(max_=300000),
?????????????????????toolbox_opts=opts.ToolboxOpts()
????????????????????)
map1.render()?
不同價(jià)格區(qū)間的商品數(shù)量:

代碼實(shí)現(xiàn):
def?tranform_price(x):
????if?x?<=?20:
????????return?'0~20'
????elif?x?<=?50:
????????return?'20~50'
????elif?x?<=?100:
????????return?'50~100'
????elif?x?<=?200:
????????return?'100~200'
????else:
????????return?'200~2500'
df['price_cut']?=?df.price.apply(lambda?x:?tranform_price(x))?
price_num?=?df.price_cut.value_counts()
price_num
bar3?=?Bar(init_opts=opts.InitOpts(width='1350px',?height='750px'))?
bar3.add_xaxis(price_num.index.tolist())
bar3.add_yaxis('price_num',?price_num.values.tolist())?
bar3.set_global_opts(title_opts=opts.TitleOpts(title='不同價(jià)格區(qū)間的商品數(shù)量'),
?????????????????????visualmap_opts=opts.VisualMapOpts(max_=1500))?
bar3.render()?
不同價(jià)格區(qū)間的銷(xiāo)量占比

代碼實(shí)現(xiàn):
from?pyecharts.charts?import?Pie
price_cut_num?=?df.groupby('price_cut')['purchase_num'].sum()?
data_pair?=?[list(z)?for?z?in?zip(price_cut_num.index,?price_cut_num.values)]
#?餅圖
pie1?=?Pie(init_opts=opts.InitOpts(width='1350px',?height='750px'))
#?內(nèi)置富文本
pie1.add(?
????????series_name="sales",
????????radius=["35%",?"55%"],
????????data_pair=data_pair,
????????label_opts=opts.LabelOpts(
????????????position="outside",
????????????formatter="{a|{a}}{abg|}\n{hr|}\n?{b|:?}{c}??{per|go7utgvlrp%}??",
????????????background_color="#eee",
????????????border_color="#aaa",
????????????border_width=1,
????????????border_radius=4,
????????????rich={
????????????????"a":?{"color":?"#999",?"lineHeight":?22,?"align":?"center"},
????????????????"abg":?{
????????????????????"backgroundColor":?"#e3e3e3",
????????????????????"width":?"100%",
????????????????????"align":?"right",
????????????????????"height":?22,
????????????????????"borderRadius":?[4,?4,?0,?0],
????????????????},
????????????????"hr":?{
????????????????????"borderColor":?"#aaa",
????????????????????"width":?"100%",
????????????????????"borderWidth":?0.5,
????????????????????"height":?0,
????????????????},
????????????????"b":?{"fontSize":?16,?"lineHeight":?33},
????????????????"per":?{
????????????????????"color":?"#eee",
????????????????????"backgroundColor":?"#334455",
????????????????????"padding":?[2,?4],
????????????????????"borderRadius":?2,
????????????????},
????????????},
????????),
)
pie1.set_global_opts(legend_opts=opts.LegendOpts(pos_left="left",?pos_top='30%',?orient="vertical"),?
?????????????????????toolbox_opts=opts.ToolboxOpts(),
?????????????????????title_opts=opts.TitleOpts(title='熱干面不同價(jià)格銷(xiāo)量占比'))
pie1.set_series_opts(
????tooltip_opts=opts.TooltipOpts(trigger="item",?formatter="{a}?
:?{c}?(go7utgvlrp%)")
????)
pie1.render()?
商品標(biāo)題文本分析 - 詞云圖

代碼實(shí)現(xiàn):
from?pyecharts.charts?import?WordCloud
from?pyecharts.globals?import?SymbolType
#?詞云圖
word1?=?WordCloud(init_opts=opts.InitOpts(width='1350px',?height='750px'))
word1.add("",?[*zip(key_words.words,?key_words.num)],
??????????word_size_range=[20,?200],
??????????shape=SymbolType.DIAMOND)
word1.set_global_opts(title_opts=opts.TitleOpts('熱干面店鋪商品關(guān)鍵詞分布'),
??????????????????????toolbox_opts=opts.ToolboxOpts())
word1.render()?
#?在一個(gè)頁(yè)面中生成所有圖
page?=?Page()
page.add(bar1,?bar2,?map1,?bar3,?pie1,?word1)
page.render('熱干面數(shù)據(jù)分析.html')
以上就是如何用Python獲取全網(wǎng)熱干面銷(xiāo)量數(shù)據(jù)的內(nèi)容啦,如果感興趣的話(huà)不妨下載數(shù)據(jù)和代碼?: https://pan.baidu.com/s/1rM6AimS9XFRtZvci9zoAcg 提取碼: tpcz
一份熱干面,一份貢獻(xiàn),武漢加油,湖北加油!
