哔哩哔哩热榜爬虫程序及数据处理

哔哩哔哩热榜爬虫程序及数据处理

 

 完整的代码与结果在最下面

 

一、设计方案

 

1.爬虫的目标是哔哩哔哩排行榜上视频的信息(https://www.bilibili.com/ranking/all/0/1/7)

 

 

2.爬取的内容包括网页上显示的所有内容,有排名标题,播放量,弹幕数,up,得分以及视频的url

3.设计方案:根据作业的要求,制作爬虫程序爬取信息并进行数据处理,整个程序分成四个部分,包括数据爬取:(get_rank),数据清洗与处理:(rubbish),文本分析生成词云:(message),数据分析与可视化:(watch)四个部分,所用到的库有request,BeautifulSoup,csv,collections,jieba,io,wordcloud,matplotlib。使用的IDE为anaconda环境配置的pycharm

设计难点:难点主要在数据处理方面,因为哔哩哔哩排行榜上爬取到的数据全都不是单纯的数字,所以在数据处理时遇到了许多问题,这方面查找资料的时间也最长

 

 

 

 

 

二、主题页面的结构特征分析

 

 

 

通过观察网页代码,发现排行榜上的每一个视频的标签为li,类名为rank-item,并且我们通过len函数打印提取到的数量也正好100符合排行榜的视频量,所以我们可以在当中继续得到视频其他信息的属性,在代码中都有注释。

 

 

 

三、网络爬虫程序设计

 

# 代码中注释部分的print都是为了调试用的

 

1.数据爬取(get_rank)

 

在保存数据部分用了self函数创建数据对象来将数据读入video对象中并且放在一个列表里,最后保存在csv文件中

结果:

 

2.数据清洗与处理(rubbish)

 

这一部分遇到了几个小问题,包括pycharm控制窗的输出结果不会显示所有数据,以及数据的编码问题,都在网上找到解决的方法,最后将清洗过的数据保存为xls文件

3.文本分析生成词云:(message)

 

文本分析,包括使用jieba库进行分词和wouldcould生成词云,先用列的标题进行查询,读取标题所在的那一列保存在txt文档中,然后使用jieba库进行分词,使用wouldcould制作词云保存成图片

jieba库分词结果:

保存结果:

 

 

4.数据分析与可视化:(watch)

 

数据分析与可视化,包括绘制折线图,柱形图,直方图,散点图

结果:

完整代码:

 

 

  1 import csv
  2 import requests
  3 from bs4 import BeautifulSoup
  4 import pandas as pd
  5 from collections import OrderedDict
  6 import jieba
  7 import io
  8 from scipy.optimize import leastsq
  9 from wordcloud import WordCloud
 10 import matplotlib.pyplot as plt
 11  
 12  
 13 # 注释部分的print都是为了调试用的
 14  
 15 def get_rank():  # 数据爬取与采集
 16     try:
 17         # 发起网络请求
 18         url = 'https://www.bilibili.com/ranking/all/0/1/7'
 19         response = requests.get(url)
 20         html_text = response.text
 21         soup = BeautifulSoup(html_text, 'html.parser')
 22  
 23         # 用来保存视频信息的对象
 24         class Video:
 25             def __init__(self, rank, title, point, visit, review, up, url):
 26                 self.rank = rank
 27                 self.title = title
 28                 self.point = point
 29                 self.visit = visit
 30                 self.review = review
 31                 self.up = up
 32                 self.url = url
 33 def to_csv(self):
 34                 return [self.rank, self.title, self.point, self.visit, self.review, self.up, self.url]
 35  
 36             # 使用静态方法
 37             @staticmethod
 38             def csv_title():
 39                 return ['排名', '标题', '分数', '播放量', '弹幕数', 'UP', 'URL']
 40  
 41         # 提取列表
 42         items = soup.find_all('li', {'class': 'rank-item'})
 43         videos = []  # 保存提取出来的video
 44         for itm in items:
 45             title = itm.find('a', {'class': 'title'}).text  # 标题
 46             point = itm.find('div', {'class': 'pts'}).text  # 综合得分
 47             rank = itm.find('div', {'class': 'num'}).text  # 排名
 48             visit = itm.find('span', {'class': 'data-box'}).text  # 播放量
 49             review = itm.find_all('span', {'class': 'data-box'})[1].text  # 弹幕数
 50             up = itm.find_all('span', {'class': 'data-box'})[2].text  # up
 51             url = itm.find('a', {'class': 'title'}).get('href')  # 获取链接
 52             v = Video(rank, title, point, visit, review, up, url)
 53             videos.append(v)
 54         # 保存
 55         file_name = f'top100.csv'
 56         with open(file_name, 'w', newline='') as f:
 57             pen = csv.writer(f)
 58             pen.writerow(Video.csv_title())
 59             # 导出数据到csv文件中
 60             for v in videos:
 61                 pen.writerow(v.to_csv())
 62         print('保存csv成功')
 63     except:
 64         return "保存csv失败"
 65  
 66  
 67 def rubbish():  # 对数据进行清洗和处理
 68     try:
 69         # pycharm控制窗的输出结果不会显示所有数据,所以在网上得到加入这三行代码进行解决方便查看结果
 70         # 加了这一行那表格的一行就不会分段出现了
 71         pd.set_option('display.width', 1000)
 72         # 显示所有列
 73         pd.set_option('display.max_columns', None)
 74         # 显示所有行
 75         pd.set_option('display.max_rows', None)
 76         # 对齐输出结果
 77         pd.set_option('display.unicode.ambiguous_as_wide', True)
 78         pd.set_option('display.unicode.east_asian_width', True)
 79  
 80         # 使用‘utf-8’会报错,使用其他解码会乱码,最终在网上得到了答案:‘在后面加入指定编译器为python即可’
 81         # 将csv格式数据写入到excel中
 82         df = pd.read_csv('top100.csv', engine='python', error_bad_lines=False)  # 当某行数据有问题时,不报错,直接跳过,处理脏数据时使用
 83         # print(df)   #输出csv表格中结果
 84         data = OrderedDict()  # 有序字典
 85         # print(df.columns)     #列名
 86         # 构建excel格式
 87         for line in list(df.columns):
 88             data[line] = list(df[line])
 89         obj = pd.DataFrame(data)
 90         obj.to_excel('top100.xls', index=False)
 91         # 查看统计信息,设置参数buf来存储字符串使数据不打印出来
 92         buf = io.StringIO()
 93         df.info(buf=buf)
 94         s = buf.getvalue()
 95         print(s)
 96         print('保存xls成功')
 97     except:
 98         return "保存xls失败"
 99  
100  
101 rubbish()
102  
103  
104 def message():  # 文本分析,包括使用jieba库进行分词和wouldcould生成词云
105     try:
106         # 用DictReader读取csv的某一列,用列的标题查询
107         with open('top100.csv', 'rt') as csvfile:
108             reader = csv.DictReader(csvfile)
109             column = [row['标题'] for row in reader]
110         # print(column)
111         # 将标题列保存到txt文件中
112         file = open('top100标题.txt', 'w')
113         file.write(str(column))
114         # 关闭文件
115         file.close()
116         print('保存txt成功')
117     except:
118         return "保存txt失败"
119  
120     try:
121         # 使用jieba库进行中文分词
122         final = ""
123         # 文件夹位置
124         filename = r"top100标题.txt"
125         # 打开文件夹,读取内容,并进行分词
126         with open(filename, 'r', encoding='gb18030') as f:
127             for line in f.readlines():
128                 word = jieba.cut(line)
129                 for i in word:
130                     final = final + i + " "
131         # print(final)
132         print('jieba分词成功')
133     except:
134         return 'jieba分词失败'
135  
136     try:
137         # 使用worldcould制作词云
138         # 打开文本
139         text = open('top100标题.txt').read()
140         # 生成对象
141         wc = WordCloud(font_path='C:\Windows\Fonts\simfang.ttf',
142                        width=800,
143                        height=600,
144                        mode='RGBA',
145                        background_color=None).generate(text)
146         # 显示词云
147         plt.imshow(wc, interpolation='bilinear')
148         plt.axis('off')
149         plt.show()
150         # 保存到文件
151         wc.to_file('标题词云.png')  # 生成图像是透明的
152         print('保存词云成功')
153     except:
154         return '保存词云失败'
155  
156  
157 message()
158  
159  
160 def watch():  # 数据分析与可视化,包括绘制折线图,柱形图,直方图,散点图
161     try:
162         # 获得绘图数据
163         point = pd.read_csv('top100.csv', engine='python')
164         # print(data.isnull().sum)
165 # 将字符串数据进行去除替换
166         rank = point['排名']
167         # print(rank)
168         points = point['分数'].map(lambda x: int(x.replace('综合得分', '')))
169         # print(points)
170         # 用来正常显示中文标签
171         plt.rcParams['font.sans-serif'] = ['SimHei']
172         # 用来正常显示负号
173 plt.rcParams['axes.unicode_minus'] = False
174         print('获取绘图数据成功')
175     except:
176         return '获取数据失败'
177  
178     try:
179         # 根据数据绘制折线图
180         plt.plot(rank,
181                  points,
182                  c='red',
183                  alpha=0.5)
184         # 绘图表区域着色
185         plt.fill_between(rank,
186                          points,
187 facecolor='blue',
188                          alpha='0.2')
189         # 设置图形的格式
190         plt.title('top100综合热度得分折线图',
191                   fontsize=24)
192         plt.xlabel('排名',
193                    fontsize=24)
194         plt.ylabel('热度得分',
195                    fontsize=12)
196         # 参数刻度线样式设置
197         plt.tick_params(axis='both',
198                         which='major',
199                         labelsize=10)
200 # 保存图片
201         plt.savefig(fname="top100综合热度得分折线图.png",
202                     figsize=[10, 10])
203         # 显示折线图
204         plt.show()
205         print('折线图保存成功')
206     except:
207         return '折线图保存失败'
208  
209     try:
210         # 根据数据绘制柱形图
211         # 创建基础图
212 fig = plt.figure()
213         # 在基础图上仅绘制一个图,括号中的三个参数代表基础图中的统计图布局,参数一次代表:图的行数量、图的列数量、第几个图。本例中,为1行1列,第一个图
214 bar1 = fig.add_subplot(1, 1, 1)
215         # 绘制柱形图,align表示条形与标签中间对齐。
216         bar1.bar(rank,
217                  points,
218                  align='center',
219                  color="blue")
220         # 设置x、y轴标签
221         plt.xlabel("排名")
222         plt.ylabel("热度得分")
223         # 设置统计图标题
224         plt.title("top100综合热度得分柱形图")
225         # 保存图片
226         plt.savefig(fname="top100综合热度得分柱形图.png",
227 figsize=[10, 10])
228         # 显示统计图
229         plt.show()
230         print('柱形图保存成功')
231     except:
232         return '柱形图保存失败'
233  
234     try:
235         # 绘制直方图
236         # 绘制基础图
237         fig = plt.figure()
238         hist1 = fig.add_subplot(1, 1, 1)
239         # 绘制直方图
240         # bins=50 表示每个变量的 值应该被分成 50 份。normed=False 表示直方图显示的是频率分布
241   hist1.hist(points,
242                          bins=50,
243                    color="blue",
244                    density=False)
245         # 确定坐标轴位置
246         hist1.xaxis.set_ticks_position("bottom")
247         hist1.yaxis.set_ticks_position("left")
248         # 设置坐标轴标签
249         plt.xlabel("热度得分")
250         plt.ylabel("人数")
251         # 设置标题
252         plt.title("top100综合热度得分直方图")
253         # 保存图片
254         plt.savefig(fname="top100综合热度得分直方图.png", figsize=[10, 10])
255         # 显示图形
256         plt.show()
257         print('直方图保存成功')
258     except:
259 return '直方图保存失败'
260 try:
261         # 绘制散点图
262         fig = plt.figure()
263         scatter1 = fig.add_subplot(1, 1, 1)
264         # 导入数据
265         scatter1.scatter(rank, points)
266         # 确定坐标轴位置
267         scatter1.xaxis.set_ticks_position('bottom')
268         scatter1.yaxis.set_ticks_position('left')
269         # 设置坐标轴标签
270         plt.xlabel("排名")
271         plt.ylabel("热度得分")
272         # 设置图表标题
273         plt.title("top100综合热度得分散点图")
274         # 保存图片
275         plt.savefig(fname="top100综合热度得分散点图.png",
276                     figsize=[10, 10])
277 # 显示图形
278 plt.show()
279         print('散点图保存成功')
280     except:
281         return '散点图保存失败'
282  
283  
284 watch()

 

 运行结果:

 

 

四、结论

 

通过爬虫程序的制作,认识到利用爬虫程序可以做到很多很酷的事情,能够通过爬虫爬取信息并运用其他库处理信息对工作效率的提升是多么的大,提高了自己对python的兴趣,坚定了认真学习的目标。但制作过程中仍有不足之处,今后会加强学习,多向老师同学请教,不断完善改进。

posted @ 2021-09-05 10:48  李豹。  阅读(285)  评论(0编辑  收藏  举报