作者:藍鯨 類型:轉載
本篇文章是python爬蟲系列的第三篇,介紹如何抓取京東商城商品評論信息,並對這些評論信息進行分析和可視化。下面是要抓取的商品信息,一款女士文胸。這個商品共有紅色,黑色和膚色三種顏色, 70B到90D共18個尺寸,以及超過700條的購買評論。
京東商品評論信息是由JS動態加載的,所以直接抓取商品詳情頁的URL並不能獲得商品評論的信息。因此我們需要先找到存放商品評論信息的文件。這里我們使用Chrome瀏覽器里的開發者工具進行查找。
具體方法是在商品詳情頁點擊鼠標右鍵,選擇檢查,在彈出的開發者工具界面中選擇Network,設置為禁用緩存(Disable cache)和只查看JS文件。然后刷新頁面。頁面加載完成后向下滾動鼠標找到商品評價部分,等商品評價信息顯示出來后,在下面Network界面的左側篩選框中輸入productPageComments,這時下面的加載記錄中只有一條信息,這里包含的就是商品詳情頁的商品評論信息。點擊這條信息,在右側的Preview界面中可以看到其中包含了當前頁面中的評論信息。(抓取價格信息輸入prices)。
復制這條信息,並把URL地址放在瀏覽器中打開,里面包含了當前頁的商品評論信息。這就是我們要抓取的URL地址。https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv100&productId=10001234327&score=0&sortType=5&page=0&pageSize=10
仔細觀察這條URL地址可以發現,其中productId=10001234327是當前商品的商品ID。與商品詳情頁URL中的ID一致。而page=0是頁碼。如果我們要獲取這個商品的所有評論,只需要更改page后面的數字即可。
在獲得了商品評論的真實地址以及URL地址的規律后,我們開始使用python抓取這件商品的700+條評論信息。並對這些信息進行處理和分析。
開始前的准備工作
在開始抓取之前先要導入各種庫文件,這里我們分別介紹下需要導入的每個庫文件的名稱以及在數據抓取和分析中的作用。requests用於進行頁面抓取,time用於設置抓取過程中的Sleep時間,random用於生產隨機數,這里的作用是將抓取頁面的順序打亂,re用於在抓取后的頁面代碼中提取需要的信息,numpy用於常規的指標計算,pandas用於進行數據匯總和透視分析,matplotlib用於繪制各站圖表,jieba用於對評論內容進行分詞和關鍵詞提取。
#導入requests庫(請求和頁面抓取) import requests #導入time庫(設置抓取Sleep時間) import time #導入random庫(生成亂序隨機數) import random #導入正則庫(從頁面代碼中提取信息) import re #導入數值計算庫(常規計算) import numpy as np #導入科學計算庫(拼表及各種分析匯總) import pandas as pd #導入繪制圖表庫(數據可視化) import matplotlib.pyplot as plt #導入結巴分詞庫(分詞) import jieba as jb #導入結巴分詞(關鍵詞提取) import jieba.analyse
將爬蟲偽裝成瀏覽器
導入完庫文件后,還不能直接進行抓取,因為這樣很容易被封。我們還需要對爬蟲進行偽裝,是爬蟲看起來更像是來自瀏覽器的訪問。這里主要的兩個工作是設置請求中的頭文件信息以及設置Cookie的內容。
頭文件信息很容易找到,在Chrome的開發者工具中選擇Network,刷新頁面后選擇Headers就可以看到本次訪問的頭文件信息,里面包含了一些瀏覽器的技術參數和引薦來源信息。將這些信息直接添加到代碼中就可以,這里我們將頭部信息保存在headers中。
#設置請求中頭文件的信息 headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11', 'Accept':'text/html;q=0.9,*/*;q=0.8', 'Accept-Charset':'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Connection':'close', 'Referer':'https://www.jd.com/' }
在查看頭文件信息的旁邊還有一個Cookies標簽,點擊進去就是本次訪問的Cookies信息。這里的Cookies信息與前面頭文件中的Cookie信息一致,不過這里更加清晰。把Request Cookies信息復制到代碼中即可,這里我們將Request Cookies信息保存在Cookie中。
#設置Cookie的內容 cookie={'TrackID':'1_VWwvLYiy1FUr7wSr6HHmHhadG8d1-Qv-TVaw8JwcFG4EksqyLyx1SO7O06_Y_XUCyQMksp3RVb2ezA', '__jda':'122270672.1507607632.1423495705.1479785414.1479794553.92', '__jdb':'122270672.1.1507607632|92.1479794553', '__jdc':'122270672', '__jdu':'1507607632', '__jdv':'122270672|direct|-|none|-|1478747025001', 'areaId':'1', 'cn':'0', 'ipLoc-djd':'1-72-2799-0', 'ipLocation':'%u5317%u4EAC', 'mx':'0_X', 'rkv':'V0800', 'user-key':'216123d5-4ed3-47b0-9289-12345', 'xtest':'4657.553.d9798cdf31c02d86b8b81cc119d94836.b7a782741f667201b54880c925faec4b'}
抓取商品評論信息
設置完請求的頭文件和Cookie信息后,我們開始抓取京東商品評論的信息。前面分析URL的時候說過,URL中包含兩個重要的信息,一個是商品ID,另一個是頁碼。這里我們只抓取一個商品的評論信息,因此商品ID不需要更改。但這個商品的評論有700+條,也就是有近80頁需要抓取,因此頁碼不是一個固定值,需要在0-80之間變化。這里我們將URL分成兩部分,通過隨機生成頁碼然后拼接URL的方式進行抓取。
#設置URL的第一部分 url1='https://sclub.jd.com/comment/productPageComments.action?productId=10001234327&score=0&sortType=3&page=' #設置URL的第二部分 url2='&pageSize=10&callback=fetchJSON_comment98vv41127' #亂序輸出0-80的唯一隨機數 ran_num=random.sample(range(80), 80)
為了使抓取過程看起來更加隨機,我們沒有從第1頁一直抓取到第80頁。而是使用random生成0-80的唯一隨機數,也就是要抓取的頁碼編號。然后再將頁碼編號與兩部分URL進行拼接。這里我們只知道商品有700+的評論,但並不知道具體數字,所以抓取范圍定位從0-80頁。
下面是具體的抓取過程,使用for循環每次從0-80的隨機數中找一個生成頁碼編號,與兩部分的URL進行拼接。生成要抓取的URL地址並與前面設置好的頭文件信息和Cookie信息一起發送請求獲取頁面信息。將獲取到的頁面信息進行匯總。每次請求間休息5秒針,避免過於頻繁的請求導致返回空值。
#拼接URL並亂序循環抓取頁面 for i in ran_num: a = ran_num[0] if i == a: i=str(i) url=(url1+i+url2) r=requests.get(url=url,headers=headers,cookies=cookie) html=r.content else: i=str(i) url=(url1+i+url2) r=requests.get(url=url,headers=headers,cookies=cookie) html2=r.content html = html + html2 time.sleep(5) print("當前抓取頁面:",url,"狀態:",r)
在抓取的過程中輸入每一步抓取的頁面URL以及狀態。通過下面的截圖可以看到,在page參數后面的頁碼是隨機生成的並不連續。
抓取完80個頁面后,我們還需要對頁面進行編碼。完成編碼后就可以看到其中所包含的中文評論信息了。后面大部分苦逼的工作就是要對這些評論信息進行不斷提取和反復的清洗。
#對抓取的頁面進行編碼 html=str(html, encoding = "GBK")
這里建議將抓取完的數據存儲在本地,后續工作可以直接從本地打開文件進行清洗和分析工作。避免每次都要重新抓取數據。這里我們將數據保存在桌面的page.txt文件中。
#將編碼后的頁面輸出為txt文本存儲 file = open("c:\\Users \\Desktop\\page.txt", "w") file.write(html) file.close()
讀取文件也比較簡單,直接open加read函數就可以完成了。
#讀取存儲的txt文本文件 html = open('c:\\Users\\ Desktop\\page.txt', 'r').read()
提取信息並進行數據清洗
京東的商品評論中包含了很多有用的信息,我們需要將這些信息從頁面代碼中提取出來,整理成數據表以便進行后續的分析工作。這里應該就是整個過程中最苦逼的數據提取和清洗工作了。我們使用正則對每個字段進行提取。對於特殊的字段在通過替換等方式進行提取和清洗。
下面是提取的第一個字段userClient,也就是用戶發布評論時所使用的設備類型,這類的字段提取還比較簡單,一行代碼搞定。查看一下提取出來的字段還比較干凈。使用同樣的方法我們分別提取了以下這些字段的內容。
#使用正則提取userClient字段信息 userClient=re.findall(r',"usefulVoteCount".*?,"userClientShow":(.*?),',html) #使用正則提取userLevel字段信息 userLevel=re.findall(r'"referenceImage".*?,"userLevelName":(.*?),',html) #使用正則提取productColor字段信息 productColor=re.findall(r'"creationTime".*?,"productColor":(.*?),',html) #使用正則提取recommend字段信息 recommend=re.findall(r'"creationTime".*?,"recommend":(.*?),',html) #使用正則提取nickname字段信息 nickname=re.findall(r'"creationTime".*?,"nickname":(.*?),',html) #使用正則提取userProvince字段信息 userProvince=re.findall(r'"referenceImage".*?,"userProvince":(.*?),',html) #使用正則提取usefulVoteCount字段信息 usefulVoteCount=re.findall(r'"referenceImage".*?,"usefulVoteCount":(.*?),',html) #使用正則提取days字段信息 days=re.findall(r'"usefulVoteCount".*?,"days":(.*?)}',html) #使用正則提取score字段信息 score=re.findall(r'"referenceImage".*?,"score":(.*?),',html)</pre>
還有一些字段比較負責,無法通過正則一次提取出來,比如isMobile字段,有些值的后面還有大括號。這就需要進一步的提取和清洗工作。
#使用正則提取isMobile字段信息 isMobile=re.findall(r'"usefulVoteCount".*?,"isMobile":(.*?),',html)
使用for循環配合替換功能將字段中所有的}替換為空。替換完成后字段看起來干凈多了。
#替換掉最后的} mobile=[] for m in isMobile: n=m.replace('}','') mobile.append(n)
productSize字段中包含了胸圍和杯罩兩類信息,為了獲得獨立的杯罩信息需要進行二次提取,將杯罩信息單獨保存出來。
#使用正則提取productSize字段信息 productSize=re.findall(r'"creationTime".*?,"productSize":(.*?),',html)
使用for循環將productSize中的第三個字符杯罩信息提取出來,並保持在cup字段中。
#提取杯罩信息 cup=[] for s in productSize: s1=s[3] cup.append(s1)
創建評論的日期信息僅依靠正則提取出來的信息還是比較亂,無法直接使用。因此也需要進行二次提取。下面是使用正則提取出的結果。
#使用正則提取時間字段信息 creationTime1=re.findall(r'"creationTime":(.*?),"referenceName',html)
日期和時間信息處於前20個字符,在二次提取中根據這個規律直接提起每個條目的前20個字符即可。將日期和時間單獨保存為creationTime。
#提取日期和時間 creationTime=[] for d in creationTime1: date=d[1:20] creationTime.append(date)
在上一步日期和時間的基礎上,我們再進一步提取出單獨的小時信息,方法與前面類似,提取日期時間中的第11和12個字符,就是小時的信息。提取完保存在hour字段以便后續的分析和匯總工作。
#提取小時信息 hour=[] for h in creationTime: date=h[10:13] hour.append(date)
最后要提取的是評論內容信息,頁面代碼中包含圖片的評論信息是重復的,因此在使用正則提取完后還需要對評論信息進行去重。
#使用正則提取評論信息 content=re.findall(r'"guid".*?,"content":(.*?),',html)
使用if進行判斷,排除掉所有包含圖片的評論信息,已達到評論去重的目的。
#對提取的評論信息進行去重 content_1=[] for i in content: if not "img" in i: content_1.append(i)
完成所有字段信息的提取和清洗后,將這些字段組合在一起生成京東商品評論數據匯總表。下面是創建數據表的代碼。數據表生成后還不能馬上使用,需要對字段進行格式設置,例如時間和日期字段和一些包含數值的字段。具體的字段和格式設置依據后續的分析過程和目的。這里我們將creationTime設置為時間格式,並設置為數據表的索引列。將days字段設置為數值格式。
#將前面提取的各字段信息匯總為table數據表,以便后面分析 table=pd.DataFrame({'creationTime':creationTime,'hour':hour,'nickname':nickname,'productColor':productColor,'productSize':productSize,'cup':cup,'recommend':recommend,'mobile':mobile,'userClient':userClient,'userLevel':userLevel,'userProvince':userProvince,'usefulVoteCount':usefulVoteCount,'content_1':content_1,'days':days,'score':score}) #將creationTime字段更改為時間格式 table['creationTime']=pd.to_datetime(table['creationTime']) #設置creationTime字段為索引列 table = table.set_index('creationTime') #設置days字段為數值格式 table['days']=table['days'].astype(np.int64) #查看整理完的數據表 table.head()
這里建議再次保存清洗和預處理完的數據表。我們這里將數據表保存為csv格式。到了這一步可以選擇在Excel中完成后續的數據分析和可視化過程,也可以繼續在python中完成。我們這里選擇繼續在python中完成后續的數據分析和可視化工作。
#保存table數據表 table.to_csv('jd_table.csv')
數據分析及可視化
分月評論數據變化趨勢
首先查看京東商品評論的時間變化趨勢情況,大部分用戶在購買商品后會在10天以內進行評論,因此我們可以近似的認為在一個月的時間維度中評論時間的變化趨勢代表了用戶購買商品的變化趨勢。
按月的維度對數據表進行匯總,並提取每個月的nickname的數量。下面是具體的代碼和分月數據。
#對數據表按月進行匯總並生成新的月度匯總數據表 table_month=table.resample('M',how=len) #提取按月匯總的nickname month=table_month['nickname']
數據范圍從2015年11月到2016年11月。使用柱狀圖對分月數據進行可視化。從圖表中可以看到2016年6月是評論的高峰,也可以近似的認為這個時間段是用戶購買該商品的高峰(6月18日是京東店慶日)。排除2016年6月和不完整的11月數據,整齊趨勢中冬季評論量較低,夏季較高。這是由於該商品的季節屬性導致的,超薄胸罩更適合夏天佩戴(這個屬性我們是在用戶的評論中發現的,在京東的商品介紹中並不明顯,只在標題中以”薄杯”說明)。
#繪制分月評論數量變化趨勢圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4,5,6,7,8,9,10,11,12,13]) plt.bar([1,2,3,4,5,6,7,8,9,10,11,12,13],month,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('月份') plt.ylabel('評論數量') plt.title('分月評論數量變化趨勢') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.xticks(a,('15-11','12','16-01','02','03','04','05','06','07','08','09','10','11')) plt.show()
通過篩選將數據表分為使用移動設備和未使用移動設備兩個表格,再分別查看和對比評論變化趨勢。
#在table表中篩選使用移動設備的條目並創建新表 mobile_t=table.loc[table["mobile"] == "true"] #在table中篩選沒有使用移動設備的條目並創建新表 mobile_f=table.loc[table["mobile"] == "false"] #按月匯總使用移動設備的數據 mobile_t_m=mobile_t.resample('M',how=len) #按月匯總不使用移動設備的數據 mobile_f_m=mobile_f.resample('M',how=len) #提取使用移動設備的按月匯總nickname mobile_y=mobile_t_m['nickname'] #提取沒有使用移動設備的按月匯總nickname mobile_n=mobile_f_m['nickname']
從結果中可以看出使用移動設備進行評論的用戶在所有的時間段中都要明顯高於使用PC的用戶。
#繪制PC與移動設備評論數量變化趨勢圖 plt.subplot(2, 1, 1) plt.plot(mobile_y,'go',mobile_y,'g-',color='#99CC01',linewidth=3,markeredgewidth=3,markeredgecolor='#99CC01',alpha=0.8) plt.ylabel('移動設備評論數量') plt.title('PC與移動設備評論數量變化趨勢') plt.subplot(2, 1, 2) plt.plot(mobile_n,'go',mobile_n,'g-',color='#99CC01',linewidth=3,markeredgewidth=3,markeredgecolor='#99CC01',alpha=0.8) plt.xlabel('月份') plt.ylabel('PC評論數量') plt.show()
24小時評論數量變化趨勢
按小時維度對評論數據進行匯總,查看用戶在24小時中的評論變化趨勢。這里需要說明的是24小時趨勢只能反映用戶登錄京東商城的趨勢,並不能近似推斷用戶購買商品的時間趨勢。
#按24小時分別對table表中的nickname進行計數 hour_group=table.groupby('hour')['nickname'].agg(len)
從24小時評論趨勢圖來看,發布商品評論的趨勢與作息時間一致,並且每日的閑暇時間是發布評論的高峰。如早上的8點,中午的12點和晚上的22點,是一天24小時中的三個評論高峰點。
#匯總24小時評論數量變化趨勢圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]) plt.bar([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],hour_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('24小時') plt.ylabel('評論數量') plt.title('24小時評論數量變化趨勢') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.xticks(a,('0','1','2','3','4','5','6','7','8','9','10','11','12''13','14','15','16','17','18','19','20','21','22','23')) plt.show()
將24小時的評論數量分為移動設備和未使用移動設備,查看並對比這兩者的變化趨勢情況。
#在使用移動設備的表中按24小時對nickname進行計數 mobile_y_h=mobile_t.groupby('hour')['nickname'].agg(len) #在沒有使用移動設備的表中按24小時對nickname進行計算 mobile_n_h=mobile_f.groupby('hour')['nickname'].agg(len)
移動設備的評論數量在24小時中的各個時間段都要高於PC的評論數量,並且在晚間更加活躍,持續時間高於PC端。這里我們產生了一個疑問,在一天中的工作時間段中,大部分用戶都會在電腦旁,但為什么這些時間段里移動設備的評論數量也要高於PC端呢?這是否與胸罩這個產品的私密性有關聯。用戶不希望別人看到自己購買的商品或評論的內容,所以選擇使用移動設備進行評論?
#匯總PC與移動設備24小時評論數量變化趨勢 plt.subplot(2, 1, 1) plt.plot(mobile_y_h,'go',mobile_y_h,'g-',color='#99CC01',linewidth=3,markeredgewidth=3,markeredgecolor='#99CC01',alpha=0.8) plt.ylabel('移動設備評論數量') plt.title('PC與移動設備24小時評論數量變化趨勢') plt.subplot(2, 1, 2) plt.plot(mobile_n_h,'go',mobile_n_h,'g-',color='#99CC01',linewidth=3,markeredgewidth=3,markeredgecolor='#99CC01',alpha=0.8) plt.xlabel('24小時') plt.ylabel('PC評論數量') plt.show()
用戶客戶端分布情況
前面的分析中,我們看到使用移動設備進行評論的用戶要遠高於PC端的用戶,下面我們對用戶所使用的設備分布情況進行統計。首先在數據表中按用戶設備(userClient)對nickname字段進行計數匯總。
#在table表中按userClient對數據進行匯總 userClient_group=table.groupby('userClient')['nickname'].agg(len)
從用戶客戶端分布情況來看,移動端的設備占大多數,其中使用iphone的用戶要高於Android用戶。由於微信購物和QQ購物單獨被分了出來,無法確定設備,因此單獨進行對比。使用微信購物渠道的用戶要高於QQ購物。
#匯總用戶客戶端分布情況 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4,5,6]) plt.bar([1,2,3,4,5,6],userClient_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('客戶端分布') plt.ylabel('評論數量') plt.title('用戶客戶端分布情況') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.ylim(0,300) plt.xticks(a,('PC','Android','iPad','iPhone','微信購物','QQ購物')) plt.show()
購買后評論天數分布
在購買后評論天數方面,我們將用戶發布評論與購買的時間間隔分為7組,分別為購買后1-5天內,5-10天內,10-15天內,15-20天內,20-25天內,25-30天內,以及大於30天。然后統計並對比用戶在不同時間區間內發布評論的數量情況。
#設置分組條件,並對table表中的days字段進行分組 bins = [0, 5, 10, 15, 20, 25, 30, 92] day_group = ['5天', '10天', '15天', '20天', '25天','30天','大於30天'] table['day_group'] = pd.cut(table['days'], bins, labels=day_group) #按新設置的分組對數據進行匯總 days_group=table.groupby('day_group')['nickname'].agg(len)
從圖表中看出,購買后5天以內是用戶發布評論的高峰,也就我們之前推測評論時間趨勢近似於購買時間的依據。隨着時間的增加評論數量逐漸下降。
#繪制用戶購買后評論天數分布圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4,5,6,7]) plt.bar([1,2,3,4,5,6,7],days_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('購買后天數') plt.ylabel('發布評論數量') plt.title('購買后評論天數分布') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.ylim(0,300) plt.xticks(a,('5天','10天','15天','20天','25天','30天','大於30天')) plt.show()
商品評分分布情況
京東商城對商品按5星評分划分為好評,中評和差評三個等級。我們這里來看下用戶5星評分的分布情況。在數據表中score字段中的值表示了用戶對胸罩產品的打分情況。我們按打分情況對數據進行匯總。
#在table表中按score對數據進行匯總 score_group=table.groupby('score')['nickname'].agg(len) #繪制用戶評分分布情況圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4,5]) plt.bar([1,2,3,4,5],score_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('評分分布') plt.ylabel('評論數量') plt.title('用戶評分分布情況') plt.legend(['評論數量'], loc='best') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.ylim(0,700) plt.xticks(a,('1星','2星','3星','4星','5星')) plt.show()
從圖表中可以看出,大部分用戶對商品的評分是5星。4星以下的幾乎沒有。但從另一個維度來看,在用戶對最有用評論的投票(usefulVoteCount)中得票最多的是一個1星的評論。
用戶胸罩尺碼分布情況
在胸罩的尺寸方面包含兩個信息,一個是胸圍尺寸,另一個是罩杯。我們在前面的清洗過程中對杯罩創建了單獨的字段。下面只對這個字段進行匯總統計。
#在table 表中按cup對數據進行匯總 cup_group=table.groupby('cup')['nickname'].agg(len)
從圖表中可以看出,評論用戶中最多的是B杯罩,其次為C杯罩,D和E的用戶數量較少。
#繪制用戶胸罩尺碼分布圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4]) plt.bar([1,2,3,4],cup_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('尺碼') plt.ylabel('評論數量') plt.title('用戶胸罩尺碼分布情況') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.ylim(0,350) plt.xticks(a,('B','C','D','E')) plt.show()
胸罩顏色偏好分布
這款胸罩共分為三個顏色,紅色,膚色和黑色。我們按顏色對評論數據進行匯總,查看用戶對不同胸罩顏色的偏好情況。
#在table表中按productColor對數據進行匯總 color_group=table.groupby('productColor')['nickname'].agg(len)
從不同顏色的評論數量上來看,大部分用戶購買的是膚色,購買紅色和黑色的用戶數量明顯少於膚色。
#繪制用戶顏色選擇分布圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3]) plt.bar([1,2,3],color_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('顏色分布') plt.ylabel('評論數量') plt.title('用戶顏色選擇分布') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.ylim(0,600) plt.xticks(a,('紅色','膚色','黑色')) plt.show()
不同尺碼用戶對胸罩顏色偏好對比
在前面杯罩尺寸和顏色偏好的基礎上,我們將兩維度進行交叉分析,查看並對比不同杯罩尺碼用戶在顏色選擇上是有規律或明顯差異。這里使用數據透視表,將杯罩尺寸設置為行,顏色設置為列,對nickname進行計數。
#使用數據透視表對胸罩尺碼和顏色進行交叉分析 color_size=pd.pivot_table(table,index=["cup"],values=["nickname"],columns=["productColor"],aggfunc=len,fill_value=0)
從數據透視表中分別提取出不同尺寸杯罩用戶購買的顏色數據。
#提取B,C,D,E尺碼的顏色分布 b=color_size.ix['B'] c=color_size.ix['C'] d=color_size.ix['D'] e=color_size.ix['E']
將不同杯罩尺寸用戶對顏色的選擇分布繪制成四個圖表,進行對比和分析。
#匯總不同胸罩尺碼顏色分布圖 plt.rc('font', family='STXihei', size=9) plt.subplot(2, 2, 1) plt.bar([1,2,3],b,color=["#EE9788","#E2D4C9","#151419"],alpha=0.8,align='center',edgecolor='white') plt.title('B Cup') plt.xticks(a,('紅色','膚色','黑色')) plt.subplot(2, 2, 2) plt.bar([1,2,3],c,color=["#EE9788","#E2D4C9","#151419"],alpha=0.8,align='center',edgecolor='white') plt.title('C Cup') plt.ylim(0,200) plt.xticks(a,('紅色','膚色','黑色')) plt.subplot(2, 2, 3) plt.bar([1,2,3],d,color=["#EE9788","#E2D4C9","#151419"],alpha=0.8,align='center',edgecolor='white') plt.title('D Cup') plt.xticks(a,('紅色','膚色','黑色')) plt.subplot(2, 2, 4) plt.bar([1,2,3],e,color=["#EE9788","#E2D4C9","#151419"],alpha=0.8,align='center',edgecolor='white') plt.title('E,Cup') plt.xticks(a,('紅色','膚色','黑色')) plt.show()
在下面的圖表中,B,C,D,E四個杯罩的用戶選擇膚色的數量都要高於另外兩種顏色。整體差別並不明顯。如果非要說有什么差別的話,C杯罩用戶更偏好紅色?D杯罩更喜歡黑色?這個結論明顯站不住腳。但有一點可以說,雖然黑色顯瘦但E杯罩的用戶中沒有人選擇黑色。
D&E Cup用戶城市分布情況
最后我們再看看下D杯罩和E杯罩用戶的城市分布情況,在數據表中並不是所有的評論都有城市信息。因此按城市統計出來的數據可能並不准確,僅供參考。
首先從數據表中篩選出cup值為D和E的數據,並保存在新的數據表中。
#從table表中提取cup尺寸為D或E的數據條目並創建新表 table_big=table.loc[(table["cup"] == "D")|(table["cup"] == "E")]
在新的數據表中按用戶所在城市(userProvince)進行匯總。查看不同城市D和E杯罩的數量。
#按城市對數據進行計數匯總 city_group=table_big.groupby('userProvince')['nickname'].agg(len)
將匯總結果繪制為圖表,從圖表來看,數量最多的為未知城市,排除未知城市,北京和廣東的數量遙遙領先,其次為四川和河南。
#匯總D和E Cup城市分布圖 plt.rc('font', family='STXihei', size=9) a=np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]) plt.barh([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24],city_group,color='#99CC01',alpha=0.8,align='center',edgecolor='white') plt.xlabel('評論數量') plt.ylabel('城市') plt.title('D Cup和E Cup城市分布') plt.legend(['評論數量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='x',alpha=0.4) plt.yticks(a,('未知','上海','雲南','內蒙古','北京','四川','天津','寧夏','安徽','山東','廣東','江西','江蘇','江西','河北','河南','浙江','湖北','湖南','甘肅','福建','遼寧','重慶','青海','香港')) plt.show()
胸罩評論內容語義分析
前面我們分別對數據表中的字段進行了統計和分析,文章最后我們對商品的評論內容進行語義分析,看看大家在這700+條評論中都在說些什么。
好好先生購買比例
在人工查看了一些評論內容后,我們發現一些有意思的信息。有一部分評論是老公或男朋友發的,這說明一些好好先生會幫老婆或女友購買胸罩。那么這部分用戶的比例有多少呢?
我們把評論中包含有關鍵詞“老婆”和“女朋友”的評論單獨保存在出來。
#篩選包含”老婆”和”女朋友”的評論 content_2=[] for i in content_1: if "老婆"in i or "女朋友"in i: content_2.append(i)
查看這些包含關鍵詞的評論內容,確實是老公和男朋友來購買胸罩並且發布的評論。
#查看評論內容 content_2
經過計算,在這款胸罩產品的評論中,由老公或男朋友購買的比例僅為2.35%。
#計算老公或男朋友購買胸罩的比例 len(content_2)/len(content_1)*100 2.3545706371191137
商品評論關鍵詞分析
回歸到商品評論分析,我們使用結巴分詞對所有胸罩的評論信息進行了分詞,並提取了權重最高的關鍵詞列表。
#文本數據格式轉換 word_str = ''.join(content_1) #提取文字關鍵詞 word_rank=jieba.analyse.extract_tags(word_str, topK=20, withWeight=True, allowPOS=()) #轉化為數據表 word_rank = pd.DataFrame(word_rank,columns=['word','rank']) #查看關鍵詞及權重 word_rank.sort('rank',ascending=False)
從高權重關鍵詞列表來看,用戶評論以正面信息為主,”不錯”,”舒服”,”喜歡”等主觀感受的正面評論權重較高。
結語
本篇文章我們從商品評論信息的抓取,清洗到分析和數據可視化實現了一個完整的閉環。整個過程中數據的清洗和預處理是最為復雜也是耗時最多的工作。由於抓取的數據量較少,只有700+條數據。因此里面的一些結論可能沒有代表性,結論也未必准確,僅供參考。