Python網路爬蟲實戰:根據天貓胸罩銷售資料分析中國女性胸部大小分佈
本文實現一個非常有趣的專案,這個專案是關於胸罩銷售資料分析的。是網路爬蟲和資料分析的綜合應用專案。本專案會從天貓抓取胸罩銷售資料,並將這些資料儲存到SQLite資料庫中,然後對資料進行清洗,最後通過SQL語句、Pandas和Matplotlib對資料進行資料視覺化分析。我們從分析結果中可以得出很多有的結果,例如,中國女性胸部標準尺寸是多少;胸罩上胸圍的銷售比例;哪個顏色的胸罩最受女性歡迎。
1. 專案效果展示
本專案涉及到網路技術、網路爬蟲技術、資料庫技術、資料分析技術、資料視覺化技術。首先應該執行tmallbra.py指令碼檔案從天貓抓取胸罩銷售資料,並將這些資料儲存到SQLite資料庫中。接下來可以執行analyze目錄中的相應Python指令碼檔案進行視覺化資料分析。下面是一些分析結果展示。
圖1:ABCD罩杯胸罩銷售比例
圖2:胸罩銷售比例(罩杯和上胸圍綜合指標)
圖3:胸罩銷售比例(按顏色分析)
圖4:罩杯和下胸圍分佈直方圖
其實Google和淘寶也給出了類似的分析結果。Google曾給出了一幅世界女性胸部尺寸分佈地圖 ,從地圖中可以明顯看出中國大部分地區呈現綠色(表示平均胸部尺寸為A罩杯),少部分地區呈現藍色(表示平均胸部尺寸為B罩杯),這也基本驗證了圖2所示的統計結果:中國大部分女性胸部尺寸是75B和75A。
再看一下淘寶給出的胸罩(按罩杯和上胸圍統計)銷售比例柱狀圖。
圖5:淘寶胸罩銷售比例柱狀圖(按罩杯和上胸圍統計)
從淘寶給出的資料可以看出,銷售最好的胸罩尺寸是75B,這個統計結果雖然銷售比例不同(取的樣本不同而導致的),但按銷售資料排行,這個分析結果與本專案的統計結果(圖2)基本吻合。
2. 天貓胸罩銷售資料分析
這裡的銷售資料其實就是評論資料。使用者購買一件商品併發了評論,就會記錄銷售資料。分析銷售資料的第一步就是要搞明白資料是怎麼跑到客戶端瀏覽器上的。通常來講,瀏覽器從服務端獲取資料有兩種方式:同步和非同步。同步就是資料隨HTML程式碼一同傳送到客戶端,不過現在的大型網站很少有用同步方式傳輸資料了。非同步方式是HTML程式碼與資料分別傳送到客戶端,資料一般是JSON格式,通過AJAX技術獲取,然後再使用JS將獲取到的資料顯示在HTML中的元素上。不過有時會加一些反爬蟲技術,或處於其他目的,非同步資料可能並不是純的JSON格式,例如,有可能是一段JavaScript程式碼,或在JSON格式資料中加一些其他的內容。不過這些基本都沒用,加的內容肯定是有規律的,否則自己的程式都無法讀了。
現在進到天貓商城官網https://www.tmall.com,在搜尋框輸入“胸罩”,點選“搜尋”按鈕進行搜尋。隨便找一個銷售胸罩的店鋪點進去。然後在頁面的右鍵選單中點選“檢查”選單項,開啟除錯視窗,切換到“Network”標籤頁。接下來檢視商品的評論,會在“Network”標籤頁顯示評論資訊要訪問的Url。在上方的搜尋框輸入“list_detail”,會列出所有已“list_detail”作為字首的Url。這些Url就是用AJAX非同步獲取的評論資料。點選某個Url,會在右側顯示如圖6所示的資料,很明顯,這些資料與JSON非常像,不過加了一些字首以及其他資訊,估計是要滿足一些特殊需要。
圖6:天貓評論資料
在返回的評論資料中,rateList就是我們需要的資訊,rateList列表中一共是20個物件,包含了20條評論資料,也就是說,通過這個Url,每次返回了20條評論資料。
在Url中還有兩個HTTP GET請求欄位對我們有用。
• itemId:當前商品的ID,通過這個欄位,可以獲得指定商品的評論數
據(不光是胸罩)。
• currentPage:當前的頁碼,從1開始。通過這個欄位,可以獲得更多的評論資料。
3.抓取天貓胸罩銷售資料
既然對天貓胸罩的評論資料的來源已經非常清楚了,本節就抓取這些資料。在tmallbra.py指令碼檔案中有一個核心函式,用於抓取指定商品的某一頁評論資料。
def getRateDetail(itemId,currentPage): # Url最後的callback欄位是用於天貓網站內部回撥的,和我們沒關係,不過這個欄位的值關係到 # 返回資料的字首,我們可以利用這個值去擷取返回資料 url = 'https://rate.tmall.com/list_detail_rate.htm?itemId=' + str(itemId) + '&spuId=837695373&sellerId=3075989694ℴ=3¤tPage=' + str(currentPage) + '&append=0... ...&callback=jsonp1278' r = http.request('GET',url,headers = headers) # 返回資料時GB18030編碼,所以要用這個編碼格式進行解碼 c = r.data.decode('GB18030') # 下面的程式碼將返回的評論資料轉換為JSON格式 c = c.replace('jsonp1278(','') c = c.replace(')','') c = c.replace('false','"false"') c = c.replace('true','"true"') # 將JSON格式的評論資料轉換為字典物件 tmalljson = json.loads(c) return tmalljson
4. 抓取胸罩商品列表
應用讓爬蟲自動選取胸罩商品,而不是我們一個一個挑。所以可以利用如下的天貓商城的搜尋頁面Url進行搜尋,按銷量從大到小排列。
https://list.tmall.com/search_product.htm ... ...
這個Url不需要傳遞任何引數,本專案只取第一個商品頁的所有商品。在tmallbra.py指令碼檔案中有一個而核心函式getProductIdList,用於返回第一個商品頁的所有商品ID(以列表形式返回)。
def getProductIdList(): url = 'https://list.tmall.com/search_product.htm... ...' r = http.request('GET', url,headers = headers) c = r.data.decode('GB18030') soup = BeautifulSoup(c,'lxml') linkList = [] idList = [] # 用Beautiful Soup提取商品頁面中所有的商品ID tags = soup.find_all(href=re.compile('detail.tmall.com/item.htm')) for tag in tags: linkList.append(tag['href']) linkList = list(set(linkList)) for link in linkList: aList = link.split('&') # //detail.tmall.com/item.htm?id=562173686340 # 將商品ID新增到列表中 idList.append(aList[0].replace('//detail.tmall.com/item.htm?id=','')) return idList
4.將抓取的銷售資料儲存到SQLite資料庫中
剩下的工作就很簡單了,只需要對商品ID列表迭代,然後對每一個商品的評論資料進行抓取,天貓每個商品最多可以獲得99頁評論,最大評論頁數可以通過getLastPage函式獲得。
def getLastPage(itemId): tmalljson = getRateDetail(itemId,1) return tmalljson['rateDetail']['paginator']['lastPage']
下面的程式碼會抓取商品搜尋第一頁的所有胸罩商品的評論資料,並將這些資料儲存到SQLite資料庫中。
# 對商品ID進行迭代 while initial < len(productIdList): try: itemId = productIdList[initial] print('----------',itemId,'------------') maxnum = getLastPage(itemId) num = 1 while num <= maxnum: try: # 抓取某個商品的某頁評論資料 tmalljson = getRateDetail(itemId, num) rateList = tmalljson['rateDetail']['rateList'] n = 0 while n < len(rateList): # 顏色分類:H007淺藍色加粉色;尺碼:32/70A colorSize = rateList[n]['auctionSku'] m = re.split('[:;]',colorSize) rateContent = rateList[n]['rateContent'] color = m[1] size = m[3] dtime = rateList[n]['rateDate'] # 將抓取的資料儲存到SQLite資料庫中 cursor.execute('''insert into t_sales(color,size,source,discuss,time) values('%s','%s','%s','%s','%s') ''' % (color,size,'天貓',rateContent,dtime)) conn.commit() n += 1 print(color) print(num) num += 1 except Exception as e: continue initial += 1 except Exception as e: print(e)
5. 資料清洗
如果讀者使用前面介紹的方法從天貓和京東抓取了胸罩銷售資料,現在我們已經有了一個SQLite資料庫,裡面有一個t_sales表,儲存了所有抓取的資料,如圖31-8所示。
從銷售資料可以看出,網路爬蟲抓取了顏色(color)、尺寸(size)、來源(source)、評論(discuss)和時間(time)五類資料。當然還可以抓取更多的資料,這裡只為了演示資料分析的方法,所以並沒有抓取那麼多的資料。
不過這五類資料有些不規範,本專案值考慮color和size,所以先要對這兩類資料進行清洗。由於每個店鋪,每個商品的顏色叫法可能不同,所以需要將這些顏色值統一一下。例如,所有包含“黑”的顏色值都可以認為是黑色。所以可以新建立一個color1欄位(儘量不要修改原始資料),將清洗後的顏色值儲存到color1欄位中。然後可以使用下面的SQL語句對顏色值進行清洗。
update t_salesset color1 = '黑色'where color like '%黑%' ; update t_salesset color1 = '綠色'where color like '%綠%' ; update t_salesset color1 = '紅色'where color like '%紅%' ; update t_salesset color1 = '白色'where color like '%白%' ; update t_salesset color1 = '藍色'where color like '%藍%' ; update t_salesset color1 = '粉色'where color like '%粉%'and color1 is null ; update t_salesset color1 = '青色'where color like '%青%' ; update t_salesset color1 = '卡其色'where color like '%卡其%' ; update t_salesset color1 = '紫色'where color like '%紫%' ; update t_salesset color1 = '膚色'where color like '%膚%' ; update t_salesset color1 = '水晶蝦'where color like '%水晶蝦%' ; update t_salesset color1 = '玫瑰色'where color like '%玫瑰%' ; update t_salesset color1 = '銀灰'where color like '%銀灰%' ;
胸罩尺寸清洗的方式與胸罩顏色類似,大家可以自己通過SQL語句去完成。
清洗完的結果如圖7所示。
圖7:清洗後的資料
6. 用SQL語句分析胸罩(按罩杯尺寸)的銷售比例
既然銷售資料都儲存在SQLite資料庫中,那麼我們不妨先用SQL語句做一下統計分析。本節將對胸罩按罩杯的銷售量做一個銷售比例統計分析。由於抓取的資料沒有超過D罩杯的,所以做資料分析時就不考慮D以上罩杯的胸罩銷售資料了。這裡只考慮A、B、C和D罩杯胸罩的銷售資料。
本節要統計的是某一個尺寸的胸罩銷售數量佔整個銷售數量的百分比,這裡需要統計和計算如下3類資料。
• 某一個尺寸的胸罩銷售數量。
• 胸罩銷售總數量
• 第1類資料和第2類資料的差值(百分比)
這3類資料完全可以用一條SQL語句搞定,為了同時搞定A、B、C和D罩杯的銷售比例,可以用4條類似的SQL語句,中間用union all連線。
select 'A' as 罩杯,printf("%.2f%%",(100.0 * count(*)/ (select count(*) from t_saleswhere size1 is not null)))as 比例, count(*) as 銷量 from t_sales where size1='A' union all select 'B',printf("%.2f%%",(100.0 * count(*)/ (select count(*) from t_saleswhere size1 is not null))) , count(*) as c from t_sales where size1='B' union all select 'C',printf("%0.2f%%",(100.0 * count(*)/ (select count(*) from t_saleswhere size1 is not null))) , count(*) as c from t_sales where size1='C' union all select 'D',printf("%.2f%%",(100.0 * count(*)/ (select count(*) from t_saleswhere size1 is not null))) , count(*) as c from t_sales where size1='D' order by 銷量 desc
上面的SQL語句不僅加入了銷售比例,還加入了銷售數量,並且按銷量降序排列。這些SQL語句需要考慮size1欄位空值的情況,因為抓取的少部分銷售記錄並沒有罩杯尺寸資料。執行上面的SQL語句後,會輸出如圖8所示的查詢結果。
圖8:用SQL語句統計胸罩(按罩杯尺寸)銷售比例
其他的銷售資料的分析類似。
7. 用Pandas和Matplotlib分析對胸罩銷售比例進行視覺化分析
既然Python提供了這麼好的Pandas和Matplotlib,那麼就可以完全不使用SQL語句進行資料分析了。可以100%使用Python程式碼搞定一切。
本節將使用Pandas完成與上一節相同的資料分析,並使用Matplotlib將分析結果以圖形化方式展現出來。
Pandas在前面的章節已經講過了,這裡不再深入介紹。本次分析主要使用了groupby方法按罩杯(size1)分組,然後使用count方法統計組內數量,最後使用insert方法添加了一個“比例”欄位。
from pandas import * from matplotlib.pyplot import * import sqlite3 import sqlalchemy # 開啟bra.sqlite資料庫 engine = sqlalchemy.create_engine('sqlite:///bra.sqlite') rcParams['font.sans-serif'] = ['SimHei'] # 查詢t_sales表中所有的資料 sales = read_sql('select source,size1 from t_sales',engine) # 對size1進行分組,並統計每一組的記錄數 size1Count = sales.groupby('size1')['size1'].count() print(size1Count) # 計算總銷售數量 size1Total = size1Count.sum() print(size1Total) print(type(size1Count)) # 將Series轉換為DataFrame size1 = size1Count.to_frame(name='銷量') print(size1) # 格式化浮點數 options.display.float_format = '{:,.2f}%'.format # 插入新的“比例”列 size1.insert(0,'比例', 100 * size1Count / size1Total) print(size1) # 將索引名改為“罩杯” size1.index.names=['罩杯'] print(size1) # 資料視覺化 print(size1['銷量']) # 餅圖要顯示的文字 labels = ['A罩杯','B罩杯','C罩杯','D罩杯'] # 用餅圖繪製銷售比例 size1['銷量'].plot(kind='pie',labels = labels, autopct='%.2f%%') # 設定長寬相同 axis('equal') legend() show()
執行程式,會看到在視窗上繪製瞭如圖9所示的胸罩銷售比例。用Pandas分析得到的資料與使用SQL分析得到的資料完全相同。
圖9:胸罩銷售比例(按罩杯尺寸)
其他分析也可以使用Pandas,視覺化使用Matplotlib。這兩個工具真是個強大的東西。祝大家學習愉快