python制作爬蟲爬取京東商品評(píng)論教程
本篇文章是python爬蟲系列的第三篇,介紹如何抓取京東商城商品評(píng)論信息,并對(duì)這些評(píng)論信息進(jìn)行分析和可視化。下面是要抓取的商品信息,一款女士文胸。這個(gè)商品共有紅色,黑色和膚色三種顏色, 70B到90D共18個(gè)尺寸,以及超過700條的購(gòu)買評(píng)論。
京東商品評(píng)論信息是由JS動(dòng)態(tài)加載的,所以直接抓取商品詳情頁(yè)的URL并不能獲得商品評(píng)論的信息。因此我們需要先找到存放商品評(píng)論信息的文件。這里我們使用Chrome瀏覽器里的開發(fā)者工具進(jìn)行查找。
具體方法是在商品詳情頁(yè)點(diǎn)擊鼠標(biāo)右鍵,選擇檢查,在彈出的開發(fā)者工具界面中選擇Network,設(shè)置為禁用緩存(Disable cache)和只查看JS文件。然后刷新頁(yè)面。頁(yè)面加載完成后向下滾動(dòng)鼠標(biāo)找到商品評(píng)價(jià)部分,等商品評(píng)價(jià)信息顯示出來后,在下面Network界面的左側(cè)篩選框中輸入productPageComments,這時(shí)下面的加載記錄中只有一條信息,這里包含的就是商品詳情頁(yè)的商品評(píng)論信息。點(diǎn)擊這條信息,在右側(cè)的Preview界面中可以看到其中包含了當(dāng)前頁(yè)面中的評(píng)論信息。(抓取價(jià)格信息輸入prices)。
復(fù)制這條信息,并把URL地址放在瀏覽器中打開,里面包含了當(dāng)前頁(yè)的商品評(píng)論信息。這就是我們要抓取的URL地址。https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98vv100&productId=10001234327&score=0&sortType=5&page=0&pageSize=10
仔細(xì)觀察這條URL地址可以發(fā)現(xiàn),其中productId=10001234327是當(dāng)前商品的商品ID。與商品詳情頁(yè)URL中的ID一致。而page=0是頁(yè)碼。如果我們要獲取這個(gè)商品的所有評(píng)論,只需要更改page后面的數(shù)字即可。
在獲得了商品評(píng)論的真實(shí)地址以及URL地址的規(guī)律后,我們開始使用python抓取這件商品的700+條評(píng)論信息。并對(duì)這些信息進(jìn)行處理和分析。
開始前的準(zhǔn)備工作
在開始抓取之前先要導(dǎo)入各種庫(kù)文件,這里我們分別介紹下需要導(dǎo)入的每個(gè)庫(kù)文件的名稱以及在數(shù)據(jù)抓取和分析中的作用。requests用于進(jìn)行頁(yè)面抓取,time用于設(shè)置抓取過程中的Sleep時(shí)間,random用于生產(chǎn)隨機(jī)數(shù),這里的作用是將抓取頁(yè)面的順序打亂,re用于在抓取后的頁(yè)面代碼中提取需要的信息,numpy用于常規(guī)的指標(biāo)計(jì)算,pandas用于進(jìn)行數(shù)據(jù)匯總和透視分析,matplotlib用于繪制各站圖表,jieba用于對(duì)評(píng)論內(nèi)容進(jìn)行分詞和關(guān)鍵詞提取。
#導(dǎo)入requests庫(kù)(請(qǐng)求和頁(yè)面抓取) import requests #導(dǎo)入time庫(kù)(設(shè)置抓取Sleep時(shí)間) import time #導(dǎo)入random庫(kù)(生成亂序隨機(jī)數(shù)) import random #導(dǎo)入正則庫(kù)(從頁(yè)面代碼中提取信息) import re #導(dǎo)入數(shù)值計(jì)算庫(kù)(常規(guī)計(jì)算) import numpy as np #導(dǎo)入科學(xué)計(jì)算庫(kù)(拼表及各種分析匯總) import pandas as pd #導(dǎo)入繪制圖表庫(kù)(數(shù)據(jù)可視化) import matplotlib.pyplot as plt #導(dǎo)入結(jié)巴分詞庫(kù)(分詞) import jieba as jb #導(dǎo)入結(jié)巴分詞(關(guān)鍵詞提取) import jieba.analyse
將爬蟲偽裝成瀏覽器
導(dǎo)入完庫(kù)文件后,還不能直接進(jìn)行抓取,因?yàn)檫@樣很容易被封。我們還需要對(duì)爬蟲進(jìn)行偽裝,是爬蟲看起來更像是來自瀏覽器的訪問。這里主要的兩個(gè)工作是設(shè)置請(qǐng)求中的頭文件信息以及設(shè)置Cookie的內(nèi)容。
頭文件信息很容易找到,在Chrome的開發(fā)者工具中選擇Network,刷新頁(yè)面后選擇Headers就可以看到本次訪問的頭文件信息,里面包含了一些瀏覽器的技術(shù)參數(shù)和引薦來源信息。將這些信息直接添加到代碼中就可以,這里我們將頭部信息保存在headers中。
#設(shè)置請(qǐng)求中頭文件的信息 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/' }
在查看頭文件信息的旁邊還有一個(gè)Cookies標(biāo)簽,點(diǎn)擊進(jìn)去就是本次訪問的Cookies信息。這里的Cookies信息與前面頭文件中的Cookie信息一致,不過這里更加清晰。把Request Cookies信息復(fù)制到代碼中即可,這里我們將Request Cookies信息保存在Cookie中。
#設(shè)置Cookie的內(nèi)容 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'}
抓取商品評(píng)論信息
設(shè)置完請(qǐng)求的頭文件和Cookie信息后,我們開始抓取京東商品評(píng)論的信息。前面分析URL的時(shí)候說過,URL中包含兩個(gè)重要的信息,一個(gè)是商品ID,另一個(gè)是頁(yè)碼。這里我們只抓取一個(gè)商品的評(píng)論信息,因此商品ID不需要更改。但這個(gè)商品的評(píng)論有700+條,也就是有近80頁(yè)需要抓取,因此頁(yè)碼不是一個(gè)固定值,需要在0-80之間變化。這里我們將URL分成兩部分,通過隨機(jī)生成頁(yè)碼然后拼接URL的方式進(jìn)行抓取。
#設(shè)置URL的第一部分 url1='https://sclub.jd.com/comment/productPageComments.action?productId=10001234327&score=0&sortType=3&page=' #設(shè)置URL的第二部分 url2='&pageSize=10&callback=fetchJSON_comment98vv41127' #亂序輸出0-80的唯一隨機(jī)數(shù) ran_num=random.sample(range(80), 80)
為了使抓取過程看起來更加隨機(jī),我們沒有從第1頁(yè)一直抓取到第80頁(yè)。而是使用random生成0-80的唯一隨機(jī)數(shù),也就是要抓取的頁(yè)碼編號(hào)。然后再將頁(yè)碼編號(hào)與兩部分URL進(jìn)行拼接。這里我們只知道商品有700+的評(píng)論,但并不知道具體數(shù)字,所以抓取范圍定位從0-80頁(yè)。
下面是具體的抓取過程,使用for循環(huán)每次從0-80的隨機(jī)數(shù)中找一個(gè)生成頁(yè)碼編號(hào),與兩部分的URL進(jìn)行拼接。生成要抓取的URL地址并與前面設(shè)置好的頭文件信息和Cookie信息一起發(fā)送請(qǐng)求獲取頁(yè)面信息。將獲取到的頁(yè)面信息進(jìn)行匯總。每次請(qǐng)求間休息5秒針,避免過于頻繁的請(qǐng)求導(dǎo)致返回空值。
#拼接URL并亂序循環(huán)抓取頁(yè)面 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("當(dāng)前抓取頁(yè)面:",url,"狀態(tài):",r)
在抓取的過程中輸入每一步抓取的頁(yè)面URL以及狀態(tài)。通過下面的截圖可以看到,在page參數(shù)后面的頁(yè)碼是隨機(jī)生成的并不連續(xù)。
抓取完80個(gè)頁(yè)面后,我們還需要對(duì)頁(yè)面進(jìn)行編碼。完成編碼后就可以看到其中所包含的中文評(píng)論信息了。后面大部分苦逼的工作就是要對(duì)這些評(píng)論信息進(jìn)行不斷提取和反復(fù)的清洗。
#對(duì)抓取的頁(yè)面進(jìn)行編碼 html=str(html, encoding = "GBK")
這里建議將抓取完的數(shù)據(jù)存儲(chǔ)在本地,后續(xù)工作可以直接從本地打開文件進(jìn)行清洗和分析工作。避免每次都要重新抓取數(shù)據(jù)。這里我們將數(shù)據(jù)保存在桌面的page.txt文件中。
#將編碼后的頁(yè)面輸出為txt文本存儲(chǔ) file = open("c:\\Users \\Desktop\\page.txt", "w") file.write(html) file.close()
讀取文件也比較簡(jiǎn)單,直接open加read函數(shù)就可以完成了。
#讀取存儲(chǔ)的txt文本文件 html = open('c:\\Users\\ Desktop\\page.txt', 'r').read()
提取信息并進(jìn)行數(shù)據(jù)清洗
京東的商品評(píng)論中包含了很多有用的信息,我們需要將這些信息從頁(yè)面代碼中提取出來,整理成數(shù)據(jù)表以便進(jìn)行后續(xù)的分析工作。這里應(yīng)該就是整個(gè)過程中最苦逼的數(shù)據(jù)提取和清洗工作了。我們使用正則對(duì)每個(gè)字段進(jìn)行提取。對(duì)于特殊的字段在通過替換等方式進(jìn)行提取和清洗。
下面是提取的第一個(gè)字段userClient,也就是用戶發(fā)布評(píng)論時(shí)所使用的設(shè)備類型,這類的字段提取還比較簡(jiǎn)單,一行代碼搞定。查看一下提取出來的字段還比較干凈。使用同樣的方法我們分別提取了以下這些字段的內(nèi)容。
#使用正則提取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>
還有一些字段比較負(fù)責(zé),無法通過正則一次提取出來,比如isMobile字段,有些值的后面還有大括號(hào)。這就需要進(jìn)一步的提取和清洗工作。
#使用正則提取isMobile字段信息 isMobile=re.findall(r'"usefulVoteCount".*?,"isMobile":(.*?),',html)
使用for循環(huán)配合替換功能將字段中所有的}替換為空。替換完成后字段看起來干凈多了。
#替換掉最后的} mobile=[] for m in isMobile: n=m.replace('}','') mobile.append(n)
productSize字段中包含了胸圍和杯罩兩類信息,為了獲得獨(dú)立的杯罩信息需要進(jìn)行二次提取,將杯罩信息單獨(dú)保存出來。
#使用正則提取productSize字段信息 productSize=re.findall(r'"creationTime".*?,"productSize":(.*?),',html)
使用for循環(huán)將productSize中的第三個(gè)字符杯罩信息提取出來,并保持在cup字段中。
#提取杯罩信息 cup=[] for s in productSize: s1=s[3] cup.append(s1)
創(chuàng)建評(píng)論的日期信息僅依靠正則提取出來的信息還是比較亂,無法直接使用。因此也需要進(jìn)行二次提取。下面是使用正則提取出的結(jié)果。
#使用正則提取時(shí)間字段信息 creationTime1=re.findall(r'"creationTime":(.*?),"referenceName',html)
日期和時(shí)間信息處于前20個(gè)字符,在二次提取中根據(jù)這個(gè)規(guī)律直接提起每個(gè)條目的前20個(gè)字符即可。將日期和時(shí)間單獨(dú)保存為creationTime。
#提取日期和時(shí)間 creationTime=[] for d in creationTime1: date=d[1:20] creationTime.append(date)
在上一步日期和時(shí)間的基礎(chǔ)上,我們?cè)龠M(jìn)一步提取出單獨(dú)的小時(shí)信息,方法與前面類似,提取日期時(shí)間中的第11和12個(gè)字符,就是小時(shí)的信息。提取完保存在hour字段以便后續(xù)的分析和匯總工作。
#提取小時(shí)信息 hour=[] for h in creationTime: date=h[10:13] hour.append(date)
最后要提取的是評(píng)論內(nèi)容信息,頁(yè)面代碼中包含圖片的評(píng)論信息是重復(fù)的,因此在使用正則提取完后還需要對(duì)評(píng)論信息進(jìn)行去重。
#使用正則提取評(píng)論信息 content=re.findall(r'"guid".*?,"content":(.*?),',html)
使用if進(jìn)行判斷,排除掉所有包含圖片的評(píng)論信息,已達(dá)到評(píng)論去重的目的。
#對(duì)提取的評(píng)論信息進(jìn)行去重 content_1=[] for i in content: if not "img" in i: content_1.append(i)
完成所有字段信息的提取和清洗后,將這些字段組合在一起生成京東商品評(píng)論數(shù)據(jù)匯總表。下面是創(chuàng)建數(shù)據(jù)表的代碼。數(shù)據(jù)表生成后還不能馬上使用,需要對(duì)字段進(jìn)行格式設(shè)置,例如時(shí)間和日期字段和一些包含數(shù)值的字段。具體的字段和格式設(shè)置依據(jù)后續(xù)的分析過程和目的。這里我們將creationTime設(shè)置為時(shí)間格式,并設(shè)置為數(shù)據(jù)表的索引列。將days字段設(shè)置為數(shù)值格式。
#將前面提取的各字段信息匯總為table數(shù)據(jù)表,以便后面分析 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字段更改為時(shí)間格式 table['creationTime']=pd.to_datetime(table['creationTime']) #設(shè)置creationTime字段為索引列 table = table.set_index('creationTime') #設(shè)置days字段為數(shù)值格式 table['days']=table['days'].astype(np.int64) #查看整理完的數(shù)據(jù)表 table.head()
這里建議再次保存清洗和預(yù)處理完的數(shù)據(jù)表。我們這里將數(shù)據(jù)表保存為csv格式。到了這一步可以選擇在Excel中完成后續(xù)的數(shù)據(jù)分析和可視化過程,也可以繼續(xù)在python中完成。我們這里選擇繼續(xù)在python中完成后續(xù)的數(shù)據(jù)分析和可視化工作。
#保存table數(shù)據(jù)表 table.to_csv('jd_table.csv')
數(shù)據(jù)分析及可視化
分月評(píng)論數(shù)據(jù)變化趨勢(shì)
首先查看京東商品評(píng)論的時(shí)間變化趨勢(shì)情況,大部分用戶在購(gòu)買商品后會(huì)在10天以內(nèi)進(jìn)行評(píng)論,因此我們可以近似的認(rèn)為在一個(gè)月的時(shí)間維度中評(píng)論時(shí)間的變化趨勢(shì)代表了用戶購(gòu)買商品的變化趨勢(shì)。
按月的維度對(duì)數(shù)據(jù)表進(jìn)行匯總,并提取每個(gè)月的nickname的數(shù)量。下面是具體的代碼和分月數(shù)據(jù)。
#對(duì)數(shù)據(jù)表按月進(jìn)行匯總并生成新的月度匯總數(shù)據(jù)表 table_month=table.resample('M',how=len) #提取按月匯總的nickname month=table_month['nickname']
數(shù)據(jù)范圍從2015年11月到2016年11月。使用柱狀圖對(duì)分月數(shù)據(jù)進(jìn)行可視化。從圖表中可以看到2016年6月是評(píng)論的高峰,也可以近似的認(rèn)為這個(gè)時(shí)間段是用戶購(gòu)買該商品的高峰(6月18日是京東店慶日)。排除2016年6月和不完整的11月數(shù)據(jù),整齊趨勢(shì)中冬季評(píng)論量較低,夏季較高。這是由于該商品的季節(jié)屬性導(dǎo)致的,超薄胸罩更適合夏天佩戴(這個(gè)屬性我們是在用戶的評(píng)論中發(fā)現(xiàn)的,在京東的商品介紹中并不明顯,只在標(biāo)題中以”薄杯”說明)。
#繪制分月評(píng)論數(shù)量變化趨勢(shì)圖 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('評(píng)論數(shù)量') plt.title('分月評(píng)論數(shù)量變化趨勢(shì)') plt.legend(['評(píng)論數(shù)量'], 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()
通過篩選將數(shù)據(jù)表分為使用移動(dòng)設(shè)備和未使用移動(dòng)設(shè)備兩個(gè)表格,再分別查看和對(duì)比評(píng)論變化趨勢(shì)。
#在table表中篩選使用移動(dòng)設(shè)備的條目并創(chuàng)建新表 mobile_t=table.loc[table["mobile"] == "true"] #在table中篩選沒有使用移動(dòng)設(shè)備的條目并創(chuàng)建新表 mobile_f=table.loc[table["mobile"] == "false"] #按月匯總使用移動(dòng)設(shè)備的數(shù)據(jù) mobile_t_m=mobile_t.resample('M',how=len) #按月匯總不使用移動(dòng)設(shè)備的數(shù)據(jù) mobile_f_m=mobile_f.resample('M',how=len) #提取使用移動(dòng)設(shè)備的按月匯總nickname mobile_y=mobile_t_m['nickname'] #提取沒有使用移動(dòng)設(shè)備的按月匯總nickname mobile_n=mobile_f_m['nickname']
從結(jié)果中可以看出使用移動(dòng)設(shè)備進(jìn)行評(píng)論的用戶在所有的時(shí)間段中都要明顯高于使用PC的用戶。
#繪制PC與移動(dòng)設(shè)備評(píng)論數(shù)量變化趨勢(shì)圖 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('移動(dòng)設(shè)備評(píng)論數(shù)量') plt.title('PC與移動(dòng)設(shè)備評(píng)論數(shù)量變化趨勢(shì)') 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評(píng)論數(shù)量') plt.show()
24小時(shí)評(píng)論數(shù)量變化趨勢(shì)
按小時(shí)維度對(duì)評(píng)論數(shù)據(jù)進(jìn)行匯總,查看用戶在24小時(shí)中的評(píng)論變化趨勢(shì)。這里需要說明的是24小時(shí)趨勢(shì)只能反映用戶登錄京東商城的趨勢(shì),并不能近似推斷用戶購(gòu)買商品的時(shí)間趨勢(shì)。
#按24小時(shí)分別對(duì)table表中的nickname進(jìn)行計(jì)數(shù) hour_group=table.groupby('hour')['nickname'].agg(len)
從24小時(shí)評(píng)論趨勢(shì)圖來看,發(fā)布商品評(píng)論的趨勢(shì)與作息時(shí)間一致,并且每日的閑暇時(shí)間是發(fā)布評(píng)論的高峰。如早上的8點(diǎn),中午的12點(diǎn)和晚上的22點(diǎn),是一天24小時(shí)中的三個(gè)評(píng)論高峰點(diǎn)。
#匯總24小時(shí)評(píng)論數(shù)量變化趨勢(shì)圖 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小時(shí)') plt.ylabel('評(píng)論數(shù)量') plt.title('24小時(shí)評(píng)論數(shù)量變化趨勢(shì)') plt.legend(['評(píng)論數(shù)量'], 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小時(shí)的評(píng)論數(shù)量分為移動(dòng)設(shè)備和未使用移動(dòng)設(shè)備,查看并對(duì)比這兩者的變化趨勢(shì)情況。
#在使用移動(dòng)設(shè)備的表中按24小時(shí)對(duì)nickname進(jìn)行計(jì)數(shù) mobile_y_h=mobile_t.groupby('hour')['nickname'].agg(len) #在沒有使用移動(dòng)設(shè)備的表中按24小時(shí)對(duì)nickname進(jìn)行計(jì)算 mobile_n_h=mobile_f.groupby('hour')['nickname'].agg(len)
移動(dòng)設(shè)備的評(píng)論數(shù)量在24小時(shí)中的各個(gè)時(shí)間段都要高于PC的評(píng)論數(shù)量,并且在晚間更加活躍,持續(xù)時(shí)間高于PC端。這里我們產(chǎn)生了一個(gè)疑問,在一天中的工作時(shí)間段中,大部分用戶都會(huì)在電腦旁,但為什么這些時(shí)間段里移動(dòng)設(shè)備的評(píng)論數(shù)量也要高于PC端呢?這是否與胸罩這個(gè)產(chǎn)品的私密性有關(guān)聯(lián)。用戶不希望別人看到自己購(gòu)買的商品或評(píng)論的內(nèi)容,所以選擇使用移動(dòng)設(shè)備進(jìn)行評(píng)論?
#匯總PC與移動(dòng)設(shè)備24小時(shí)評(píng)論數(shù)量變化趨勢(shì) 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('移動(dòng)設(shè)備評(píng)論數(shù)量') plt.title('PC與移動(dòng)設(shè)備24小時(shí)評(píng)論數(shù)量變化趨勢(shì)') 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小時(shí)') plt.ylabel('PC評(píng)論數(shù)量') plt.show()
用戶客戶端分布情況
前面的分析中,我們看到使用移動(dòng)設(shè)備進(jìn)行評(píng)論的用戶要遠(yuǎn)高于PC端的用戶,下面我們對(duì)用戶所使用的設(shè)備分布情況進(jìn)行統(tǒng)計(jì)。首先在數(shù)據(jù)表中按用戶設(shè)備(userClient)對(duì)nickname字段進(jìn)行計(jì)數(shù)匯總。
#在table表中按userClient對(duì)數(shù)據(jù)進(jìn)行匯總 userClient_group=table.groupby('userClient')['nickname'].agg(len)
從用戶客戶端分布情況來看,移動(dòng)端的設(shè)備占大多數(shù),其中使用iphone的用戶要高于Android用戶。由于微信購(gòu)物和QQ購(gòu)物單獨(dú)被分了出來,無法確定設(shè)備,因此單獨(dú)進(jìn)行對(duì)比。使用微信購(gòu)物渠道的用戶要高于QQ購(gòu)物。
#匯總用戶客戶端分布情況 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('評(píng)論數(shù)量') plt.title('用戶客戶端分布情況') plt.legend(['評(píng)論數(shù)量'], 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','微信購(gòu)物','QQ購(gòu)物')) plt.show()
購(gòu)買后評(píng)論天數(shù)分布
在購(gòu)買后評(píng)論天數(shù)方面,我們將用戶發(fā)布評(píng)論與購(gòu)買的時(shí)間間隔分為7組,分別為購(gòu)買后1-5天內(nèi),5-10天內(nèi),10-15天內(nèi),15-20天內(nèi),20-25天內(nèi),25-30天內(nèi),以及大于30天。然后統(tǒng)計(jì)并對(duì)比用戶在不同時(shí)間區(qū)間內(nèi)發(fā)布評(píng)論的數(shù)量情況。
#設(shè)置分組條件,并對(duì)table表中的days字段進(jìn)行分組 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) #按新設(shè)置的分組對(duì)數(shù)據(jù)進(jìn)行匯總 days_group=table.groupby('day_group')['nickname'].agg(len)
從圖表中看出,購(gòu)買后5天以內(nèi)是用戶發(fā)布評(píng)論的高峰,也就我們之前推測(cè)評(píng)論時(shí)間趨勢(shì)近似于購(gòu)買時(shí)間的依據(jù)。隨著時(shí)間的增加評(píng)論數(shù)量逐漸下降。
#繪制用戶購(gòu)買后評(píng)論天數(shù)分布圖 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('購(gòu)買后天數(shù)') plt.ylabel('發(fā)布評(píng)論數(shù)量') plt.title('購(gòu)買后評(píng)論天數(shù)分布') plt.legend(['評(píng)論數(shù)量'], 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()
商品評(píng)分分布情況
京東商城對(duì)商品按5星評(píng)分劃分為好評(píng),中評(píng)和差評(píng)三個(gè)等級(jí)。我們這里來看下用戶5星評(píng)分的分布情況。在數(shù)據(jù)表中score字段中的值表示了用戶對(duì)胸罩產(chǎn)品的打分情況。我們按打分情況對(duì)數(shù)據(jù)進(jìn)行匯總。
#在table表中按score對(duì)數(shù)據(jù)進(jìn)行匯總 score_group=table.groupby('score')['nickname'].agg(len) #繪制用戶評(píng)分分布情況圖 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('評(píng)分分布') plt.ylabel('評(píng)論數(shù)量') plt.title('用戶評(píng)分分布情況') plt.legend(['評(píng)論數(shù)量'], 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()
從圖表中可以看出,大部分用戶對(duì)商品的評(píng)分是5星。4星以下的幾乎沒有。但從另一個(gè)維度來看,在用戶對(duì)最有用評(píng)論的投票(usefulVoteCount)中得票最多的是一個(gè)1星的評(píng)論。
用戶胸罩尺碼分布情況
在胸罩的尺寸方面包含兩個(gè)信息,一個(gè)是胸圍尺寸,另一個(gè)是罩杯。我們?cè)谇懊娴那逑催^程中對(duì)杯罩創(chuàng)建了單獨(dú)的字段。下面只對(duì)這個(gè)字段進(jìn)行匯總統(tǒng)計(jì)。
#在table 表中按cup對(duì)數(shù)據(jù)進(jìn)行匯總 cup_group=table.groupby('cup')['nickname'].agg(len)
從圖表中可以看出,評(píng)論用戶中最多的是B杯罩,其次為C杯罩,D和E的用戶數(shù)量較少。
#繪制用戶胸罩尺碼分布圖 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('評(píng)論數(shù)量') plt.title('用戶胸罩尺碼分布情況') plt.legend(['評(píng)論數(shù)量'], 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()
胸罩顏色偏好分布
這款胸罩共分為三個(gè)顏色,紅色,膚色和黑色。我們按顏色對(duì)評(píng)論數(shù)據(jù)進(jìn)行匯總,查看用戶對(duì)不同胸罩顏色的偏好情況。
#在table表中按productColor對(duì)數(shù)據(jù)進(jìn)行匯總 color_group=table.groupby('productColor')['nickname'].agg(len)
從不同顏色的評(píng)論數(shù)量上來看,大部分用戶購(gòu)買的是膚色,購(gòu)買紅色和黑色的用戶數(shù)量明顯少于膚色。
#繪制用戶顏色選擇分布圖 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('評(píng)論數(shù)量') plt.title('用戶顏色選擇分布') plt.legend(['評(píng)論數(shù)量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='y',alpha=0.4) plt.ylim(0,600) plt.xticks(a,('紅色','膚色','黑色')) plt.show()
不同尺碼用戶對(duì)胸罩顏色偏好對(duì)比
在前面杯罩尺寸和顏色偏好的基礎(chǔ)上,我們將兩維度進(jìn)行交叉分析,查看并對(duì)比不同杯罩尺碼用戶在顏色選擇上是有規(guī)律或明顯差異。這里使用數(shù)據(jù)透視表,將杯罩尺寸設(shè)置為行,顏色設(shè)置為列,對(duì)nickname進(jìn)行計(jì)數(shù)。
#使用數(shù)據(jù)透視表對(duì)胸罩尺碼和顏色進(jìn)行交叉分析 color_size=pd.pivot_table(table,index=["cup"],values=["nickname"],columns=["productColor"],aggfunc=len,fill_value=0)
從數(shù)據(jù)透視表中分別提取出不同尺寸杯罩用戶購(gòu)買的顏色數(shù)據(jù)。
#提取B,C,D,E尺碼的顏色分布 b=color_size.ix['B'] c=color_size.ix['C'] d=color_size.ix['D'] e=color_size.ix['E']
將不同杯罩尺寸用戶對(duì)顏色的選擇分布繪制成四個(gè)圖表,進(jìn)行對(duì)比和分析。
#匯總不同胸罩尺碼顏色分布圖 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四個(gè)杯罩的用戶選擇膚色的數(shù)量都要高于另外兩種顏色。整體差別并不明顯。如果非要說有什么差別的話,C杯罩用戶更偏好紅色?D杯罩更喜歡黑色?這個(gè)結(jié)論明顯站不住腳。但有一點(diǎn)可以說,雖然黑色顯瘦但E杯罩的用戶中沒有人選擇黑色。
D&E Cup用戶城市分布情況
最后我們?cè)倏纯聪翫杯罩和E杯罩用戶的城市分布情況,在數(shù)據(jù)表中并不是所有的評(píng)論都有城市信息。因此按城市統(tǒng)計(jì)出來的數(shù)據(jù)可能并不準(zhǔn)確,僅供參考。
首先從數(shù)據(jù)表中篩選出cup值為D和E的數(shù)據(jù),并保存在新的數(shù)據(jù)表中。
#從table表中提取cup尺寸為D或E的數(shù)據(jù)條目并創(chuàng)建新表 table_big=table.loc[(table["cup"] == "D")|(table["cup"] == "E")]
在新的數(shù)據(jù)表中按用戶所在城市(userProvince)進(jìn)行匯總。查看不同城市D和E杯罩的數(shù)量。
#按城市對(duì)數(shù)據(jù)進(jìn)行計(jì)數(shù)匯總 city_group=table_big.groupby('userProvince')['nickname'].agg(len)
將匯總結(jié)果繪制為圖表,從圖表來看,數(shù)量最多的為未知城市,排除未知城市,北京和廣東的數(shù)量遙遙領(lǐng)先,其次為四川和河南。
#匯總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('評(píng)論數(shù)量') plt.ylabel('城市') plt.title('D Cup和E Cup城市分布') plt.legend(['評(píng)論數(shù)量'], loc='upper right') plt.grid(color='#95a5a6',linestyle='--', linewidth=1,axis='x',alpha=0.4) plt.yticks(a,('未知','上海','云南','內(nèi)蒙古','北京','四川','天津','寧夏','安徽','山東','廣東','江西','江蘇','江西','河北','河南','浙江','湖北','湖南','甘肅','福建','遼寧','重慶','青海','香港')) plt.show()
胸罩評(píng)論內(nèi)容語義分析
前面我們分別對(duì)數(shù)據(jù)表中的字段進(jìn)行了統(tǒng)計(jì)和分析,文章最后我們對(duì)商品的評(píng)論內(nèi)容進(jìn)行語義分析,看看大家在這700+條評(píng)論中都在說些什么。
好好先生購(gòu)買比例
在人工查看了一些評(píng)論內(nèi)容后,我們發(fā)現(xiàn)一些有意思的信息。有一部分評(píng)論是老公或男朋友發(fā)的,這說明一些好好先生會(huì)幫老婆或女友購(gòu)買胸罩。那么這部分用戶的比例有多少呢?
我們把評(píng)論中包含有關(guān)鍵詞“老婆”和“女朋友”的評(píng)論單獨(dú)保存在出來。
#篩選包含”老婆”和”女朋友”的評(píng)論 content_2=[] for i in content_1: if "老婆"in i or "女朋友"in i: content_2.append(i)
查看這些包含關(guān)鍵詞的評(píng)論內(nèi)容,確實(shí)是老公和男朋友來購(gòu)買胸罩并且發(fā)布的評(píng)論。
#查看評(píng)論內(nèi)容 content_2
經(jīng)過計(jì)算,在這款胸罩產(chǎn)品的評(píng)論中,由老公或男朋友購(gòu)買的比例僅為2.35%。
#計(jì)算老公或男朋友購(gòu)買胸罩的比例 len(content_2)/len(content_1)*100 2.3545706371191137
商品評(píng)論關(guān)鍵詞分析
回歸到商品評(píng)論分析,我們使用結(jié)巴分詞對(duì)所有胸罩的評(píng)論信息進(jìn)行了分詞,并提取了權(quán)重最高的關(guān)鍵詞列表。
#文本數(shù)據(jù)格式轉(zhuǎn)換 word_str = ''.join(content_1) #提取文字關(guān)鍵詞 word_rank=jieba.analyse.extract_tags(word_str, topK=20, withWeight=True, allowPOS=()) #轉(zhuǎn)化為數(shù)據(jù)表 word_rank = pd.DataFrame(word_rank,columns=['word','rank']) #查看關(guān)鍵詞及權(quán)重 word_rank.sort('rank',ascending=False)
從高權(quán)重關(guān)鍵詞列表來看,用戶評(píng)論以正面信息為主,”不錯(cuò)”,”舒服”,”喜歡”等主觀感受的正面評(píng)論權(quán)重較高。
結(jié)語
本篇文章我們從商品評(píng)論信息的抓取,清洗到分析和數(shù)據(jù)可視化實(shí)現(xiàn)了一個(gè)完整的閉環(huán)。整個(gè)過程中數(shù)據(jù)的清洗和預(yù)處理是最為復(fù)雜也是耗時(shí)最多的工作。由于抓取的數(shù)據(jù)量較少,只有700+條數(shù)據(jù)。因此里面的一些結(jié)論可能沒有代表性,結(jié)論也未必準(zhǔn)確,僅供參考。
- Python如何爬取微信公眾號(hào)文章和評(píng)論(基于 Fiddler 抓包分析)
- 詳解用python寫網(wǎng)絡(luò)爬蟲-爬取新浪微博評(píng)論
- python爬蟲爬取微博評(píng)論案例詳解
- Python實(shí)現(xiàn)的爬取網(wǎng)易動(dòng)態(tài)評(píng)論操作示例
- Python爬取網(wǎng)易云音樂熱門評(píng)論
- python 自動(dòng)化數(shù)據(jù)提取之正則表達(dá)式
- 通過抓取淘寶評(píng)論為例講解Python爬取ajax動(dòng)態(tài)生成的數(shù)據(jù)(經(jīng)典)
- 如何基于Python爬取隱秘的角落評(píng)論
相關(guān)文章
Python OpenCV實(shí)現(xiàn)邊緣檢測(cè)
這篇文章主要為大家詳細(xì)介紹了Python OpenCV實(shí)現(xiàn)邊緣檢測(cè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08python實(shí)現(xiàn)自動(dòng)化之文件合并
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)自動(dòng)化文件合并,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Python Pygame實(shí)戰(zhàn)之趣味籃球游戲的實(shí)現(xiàn)
這篇文章主要為大家分享了一個(gè)基于Python和Pygame實(shí)現(xiàn)的一個(gè)趣味籃球游戲,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定幫助,需要的可以參考一下2022-04-04Python 多個(gè)圖同時(shí)在不同窗口顯示的實(shí)現(xiàn)方法
今天小編就為大家分享一篇Python 多個(gè)圖同時(shí)在不同窗口顯示的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07Python3.7+tkinter實(shí)現(xiàn)查詢界面功能
這篇文章主要介紹了Python3.7+tkinter實(shí)現(xiàn)查詢界面功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12Python編寫春聯(lián)的示例代碼(支持行書隸書楷書)
這篇文章主要介紹了如何通過Python代碼編寫春聯(lián),其中春聯(lián)字體支持行書隸書楷書。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動(dòng)手試一試2022-01-01Django ORM框架的定時(shí)任務(wù)如何使用詳解
這篇文章主要給大家介紹了關(guān)于Django ORM框架的定時(shí)任務(wù)如何使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用django具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10對(duì)python數(shù)據(jù)清洗容易遇到的函數(shù)-re.sub bytes string詳解
今天小編就為大家分享一篇對(duì)python數(shù)據(jù)清洗容易遇到的函數(shù)-re.sub bytes string詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07