(一)選題的背景
隨着電商的迅速發展,越來越多的商家都會選擇在電商網站銷售農產品,其中在電商平台賣茶葉就是一個成功的案例。茶葉作為一種天然的健康飲品,具有悠久的消費歷史和廣大的消費群體。近年來,隨着人們生活水平的不斷提高,對健康的重視程度日益上升。飲茶作為一種健康的生活習慣,符合現階段消費者對健康和高品質生活的追求。並且近年來,我國茶產業快速發展,一二三產業融合推進,呈現出良好的發展勢頭。中國是茶的故鄉,也是茶葉生產大國。中國茶葉生產快速發展,茶葉種植面積擴大,茶葉產量不斷增長,茶葉買賣前景一片光明。本文通過爬取淘寶茶葉的商品相關信息,並根據爬取到數據做數據分析,得出有效的結論,為消費者和商家的茶葉購買或銷售提出可行的建議。
(二)主題式網絡爬蟲的設計方案
本文的主題式網絡爬蟲名稱為“淘寶茶葉商品信息爬取與數據分析”,主要爬取的內容包括商品的標題、銷售地、銷售量、評論數量、銷售價格、店鋪名稱、商品唯一標識ID以及詳情頁網址等信息。爬取方式選擇selenium自動化采集的方法,使用到的Python包有time、selenium、base64和threading,pandas,requests和re,技術難點在於淘寶商品信息的分析和解析部分。爬取過程設計如下圖:
(三)數據頁面的結構特征分析
打開淘寶網站,在搜索框輸入“茶葉”,然后右鍵檢查,可以看到如下的網頁結構:
很明顯,網頁結構較為復雜,不適於用xpath解析,所以本文選擇正則表達式re庫來解析。方法是選用鼠標定位到需要的商品信息,可以直接復制element到代碼中修改,得到需要的數據,如圖:
(一)網絡爬蟲程序設計
- 數據爬取與采集
數據采集代碼如下:
1 from selenium import webdriver 2 import time 3 from PIL import Image 4 import base64 5 import threading 6 import pandas as pd 7 import requests 8 import re 9 10 11 # 定義爬蟲配置參數 12 headers = {'Host':'s.taobao.com', 13 'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0', 14 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 15 'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 16 'Accept-Encoding':'gzip, deflate, br', 17 'Connection':'keep-alive'} 18 list_url = 'http://s.taobao.com/search?q=%(key)s&ie=utf8&s=%(page)d' # 對應頁數 19 20 # 打開登錄二維碼圖片 21 def open_img(img_location): 22 img=Image.open(img_location) 23 img.show() 24 25 # 登陸獲取cookies 26 def login(): 27 driver = webdriver.Chrome() 28 driver.get('https://login.taobao.com/member/login.jhtml') 29 try: 30 driver.find_element_by_xpath('//*[@id="login"]/div[1]/i').click() 31 except: 32 pass 33 time.sleep(3) 34 # 執行JS獲得canvas的二維碼 35 JS = 'return document.getElementsByTagName("canvas")[0].toDataURL("image/png");' 36 im_info = driver.execute_script(JS) # 執行JS獲取圖片信息 37 im_base64 = im_info.split(',')[1] # 拿到base64編碼的圖片信息 38 im_bytes = base64.b64decode(im_base64) # 轉為bytes類型 39 time.sleep(2) 40 with open('./login.png','wb') as f: 41 f.write(im_bytes) 42 f.close() 43 t = threading.Thread(target=open_img,args=('./login.png',)) 44 t.start() 45 print("正在轉碼中,請稍后!\n") 46 while(True): 47 c = driver.get_cookies() 48 if len(c) > 20: # 登陸成功獲取到cookies 49 cookies = {} 50 for i in range(len(c)): 51 cookies[c[i]['name']] = c[i]['value'] 52 driver.close() 53 print("登錄成功,正在開啟爬蟲!\n") 54 return cookies 55 time.sleep(1) 56 57 def run(): 58 # 正則匹配模式,獲取所需數據 59 p_title = '"raw_title":"(.*?)"' # 標題 60 p_location = '"item_loc":"(.*?)"' # 銷售地 61 p_sale = '"view_sales":"(.*?)人付款"' # 銷售量 62 p_comment = '"comment_count":"(.*?)"' # 評論數 63 p_price = '"view_price":"(.*?)"' # 銷售價格 64 p_nick = '"nick":"(.*?)"' # 店鋪名稱 65 p_nid = '"nid":"(.*?)"' # 商品id 66 p_url = '"pic_url":"(.*?)"' # 商品網址 67 68 # 數據爬取 69 key = input('請輸入商品名稱:') # 商品的關鍵詞 70 N = 100 # 爬取的頁數 71 data = [] 72 cookies = login() # 得到登錄的cookies 73 for i in range(N): 74 try: 75 page = i*44 76 url = list_url%{'key':key,'page':page} 77 res = requests.get(url,headers=headers,cookies=cookies) 78 html = res.text 79 title = re.findall(p_title,html) 80 location = re.findall(p_location,html) 81 sale = re.findall(p_sale,html) 82 comment = re.findall(p_comment,html) 83 price = re.findall(p_price,html) 84 nick = re.findall(p_nick, html) 85 nid = str(re.findall(p_nid,html)) 86 ourl = re.findall(p_url, html) 87 for j in range(len(title)): 88 # 持久化數據 89 content = [title[j], location[j], sale[j], comment[j], price[j], nick[j], nid[j], ourl[j]] 90 print(content) 91 data.append(content) 92 print(f'=====已爬取完第{i+1}頁=====') 93 time.sleep(3) 94 except: 95 pass 96 # 使用pandas保存數據,使數據持久化 97 data = pd.DataFrame(data, columns=['標題','發貨地','銷量','評論數','價格','店鋪名稱','商品ID', '詳情頁網址']) 98 data.to_csv(f'淘寶{key}信息.csv',encoding='utf-8-sig',index=False) 99 print('淘寶商品數據已完成爬取並保存') 100 101 102 if __name__ == '__main__': 103 run()
運行結果:
2.對數據進行清洗與處理
2.1 數據探索:
1 # 導入所需包 2 import pandas as pd 3 import pandas as pd 4 import numpy as np 5 import matplotlib.pyplot as plt 6 from sklearn.linear_model import LinearRegression 7 8 df = pd.read_csv('淘寶茶葉信息.csv') 9 df.head()
運行結果:
2.2 數據清洗:
1 df.dropna(inplace=True) 2 df.reset_index(drop=True, inplace=True) 3 4 # 刪除臟數據后的數據信息 5 df.info()
運行結果:
2.3 銷售量數據清洗:
1 sales = [] 2 for p in df['銷量'].values: 3 if '萬' in p: 4 sales.append(int(p.split('萬')[0]) * 10000) 5 elif '+' in p: 6 sales.append(int(p[:-1])) 7 else: 8 sales.append(int(p)) 9 df['銷量'] = sales 10 df['銷量'] = df['銷量'].astype(int)
運行結果:
3.數據分析與可視化
3.1 淘寶茶葉發貨地條形圖
1 plt.figure(figsize=(25, 10)) 2 address = df['發貨地'].value_counts() 3 plt.bar(address.index[:15], address.values[:15], facecolor='yellow') 4 # 顯示橫軸標簽 5 plt.xlabel('發貨地', fontsize=18) 6 # 顯示縱軸標簽 7 plt.ylabel('數量', fontsize=18) 8 # 顯示圖標題 9 plt.xticks(fontsize=15) 10 plt.yticks(fontsize=15) 11 for i, j in zip(address.index[:15], address.values[:15]): 12 plt.text(i, j, j, va='bottom', ha='center', fontsize=15, color='red') 13 plt.title('淘寶茶葉發貨地條形圖', fontsize=25) 14 plt.savefig('淘寶茶葉發貨地條形圖.png') 15 plt.show()
運行結果:
可以發現,發貨地最多的是在廣東,其中廣告潮州居多,廣州和汕頭分別在第三和第四位。
3.2 淘寶茶葉銷量直方圖
1 plt.figure(figsize=(12, 8)) 2 plt.hist(df['銷量'], bins=10, facecolor='red', edgecolor='black') 3 # 顯示橫軸標簽 4 plt.xlabel('銷量區間') 5 # 顯示縱軸標簽 6 plt.ylabel('頻數/頻率') 7 # 顯示圖標題 8 plt.title('淘寶茶葉銷量頻數/頻率分布直方圖') 9 plt.savefig('淘寶茶葉銷量頻數頻率分布直方圖.png') 10 plt.show()
運行結果:
銷量集中在0-30000,其中15000以下居多。
3.3 淘寶茶葉評論數量直方圖
plt.figure(figsize=(12, 8)) plt.hist(df['評論數'], bins=20, facecolor='red', edgecolor='black') # 顯示橫軸標簽 plt.xlabel('評論數量區間') # 顯示縱軸標簽 plt.ylabel('頻數/頻率') # 顯示圖標題 plt.title('淘寶茶葉評論數量頻數/頻率分布直方圖') plt.savefig('淘寶茶葉評論數量數頻率分布直方圖.png') plt.show()
運行結果:
淘寶茶葉評論數量集中在50000以下。
3.4 淘寶茶葉價格直方圖
1 plt.figure(figsize=(12, 8)) 2 plt.hist(df['價格'], bins=20, facecolor='red', edgecolor='black') 3 # 顯示橫軸標簽 4 plt.xlabel('評論數量區間') 5 # 顯示縱軸標簽 6 plt.ylabel('頻數/頻率') 7 # 顯示圖標題 8 plt.title('淘寶茶葉價格頻數/頻率分布直方圖') 9 plt.savefig('淘寶茶葉價格數頻率分布直方圖.png') 10 plt.show()
運行結果:
淘寶茶葉價格集中在0-400元之間。
4.淘寶茶葉銷量與價格和評論數和之間的線性回歸模型
4.1 淘寶茶葉銷量與評論數量的散點圖
1 plt.figure(figsize=(15, 8)) 2 plt.scatter(df['銷量'], df['評論數'],facecolor='green', edgecolor='black') 3 # 顯示橫軸標簽 4 plt.xlabel('銷量', fontsize=18) 5 # 顯示縱軸標簽 6 plt.ylabel('評論數量', fontsize=18) 7 # 顯示圖標題 8 plt.xticks(fontsize=12) 9 plt.yticks(fontsize=15) 10 plt.title('淘寶茶葉銷量與評論數量的散點圖', fontsize=25) 11 plt.savefig('淘寶茶葉銷量與評論數量的散點圖.png') 12 plt.show()
運行結果:
4.2 淘寶茶葉銷量與價格的散點圖
1 plt.figure(figsize=(15, 8)) 2 plt.scatter(df['銷量'], df['價格'],facecolor='green', edgecolor='black') 3 # 顯示橫軸標簽 4 plt.xlabel('銷量', fontsize=18) 5 # 顯示縱軸標簽 6 plt.ylabel('價格', fontsize=18) 7 # 顯示圖標題 8 plt.xticks(fontsize=12) 9 plt.yticks(fontsize=15) 10 plt.title('淘寶茶葉銷量與價格的散點圖', fontsize=25) 11 plt.savefig('淘寶茶葉銷量與價格價格的散點圖.png') 12 plt.show()
運行結果:
由以上的兩個散點圖分析可知,淘寶茶葉的銷量與價格是存在相關關系的,但銷量與評論數不存在明顯的相關關系,下面構建淘寶茶葉的銷量與價格的一元線性回歸方程。
1 model = LinearRegression() 2 model.fit(np.array(df['銷量'].values).reshape(-1, 1), np.array(df['價格'].values).reshape(-1, 1))
運行結果:
由此可以得到淘寶茶葉銷量與價格之間的一線回歸模型方程為:
y=213.74771645 - 0.0050832x
以上回國方程說明說明隨着淘寶茶葉的價格的升高,銷量就會趨於減少。
5.數據持久化
1 # 使用pandas保存數據,使數據持久化 2 data = pd.DataFrame(data, columns=['標題','發貨地','銷量','評論數','價格','店鋪名稱','商品ID', '詳情頁網址']) 3 data.to_csv(f'淘寶{key}信息.csv',encoding='utf-8-sig',index=False) 4 print('淘寶商品數據已完成爬取並保存') 5 6 7 if __name__ == '__main__': 8 run()
運行結果:
6.將以上各部分的代碼匯總,附上完整程序代碼
1 from selenium import webdriver 2 import time 3 from PIL import Image 4 import base64 5 import threading 6 import pandas as pd 7 import requests 8 import re 9 10 11 12 13 14 # 定義爬蟲配置參數 15 16 17 headers = {'Host':'s.taobao.com', 18 'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0', 19 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 20 'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 21 'Accept-Encoding':'gzip, deflate, br', 22 'Connection':'keep-alive'} 23 list_url = 'http://s.taobao.com/search?q=%(key)s&ie=utf8&s=%(page)d' # 對應頁數 24 25 26 27 28 # 打開登錄二維碼圖片 29 30 31 def open_img(img_location): 32 img=Image.open(img_location) 33 img.show() 34 35 36 37 38 39 # 登陸獲取cookies 40 41 42 def login(): 43 driver = webdriver.Chrome() 44 driver.get('https://login.taobao.com/member/login.jhtml') 45 try: 46 driver.find_element_by_xpath('//*[@id="login"]/div[1]/i').click() 47 except: 48 pass 49 time.sleep(3) 50 51 # 執行JS獲得canvas的二維碼 52 53 54 JS = 'return document.getElementsByTagName("canvas")[0].toDataURL("image/png");' 55 56 im_info = driver.execute_script(JS) # 執行JS獲取圖片信息 57 58 im_base64 = im_info.split(',')[1] # 拿到base64編碼的圖片信息 59 60 im_bytes = base64.b64decode(im_base64) # 轉為bytes類型 61 62 time.sleep(2) 63 with open('./login.png','wb') as f: 64 f.write(im_bytes) 65 f.close() 66 t = threading.Thread(target=open_img,args=('./login.png',)) 67 t.start() 68 print("正在轉碼中,請稍后!\n") 69 while(True): 70 c = driver.get_cookies() 71 72 if len(c) > 20: # 登陸成功獲取到cookies 73 74 cookies = {} 75 for i in range(len(c)): 76 cookies[c[i]['name']] = c[i]['value'] 77 driver.close() 78 print("登錄成功,正在開啟爬蟲!\n") 79 return cookies 80 time.sleep(1) 81 82 83 84 def run(): 85 86 # 正則匹配模式,獲取所需數據 87 88 89 p_title = '"raw_title":"(.*?)"' # 標題 90 91 p_location = '"item_loc":"(.*?)"' # 銷售地 92 93 p_sale = '"view_sales":"(.*?)人付款"' # 銷售量 94 95 p_comment = '"comment_count":"(.*?)"' # 評論數 96 97 p_price = '"view_price":"(.*?)"' # 銷售價格 98 99 p_nick = '"nick":"(.*?)"' # 店鋪名稱 100 101 p_nid = '"nid":"(.*?)"' # 商品id 102 103 p_url = '"pic_url":"(.*?)"' # 商品網址 104 105 106 # 數據爬取 107 108 109 key = input('請輸入商品名稱:') # 商品的關鍵詞 110 111 N = 100 # 爬取的頁數 112 113 data = [] 114 115 cookies = login() # 得到登錄的cookies 116 117 for i in range(N): 118 try: 119 page = i*44 120 url = list_url%{'key':key,'page':page} 121 res = requests.get(url,headers=headers,cookies=cookies) 122 html = res.text 123 title = re.findall(p_title,html) 124 location = re.findall(p_location,html) 125 sale = re.findall(p_sale,html) 126 comment = re.findall(p_comment,html) 127 price = re.findall(p_price,html) 128 nick = re.findall(p_nick, html) 129 nid = str(re.findall(p_nid,html)) 130 ourl = re.findall(p_url, html) 131 for j in range(len(title)): 132 133 # 持久化數據 134 135 136 content = [title[j], location[j], sale[j], comment[j], price[j], nick[j], nid[j], ourl[j]] 137 print(content) 138 data.append(content) 139 print(f'=====已爬取完第{i+1}頁=====') 140 time.sleep(3) 141 except: 142 pass 143 144 # 使用pandas保存數據,使數據持久化 145 146 147 data = pd.DataFrame(data, columns=['標題','發貨地','銷量','評論數','價格','店鋪名稱','商品ID', '詳情頁網址']) 148 data.to_csv(f'淘寶{key}信息.csv',encoding='utf-8-sig',index=False) 149 print('淘寶商品數據已完成爬取並保存') 150 151 152 if __name__ == '__main__': 153 run() 154 155 156 157 158 159 # 導入所需包 160 161 import pandas as pd 162 import pandas as pd 163 import numpy as np 164 import matplotlib.pyplot as plt 165 from sklearn.linear_model import LinearRegression 166 167 df = pd.read_csv('淘寶茶葉信息.csv') 168 df.head() 169 170 171 172 df.dropna(inplace=True) 173 df.reset_index(drop=True, inplace=True) 174 175 # 刪除臟數據后的數據信息 176 177 178 df.info() 179 180 181 182 sales = [] 183 for p in df['銷量'].values: 184 if '萬' in p: 185 sales.append(int(p.split('萬')[0]) * 10000) 186 elif '+' in p: 187 sales.append(int(p[:-1])) 188 else: 189 sales.append(int(p)) 190 df['銷量'] = sales 191 df['銷量'] = df['銷量'].astype(int) 192 193 194 195 196 197 198 plt.figure(figsize=(25, 10)) 199 address = df['發貨地'].value_counts() 200 plt.bar(address.index[:15], address.values[:15], facecolor='yellow') 201 202 # 顯示橫軸標簽 203 204 205 plt.xlabel('發貨地', fontsize=18) 206 207 # 顯示縱軸標簽 208 209 210 plt.ylabel('數量', fontsize=18) 211 212 # 顯示圖標題 213 214 215 plt.xticks(fontsize=15) 216 plt.yticks(fontsize=15) 217 for i, j in zip(address.index[:15], address.values[:15]): 218 plt.text(i, j, j, va='bottom', ha='center', fontsize=15, color='red') 219 plt.title('淘寶茶葉發貨地條形圖', fontsize=25) 220 plt.savefig('淘寶茶葉發貨地條形圖.png') 221 plt.show() 222 223 224 225 226 plt.figure(figsize=(12, 8)) 227 plt.hist(df['銷量'], bins=10, facecolor='red', edgecolor='black') 228 229 # 顯示橫軸標簽 230 231 232 plt.xlabel('銷量區間') 233 234 # 顯示縱軸標簽 235 236 237 plt.ylabel('頻數/頻率') 238 239 # 顯示圖標題 240 241 242 plt.title('淘寶茶葉銷量頻數/頻率分布直方圖') 243 plt.savefig('淘寶茶葉銷量頻數頻率分布直方圖.png') 244 plt.show() 245 246 247 248 plt.figure(figsize=(12, 8)) 249 plt.hist(df['評論數'], bins=20, facecolor='red', edgecolor='black') 250 251 # 顯示橫軸標簽 252 253 254 plt.xlabel('評論數量區間') 255 256 # 顯示縱軸標簽 257 258 259 plt.ylabel('頻數/頻率') 260 261 # 顯示圖標題 262 263 264 plt.title('淘寶茶葉評論數量頻數/頻率分布直方圖') 265 plt.savefig('淘寶茶葉評論數量數頻率分布直方圖.png') 266 plt.show() 267 268 269 270 plt.figure(figsize=(12, 8)) 271 plt.hist(df['價格'], bins=20, facecolor='red', edgecolor='black') 272 273 # 顯示橫軸標簽 274 275 276 plt.xlabel('評論數量區間') 277 278 # 顯示縱軸標簽 279 280 281 plt.ylabel('頻數/頻率') 282 283 # 顯示圖標題 284 285 286 plt.title('淘寶茶葉價格頻數/頻率分布直方圖') 287 plt.savefig('淘寶茶葉價格數頻率分布直方圖.png') 288 plt.show() 289 290 291 292 293 294 295 plt.figure(figsize=(15, 8)) 296 plt.scatter(df['銷量'], df['評論數'],facecolor='green', edgecolor='black') 297 298 # 顯示橫軸標簽 299 300 301 plt.xlabel('銷量', fontsize=18) 302 303 # 顯示縱軸標簽 304 305 306 plt.ylabel('評論數量', fontsize=18) 307 308 # 顯示圖標題 309 310 311 plt.xticks(fontsize=12) 312 plt.yticks(fontsize=15) 313 plt.title('淘寶茶葉銷量與評論數量的散點圖', fontsize=25) 314 plt.savefig('淘寶茶葉銷量與評論數量的散點圖.png') 315 plt.show() 316 317 318 319 plt.figure(figsize=(15, 8)) 320 plt.scatter(df['銷量'], df['價格'],facecolor='green', edgecolor='black') 321 322 # 顯示橫軸標簽 323 324 325 plt.xlabel('銷量', fontsize=18) 326 327 # 顯示縱軸標簽 328 329 330 plt.ylabel('價格', fontsize=18) 331 332 # 顯示圖標題 333 334 335 plt.xticks(fontsize=12) 336 plt.yticks(fontsize=15) 337 plt.title('淘寶茶葉銷量與價格的散點圖', fontsize=25) 338 plt.savefig('淘寶茶葉銷量與價格價格的散點圖.png') 339 plt.show() 340 341 342 343 344 345 model = LinearRegression() 346 model.fit(np.array(df['銷量'].values).reshape(-1, 1), np.array(df['價格'].values).reshape(-1, 1))
(五)總結
1.經過對主題數據的分析與可視化(對淘寶茶葉數據做的相關數據分析),可以得出以下結論:
- 淘寶茶葉發貨地最多的是在廣東,其中廣告潮州居多,廣州和汕頭分別在第三和第四位。
- 淘寶茶葉銷量集中在0-30000,其中15000以下居多。
- 淘寶茶葉評論數量集中在50000以下。
- 淘寶茶葉價格集中在0-400元之間。
- 隨着茶葉價格的增加,銷量會減少。
已達到預期的目標.
2.本次程序設計任務的各個部分都已完成,該程序通過對淘寶茶葉商品信息爬取與數據分析,主要爬取了商品的標題、銷售地、銷售量、評論數量、銷售價格、店鋪名稱、商品唯一標識ID以及詳情頁網址等信息,先是獲取到目標網頁的內容,再通過庫來實現對標簽內容的提取;再進行數據清理處理,並且所爬取的目標數據存儲到本地的excel文件,實現數據的持久化,最后通過matplotlib等對研究對象繪圖分析,最后根據數據之間的關系,分析兩個變量之間的相關系數,畫出散點圖,並建立變量之間的回歸方程。在此過程中從一個大框架再不斷細分完成每一部分的內容,使自己在這個過程中不斷完善進步。於此同時,也發現自己對數據清洗和數據可視化的不足及不熟練,還需多加學習,多加實踐。