一、選題的背景
為什么要選擇此選題?要達到的數據分析的預期目標是什么?(10 分)
現在大家都很喜歡b站,我也作為b站老用戶,所以這個爬蟲通過爬取b站播放排行榜信息,來看看最近必看的有用的好玩的任何視頻。
二、主題式網絡爬蟲設計方案(10 分)
1.主題式網絡爬蟲名稱:爬取b站熱門播放排行榜
2.主題式網絡爬蟲爬取的內容與數據特征分析:
通過request爬取b站熱門視頻排行榜的排名、播放量、彈幕數
使用BeautifulSoup分析網頁結構定位內容所在標簽獲取數據
使用Numpy對獲取的數據進行數據清洗
使用matplotlib對數據進行可視化處理
3.主題式網絡爬蟲設計方案概述:
數據獲取需要分為幾個步驟實現:
1) 通過request獲取網頁資源
2) 使用BuautifulSoup解析網頁,定位爬取資源
3) 編寫代碼將數據保存到csv文件中
三、主題頁面的結構特征分析(10 分)
數據來源:
https://www.bilibili.com/v/popular/all?spm_id_from=333.851.b_7072696d61727950616765546162.3
Htmls頁面解析
(1) 需要爬取的網頁
(1) 按下F12打開開發者模式
(1) 按下ctrl + shift + c然后點擊需要爬取的內容
(1) 從最下面的層級列表中可以看到我們需要爬取的標題最終在a.title這個標簽下面
(5) 同理找到播放量和彈幕數
四、網絡爬蟲程序設計
1.
數據爬取及采集:
---------------------------------------------------------------------------------------------
導入程序所需要的所有第三方運行庫
1 import requests #獲取頁面數據 2 import pandas as pd #用於數據清洗 3 from bs4 import BeautifulSoup #解析頁面 4 import numpy as np 5 import matplotlib #繪圖庫 6 import seaborn as sns 7 from matplotlib import pyplot as plt 8 import re #用於正則表達式 9 from scipy.sparse import data 10 import matplotlib.pyplot as plt 11 from imageio import imread 12 from wordcloud import WordCloud
獲取頁面響應數據
1 #獲取頁面響應數據 2 3 def getHtmlText(url): 4 try: 5 #UA偽裝 6 headers = { 7 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62' 8 } 9 html = page_text = requests.get(url = url,headers = headers) 10 # html.encoding = 'utf-8' #設置頁面編碼格式為utf-8防止獲取到的是亂碼 11 htmlText = html.text 12 # print(htmlText) 13 return htmlText 14 except: 15 print("獲取頁面數據失敗") #若出現異常打印字符串
BeautifulSoup進行頁面解析
1 #使用BeautifulSoup進行頁面解析 2 def ymjiexi(html_text): 3 soup = BeautifulSoup(html_text,'html.parser') 4 return soup
對爬取內容進行定位
1 #對爬取內容進行定位 2 def Title(): #獲取標題並進行存儲 3 tit = [] #創建數組進行存儲 4 title = ymjiexi(getHtmlText(url)).select('.info > a') 5 for ti in title: 6 tit.append(ti.text) 7 return tit 8 #獲取播放量並進行存儲 9 def getBo(): 10 bofan = [] #創建數組進行存儲 11 bo = ymjiexi(getHtmlText(url)).select('.detail-state > span:nth-of-type(1)') 12 for b in bo: 13 bof = re.findall(r'\d+\.\d+|\d+',b.text) 14 bofan.append(bof[0]) 15 return bofan
獲取彈幕並進行存儲
1 #獲取彈幕並進行存儲 2 def danmu(): 3 danmus = [] #存儲彈幕數 4 danmu = ymjiexi(getHtmlText(url)).select('.detail-state > span:nth-of-type(2)') 5 for d in danmu: 6 bof = re.findall('\d+\.\d+|\d+',d.text) 7 if float(bof[0]) < 10: 8 bof[0] = float(bof[0]) * 10000 #如果彈幕數量 9 danmus.append(bof[0]) 10 return danmus
運行得到結果
1 if __name__ == '__main__': 2 url = 'https://www.bilibili.com/v/popular/rank/all' 3 ymjiexi(getHtmlText(url)) 4 Title() #獲取標題 5 getBo() #獲取播放量 6 danmu() #獲取彈幕量 7 datas = [] #存儲標題和播放量 8 print("{:^10}\t{:^30}\t{:^40}\t{:^30}".format( '排名','標題', '播放量','彈幕數')) 9 for i in range(10): 10 print("{:^10}\t{:^30}\t{:^40}\t{:^30}".format(i+1,Title()[i],getBo()[i],danmu()[i])) 11 datas.append([i+1,Title()[i],getBo()[i],danmu()[i]])
12 對數據進行清理: 13 14 15 df = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) #導入文件 16 #查找重復值 17 df.duplicated() 18 print(df.duplicated()) 19 刪除無效行列 20 21 # 刪除無效列 22 23 df.drop('標題',axis = 1,inplace = True) 24 25 print(df.head(10)) 26 27 # 查找是否有空值 28 29 print(df['播放量'].isnull().value_counts()) 30 31 print(df['彈幕數'].isnull().value_counts()) 32 33 34 35 異常值的觀察 36 37 38 39 abnormal = df.describe() 40 41 42 43 print(abnormal) 44 45 # 查看相關系數 46 47 xishu = df.corr() 48 49 print(xishu)
數據分析與可視化:
散點圖
1 def aScatter(): 2 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止數據可視化總出現中文字符不顯示 3 x = df.播放量 4 y = df.彈幕數 5 plt.xlabel('播放量') 6 plt.ylabel('彈幕數') 7 plt.scatter(x, y, color = "red", label = "點", s = 50) 8 plt.title("播放量與彈幕數量的散點圖") 9 plt.legend(loc = 'best') 10 plt.show() 11 aScatter()
折線圖
1 # 折線圖 2 # 排名與彈幕數的折線圖 3 def brokenLine(): 4 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止數據可視化總出現中文字符不顯示 5 dp = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) 6 x = dp.排名 7 y = dp.彈幕數 8 plt.xlabel("排名") 9 plt.ylabel("彈幕數") 10 plt.plot(x, y, color = "green", label = "折線") 11 plt.title("播放量與彈幕數的折線圖") 12 plt.legend() 13 plt.show() 14 brokenLine()
扇形圖
1 #播放量與彈幕數的扇形圖 2 def pieChart(): 3 dp = pd.DataFrame(pd.read_csv('b站播放量排行榜(刪除后).csv')) 4 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止數據可視化總出現中文字符不顯示 5 x = df.播放量 6 y = df.彈幕數 7 name = [x[0], x[1], x[2], x[3], x[4]] 8 math = [y[0], y[1], y[2], y[3], y[4]] 9 explode = [0.1, 0.1, 0.1, 0.1, 0.1] 10 plt.pie(math, labels = name, colors = ["r", "g", "c", "b", "y"], explode = explode) 11 plt.axis("equal") 12 plt.title("b站熱榜播放量與彈幕數的扇形圖") 13 plt.show() 14 pieChart()
回歸直線圖
1 def back(): 2 dp = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) 3 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止數據可視化總出現中文字符不顯示 4 plt.rcParams['font.serif'] = ['KaiTi'] 5 plt.rcParams['axes.unicode_minus'] = False 6 x = df.排名 7 y = df.彈幕數 8 # X,Y為散點圖的 9 X = df.排名 10 Y = df.彈幕數 11 # 先定義所需要的數據 12 x_i2 = 0 13 x_i = 0 14 y_i = 0 15 # 用mean()方法計算出x,y的均值 16 q = x.mean() 17 w = y.mean() 18 for i in range(7): 19 x_i2 = x_i + x[i] * x[i] 20 x_i = x_i + x[i] 21 y_i = y_i + y[i] 22 m_1 = x_i * y_i - 7 * q * w 23 m_2 = x_i2 - 7 * q * q 24 k = m_1 / m_2 25 # 截距 26 b = w - q * k 27 x = np.linspace(0, 7) 28 y = k * x + b 29 print("斜率k=", k, "截距b=", b) 30 plt.figure(figsize = (6, 4)) 31 plt.xlabel('排名') 32 plt.ylabel('彈幕數') 33 plt.scatter(X, Y, color = "green", label = "散點", linewidth = 2) 34 plt.plot(x, y, color = "blue", label = "回歸直線") 35 plt.title("回歸直線圖") 36 plt.legend() 37 plt.show() 38 back()
條形圖
1 # 繪制條形圖 2 def bar(): 3 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止數據可視化總出現中文字符不顯示 4 df = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) 5 x = df.排名 6 y = df.播放量 7 plt.xlabel('排名') 8 plt.ylabel('播放量') 9 plt.bar(x,y,color='red',width = 0.8) 10 plt.title("排名與播放量的條形圖") 11 plt.show() 12 bar()
線性關系圖
1 # 線性關系圖 2 def line(): 3 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止數據可視化總出現中文字符不顯示 4 plt.rcParams['font.serif'] = ['KaiTi'] 5 plt.rcParams['axes.unicode_minus'] = False 6 df = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) 7 sns.lmplot(x = "排名", y = "播放量", data = df) 8 plt.show() 9 line()
標題詞雲圖
1 #讀取b站播放量排行榜.csv將其中的標題名稱寫到txt文本中 2 text = pd.read_csv("b站播放量排行榜.csv", encoding='utf-8') 3 with open("標題.txt",'a+', encoding='utf-8') as f: 4 for title in text.標題: 5 f.write((str(title)+'\n')) 6 #讀取文本 7 text=open('標題.txt',encoding='utf-8').read() 8 #詞雲的背景圖片 9 photo=imread('小雞.jpg') 10 Cyun=WordCloud( 11 background_color = "white", 12 mask = photo, 13 14 width=1000, 15 16 repeat=True, 17 18 font_path=r'simfang.ttf', 19 20 height=1600).generate(text) 21 22 plt.imshow(Cyun) 23 24 plt.axis("off") 25 26 plt.show() 27 28 #保存圖片 29 30 Cyun.to_file("標題詞雲.jpg")
爬蟲源碼:
1 #導入程序所需要的所有第三方運行庫 2 import requests 3 import bs4 4 import pandas as pd 5 from bs4 import BeautifulSoup 6 import numpy as np 7 import matplotlib 8 import seaborn as sns 9 from matplotlib import pyplot as plt 10 import re 11 from scipy.sparse import data 12 from wordcloud import WordCloud 13 import matplotlib.pyplot as plt 14 from imageio import imread 15 16 17 plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文標簽,防止畫圖出現中文字符不顯示 18 plt.rcParams['font.serif'] = ['KaiTi'] 19 plt.rcParams['axes.unicode_minus'] = False 20 21 22 23 24 #獲取頁面數據 25 def getHtmlText(url): 26 try: 27 #UA偽裝 28 headers = { 29 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62' 30 } 31 html = page_text = requests.get(url = url,headers = headers) 32 # html.encoding = 'utf-8' #設置頁面編碼格式為utf-8防止獲取到的是亂碼 33 htmlText = html.text 34 # print(htmlText) 35 return htmlText 36 except: 37 print("獲取頁面數據失敗") #若出現異常打印字符串 38 39 #使用BeautifulSoup進行頁面解析 40 def ymjiexi(html_text): 41 soup = BeautifulSoup(html_text,'html.parser') 42 return soup 43 44 #對爬取內容進行定位 45 def Title(): #獲取標題並進行存儲 46 tit = [] #創建數組進行存儲 47 title = ymjiexi(getHtmlText(url)).select('.info > a') 48 for ti in title: 49 tit.append(ti.text) 50 return tit 51 #獲取播放量並進行存儲 52 def getBo(): 53 bofan = [] #創建數組進行存儲 54 bo = ymjiexi(getHtmlText(url)).select('.detail-state > span:nth-of-type(1)') 55 for b in bo: 56 bof = re.findall(r'\d+\.\d+|\d+',b.text) 57 bofan.append(bof[0]) 58 return bofan 59 def danmu(): 60 danmus = [] #存儲彈幕數 61 danmu = ymjiexi(getHtmlText(url)).select('.detail-state > span:nth-of-type(2)') 62 63 for d in danmu: 64 bof = re.findall('\d+\.\d+|\d+',d.text) 65 # print(bof) 66 danmus.append(bof[0]) 67 return danmus 68 69 70 if __name__ == '__main__': 71 url = 'https://www.bilibili.com/v/popular/rank/all' 72 ymjiexi(getHtmlText(url)) 73 Title() #獲取標題 74 getBo() #獲取播放量 75 danmu() #獲取彈幕量 76 datas = [] #存儲標題和播放量 77 print("{:^30}\t{:^40}\t{:^30}".format( '標題', '播放量','彈幕數')) 78 for i in range(10): 79 print("{:^30}\t{:^40}\t{:^30}".format(Title()[i],getBo()[i],danmu()[i])) 80 datas.append([Title()[i],getBo()[i],danmu()[i]]) 81 print(datas) 82 83 #將爬取到的內容保存到csv文件里進存儲和后續的數據清洗 84 df = pd.DataFrame(datas, columns = ["標題", '播放量', '彈幕數']) 85 df.to_csv('b站播放量排行榜.csv', index = False) #設置index = Flase防止出現未命名的列 86 print("爬取完畢!") 87 88 #進行數據清洗 89 90 df = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) #導入文件 91 # 查找重復值 92 df.duplicated() 93 print(df.duplicated()) 94 95 # 刪除無效行 96 df.drop('標題',axis = 1,inplace = True) 97 98 print(df.head(10)) 99 100 # 查找是否有空值 101 print(df['標題'].isnull().value_counts()) 102 print(df['熱度'].isnull().value_counts()) 103 104 # 刪除彈幕數量小於20的標題 105 def drop(): 106 drop = df.drop(index=(df.loc[(df['彈幕數']<20)].index)) 107 print(drop) 108 drop.to_csv('b站播放量排行榜(刪除后).csv', index = False) 109 print("保存成功") 110 drop() 111 112 113 114 # 異常值的觀察 115 abnormal = df.describe() 116 print(abnormal) 117 118 119 # 查看相關系數 120 xishu = df.corr() 121 print(xishu) 122 123 # 散點圖 124 def aScatter(): 125 x = df.播放量 126 y = df.彈幕數 127 plt.xlabel('播放量') 128 plt.ylabel('彈幕數') 129 plt.scatter(x, y, color = "red", label = "點", s = 50) 130 plt.title("播放量與彈幕數量的散點圖") 131 plt.legend(loc = 'best') 132 plt.show() 133 aScatter() 134 135 136 # 折線圖 137 # 播放量與彈幕數的折線圖 138 def brokenLine(): 139 dp = pd.DataFrame(pd.read_csv('b站播放量排行榜(刪除后).csv')) 140 print(df.head(10)) 141 x = dp.播放量 142 y = dp.彈幕數 143 plt.xlabel("播放量") 144 plt.ylabel("彈幕數") 145 plt.plot(x, y, color = "green", label = "折線") 146 plt.title("播放量與彈幕數的折線圖") 147 plt.legend() 148 plt.show() 149 brokenLine() 150 151 152 #播放量與彈幕數的扇形圖 153 def pieChart(): 154 dp = pd.DataFrame(pd.read_csv('b站播放量排行榜(刪除后).csv')) 155 x = df.播放量 156 y = df.彈幕數 157 name = [x[0], x[1], x[2], x[3], x[4]] 158 math = [y[0], y[1], y[2], y[3], y[4]] 159 explode = [0.1, 0.1, 0.1, 0.1, 0.1] 160 plt.pie(math, labels = name, colors = ["r", "g", "c", "b", "y"], explode = explode) 161 plt.axis("equal") 162 plt.title("b站熱榜播放量與彈幕數的扇形圖") 163 plt.show() 164 pieChart() 165 166 #播放量與彈幕數的回歸直線圖 167 # 回歸直線的圖 168 def back(): 169 dp = pd.DataFrame(pd.read_csv('b站播放量排行榜(刪除后).csv')) 170 171 x = df.播放量 172 y = df.彈幕數 173 # X,Y為散點圖的 174 X = df.播放量 175 Y = df.彈幕數 176 # 先定義所需要的數據 177 x_i2 = 0 178 x_i = 0 179 y_i = 0 180 # 用mean()方法計算出x,y的均值 181 q = x.mean() 182 w = y.mean() 183 for i in range(7): 184 x_i2 = x_i + x[i] * x[i] 185 x_i = x_i + x[i] 186 y_i = y_i + y[i] 187 188 m_1 = x_i * y_i - 7 * q * w 189 190 m_2 = x_i2 - 7 * q * q 191 192 k = m_1 / m_2 193 # 截距 194 b = w - q * k 195 x = np.linspace(0, 7) 196 y = k * x + b 197 print("斜率k=", k, "截距b=", b) 198 plt.figure(figsize = (6, 4)) 199 plt.xlabel('播放量') 200 plt.ylabel('彈幕數') 201 plt.scatter(X, Y, color = "green", label = "散點", linewidth = 2) 202 plt.plot(x, y, color = "blue", label = "回歸直線") 203 plt.title("回歸直線圖") 204 plt.legend() 205 plt.show() 206 back() 207 208 #繪制條形圖 209 def bar(): 210 df = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) 211 x = df.播放量 212 y = df.彈幕數 213 plt.xlabel('播放量') 214 plt.ylabel('彈幕數') 215 plt.bar(x,y,color='red') 216 plt.title("播放量與彈幕數的條形圖") 217 plt.show() 218 bar() 219 220 221 # 線性關系圖 222 def line(): 223 df = pd.DataFrame(pd.read_csv('b站播放量排行榜.csv')) 224 sns.lmplot(x = "播放量", y = "彈幕數", data = df) 225 plt.show() 226 line() 227 228 #讀取b站播放量排行榜.csv將其中的標題名稱寫到txt文本中 229 text = pd.read_csv("b站播放量排行榜.csv", encoding='utf-8') 230 with open("標題.txt",'a+', encoding='utf-8') as f: 231 for title in text.標題: 232 f.write((str(title)+'\n')) 233 234 #讀取文本 235 text=open('標題.txt',encoding='utf-8').read() 236 #詞雲的背景圖片 237 photo=imread('小雞.jpg') 238 Cyun=WordCloud( 239 background_color = "white", 240 mask = photo, 241 width=1000, 242 repeat=True, 243 font_path=r'simfang.ttf', 244 height=1600).generate(text) 245 plt.imshow(Cyun) 246 plt.axis("off") 247 plt.show() 248 #保存圖片 249 Cyun.to_file("標題詞雲.jpg")
總結:
經過爬蟲和數據可視化,我們可以觀察到b站排行榜的想知道的信息,雖然實用性不高,但是就是好玩,每個人所追求的東西都不一樣,爬蟲也並不只是為了完成任務型的工作,我們在學習的過程中應該真正做到學以致用,在玩中學,在學習中自己找樂子,才能找到枯燥學習中的樂趣,看看詞雲圖,是不是很喜感。當然這個也不是完全沒用的,b站確實是能夠了解很多趨於年輕態的信息,大齡人若想了解年輕人所想,不妨也試試去b站。未來我希望能繼續完善能力,在此之上有更大發展。