Python网络爬虫--爬取bilibili排行榜


一、选题的背景

 

为什么要选择此选题?要达到的数据分析的预期目标是什么?(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站。未来我希望能继续完善能力,在此之上有更大发展。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM