1.(1.1)在Github仓库中新建一个学号为名的文件夹,同时在博客正文首行给出作业Github链接。(2’)
https://github.com/s1f4/software-engineering.git
一、PSP表格
(1.1)在开始实现程序之前,在附录提供的PSP表格记录下你估计将在程序的各个模块的开发上耗费的时间。(3’)
(1.2)在你实现完程序之后,在附录提供的PSP表格记录下你在程序的各个模块上实际花费的时间。(3’)
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 90 |
· Estimate | · 估计这个任务需要多少时间 | 2520 | 2850 |
Development | 开发 | 420 | 600 |
· Analysis | · 需求分析 (包括学习新技术) | 600 | 720 |
· Design Spec | · 生成设计文档 | 30 | 60 |
· Design Review | · 设计复审 | 30 | 60 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
· Design | · 具体设计 | 120 | 180 |
· Coding | · 具体编码 | 300 | 360 |
· Code Review | · 代码复审 | 60 | 120 |
· Test | · 测试(自我测试,修改代码,提交修改) | 180 | 240 |
Reporting | 报告 | 180 | 180 |
· Test Repor | · 测试报告 | 90 | 120 |
· Size Measurement | · 计算工作量 | 60 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 90 | 60 |
· 合计 | 2240 | 2850 |
二、任务要求的实现
(2.1)项目设计与技术栈。从阅读完题目到完成作业,这一次的任务被你拆分成了几个环节?你分别通过什么渠道、使用什么方式方法完成了各个环节?列出你完成本次任务所使用的技术栈。(5’)
分为三步:分析需求、学习爬虫技术、实现代码。
分析需求:列出任务要求关键,爬取B站300个视频弹幕,统计弹幕输出前二十并导入到Excel表以及据此制作词云图;通过CSDN、B站、知乎等学习爬虫B站弹幕从一个视频到多个视频以及翻页爬取;通过CSDN、B站、知乎等学习在写代码需要用到的库以及工具,解决在写代码时遇见的问题,比如在实现统计、自动导入Excel表、词云图功能时。
学习了爬虫基本操作以及一些用到的库requests、json、re 、openpyxl、collections、matplotlib、wordcloud、PIL、numpy、logging、jieba。
(2.2)爬虫与数据处理。说明业务逻辑,简述代码的设计过程(例如可介绍有几个类,几个函数,他们之间的关系),并对关键的函数或算法进行说明。(20’)
定义一个空的弹幕列表danmu_list,利用开发者工具找到B站搜索关键词后页面的url,headers,cookies;定义get_danmu方法,用B站官方API接口,以及弹幕链接,通过正则表达式获得一个页面弹幕,返回给danmu_list列表。通过for循环改变page以及bvid达到翻页获取弹幕。通过Counter、openpyxl库来实现统计所有弹幕数量,输出排名前二十的弹幕,并将数据导入Excel表中。利用wordcloud、PIT、numpy、jieba对统计的数据制作词云图。
根据B站官方API接口的bvid,获得cid_url连接,通过request请求,用json获得cid_res对象,得到cid号,通过字符串拼接以及官方弹幕链接得到带cid参数的弹幕链接,通过正则表达式匹配获得弹幕列表内容。
def get_danmu(bvid,headers):
cid_url = "https://api.bilibili.com/x/web-interface/view?bvid=" + bvid
cid_req = requests.get(cid_url, headers=headers)
cid_res = json.loads(cid_req.text)# 通过json.loads转换为对象
cid = cid_res['data']['cid']
danmu_url = "https://comment.bilibili.com/" + str(cid) + ".xml" # 弹幕链接
danmu_req = requests.get(danmu_url, headers=headers)
danmu_req.encoding = 'utf-8'
danmu_list = re.findall('<d p=".*?">(.*?)</d>',danmu_req.text)# 正则表达式匹配
return danmu_list
利用session()自动处理cookies,做状态保持,B站一个页面显示30个视频,爬取300个视频,就需要请求10个页面通过page、bvid号改变,返回十个页面的弹幕内容给弹幕列表dnmu_list。
# 一个页面有30个视频,需要爬取300个视频,所以需要10页
for i in range(10):
sess = requests.session()# 实例化对象 requests.session()复用TCP
req = sess.get(url + "&page=" + str(i+1), headers=headers, cookies=cookies)# get请求,
res = json.loads(req.text)# 通过json.loads转换为对象
for video in res['data']['result']:
danmu_list = danmu_list + get_danmu(video['bvid'],headers)
通过Counter库统计所有弹幕数量,利用most_common(20)方法获取排名前二十弹幕,之后通过openpyxl.Workbook()实例化一个workbook对象,利用save()方法将弹幕保存到danmu_statistics.xlsx。
# 统计弹幕数量
danmu_count = Counter(danmu_list)
# 获取数量排名前20的弹幕
top_20_count = danmu_count.most_common(20)
# 创建新的Excel表,写入统计结果
workbook = openpyxl.Workbook()
sheet = workbook.active
# 写入表头
sheet['A1'] = '弹幕'
sheet['B1'] = '数量'
# 写入数据
for i, (danmu, count) in enumerate(top_20_count, start=2):
sheet[f'A{i}'] = danmu
sheet[f'B{i}'] = count
# 打印输出数量排名前20的弹幕
print("数量排名前20的弹幕:")
for danmu, count in top_20_count:
print(f"{danmu}: {count}")
# 保存Excel表
workbook.save('danmu_statistics.xlsx')
词云图要显示中文文本,使用jieba中文分词库,对文本进行中文分词,使用.join()将结果转换为字符串;np.arry()用于处理图像数据;plt用于显示词云图;用wordcloud生成词云图对象wc。
# 用来关闭jieba在控制台中默认打印的很长一串提醒信息的
jieba.setLogLevel(logging.WARNING)
# 将弹幕列表转换为字符串
text = ' '.join(danmu_list)
# 对文本进行中文分词
wc_list = jieba.lcut(text)
# 将分词结果转换为字符串
wc_text = ' '.join(wc_list)
# 设置停用词
stopwords = set(STOPWORDS)
stopwords.update(["的", "了", "和", "是", "在", "我", "你", "他", "她"])
# 加载背景图片
mask = np.array(Image.open("background_image.png")) # 打开遮罩图片,将图片转换为数组
# 创建词云对象
wc = WordCloud(width=1000,height=600,font_path="C:\Windows\Fonts\STXINGKA.ttf",background_color='white',stopwords=stopwords, mask=mask, contour_width=1, contour_color='steelblue').generate(text)
# 绘制词云图
plt.figure(figsize=(8,8))
plt.imshow(wc, interpolation='bilinear') # 用plt显示图片
plt.axis('off') # 不显示坐标轴
plt.show()
wc.to_file("wc_image.png")
(2.3)数据统计接口部分的性能改进。记录在数据统计接口的性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(例如可通过VS /JProfiler的性能分析工具自动生成),并展示你程序中消耗最大的函数。(6’)
性能分析图
其中request消耗最大
(2.4)数据结论的可靠性。介绍结论的内容,以及通过什么数据以及何种判断方式得出此结论(6’)
结论内容可概括为提倡保护海洋、保护地球,支持抵制、反对排放,坚决抵制日本排放核污水。通过搜索B站上“日本排放核污水”关键字爬取300个视频弹幕,从而获得数据。通过排名前二十弹幕的Excel表柱形图,我们可以得出B站网友们对于“日本核污水排海”事件的评论排在第一位的是“保护海洋”,弹幕量高达1249条,其次是“支持”,这个支持应该是赞同保护海洋,坚决抵制日本排放核污水。通过词云图对采集的数据即弹幕进行可视化,可以通过字体的大小显示出某个数据(弹幕)出现的频次高,也侧边表达出评论人对这个事件某个看法认可度高。
(2.5)数据可视化界面的展示。在博客中介绍数据可视化界面的组件和设计的思路。(15’)
通过词云图对采集的数据即弹幕进行可视化,利用jieba——中文分词库、wordcloud——用于生成词云图、matplotlib——用于显示词云图、numpy——用于处理图像数据。先对统计的弹幕列表danmu_list通过.join转换成字符串text,通过jieba.icut()对进行中文分词,加载背景图片使用np.array()方法,实例化词云图对象 创建词云对象wc = WordCloud().generate(text),绘制词云图plt.imshow(wc, interpolation=‘bilinear’)。
通过采集的排名前二十弹幕的excel表格绘制柱形图
三、心得体会
(3.1)在这儿写下你完成本次作业的心得体会,当然,如果你还有想表达的东西但在上面两个板块没有体现,也可以写在这儿~(10’)
针对这次个人编程任务,完成得很艰难,前期一直在看题目要求,不仅要写代码,还要用到Github、性能分析、测试等,但毫无头绪,什么都不懂,也不知道从哪开始。所以就一直在B站、CSDN、知乎上搜索相关的,但是很零散知识,聚合不到一起,还是没有办法开始。到第三天慢慢就开始有点头绪,先学习爬虫,从爬虫B站上一个视频弹幕开始,知道原理,但很遗憾的是,学得不精髓,只是勉强达到题目要求的结果,也没有创建类和把要实现功能用方法实现。中间也是改了又改,报错改,尽自己所能使其完善,能够不负所托运行出来在作业截止前。对于Github真的是费尽心思,首先刚开始浏览器突然进不去,查了一些方法没学会,只能另寻他路,在一个小时后下载搜狐浏览器成功进去,刚开始不熟练,怕出错,又是一顿搜教程学教程。前进的每一步都在学习中获得。代码性能分析做得也不是很好。总之,要吸收这次学来的知识,继续学习爬虫还有Github、分析工具的使用。