基于python
的小爬虫, 用于提取bilibiili
的视频弹幕并加以简单的处理以及可视化。
运行 main.py
为无GUI版本
运行 main_with_UI.py
为带GUI版本
安装完对应库之后直接运行 main.py
或者 main_with_UI.py
, 之后根据对应提示进行操作即可
- 在
main.py
中, 如果需要修改图片遮罩、弹幕文件保存名、词云图片保存名、词云遮罩、词云图片大小等参数请根据注释自行修改相关参数。
爬取的弹幕文件在去重统计重复数量之后会保存在 danmaku_data
文件夹下
生成的词云图会保存在 word_cloud_image
文件夹下
需要添加自定义图片遮罩,请放置图片到 image_masks
文件夹下
需要添加自定义字体,请放置字体文件到 fonts
文件夹下
下面涉及的函数名可能与实际函数名不一样。
具体应该实现的功能:
- 数据获取
- 数据分析
- 可视化
数据获取模块有以下几个功能:
- 根据用户输入的关键字以及需要的视频个数爬取相关视频的
BV
号 - 根据BV号获取相关视频的cid
- 根据cid获取相关视频的当前弹幕池
- 最后汇总各个视频的弹幕池,形成一个字符串列表
-
是否完成
-
功能实现:通过关键词获取前n页的相关视频BV号, 返回BV号的字符串列表
-
参数:
- _keyword: 关键词
- _video_count: 读取的视频数量
-
返回值: 获取的BV号字符串列表
-
是否完成
-
功能实现:读取BV号对应视频的cid
-
参数:_bv : 视频BV号
-
返回值: 对应的cid
-
是否完成
-
功能实现:根据cid读取当前视频弹幕池内弹幕
-
参数:cid : cid
-
返回值: 弹幕字符串列表
-
是否完成
-
功能实现: 封装本模块的功能
-
参数:
- _keyword: 关键词
- _video_count: 读取的视频数量
-
返回值:收集的弹幕列表
数据分析模块应该有以下几个功能:
- 进行简单的统计同类型弹幕个数,最后生成一个列表,列表的元素为一个元组,元组第一个元素为弹幕,第二个元素为出现次数。元组的排序按照次数从大到小
- 将上述列表保存为
.csv
文件,分为两列。每一行对应一条弹幕,第一列为弹幕数量,第二列为弹幕文本。按顺序从高到低排列。 - 将字符串列表组合成字符串并且分词,为接下来可视化做词云做准备
需要两个模块,一个负责写文件,另一个就是负责分析数据
-
是否完成
-
功能实现:统计传入的字符串列表中各个字符串出现的次数。返回列表元素为(string, int)样式的元组。
-
参数:_str_list: 字符串列表
-
返回值: 结果保存为特殊格式的列表
-
是否完成
- 功能实现:将列表按照某种规则存为
.CSV
文件。文件将保存在DanmakuData
文件夹下
- 功能实现:将列表按照某种规则存为
-
参数:
-
_list: 目标字典
-
_file_name: 保存的文件名
-
- 通过数据分析部分得到的分词结果进行词云生成
生成词云图:CreateWordCloudImage(_content: str, _file_name: str, _max_words=100, _width=1000, _height=1000, _mask_name='default.png', _font_name='default.ttc')
-
是否完成
-
功能实现:创建词云图。遮罩图默认为空。此时长宽设置生效。自定义遮罩请放置在
image_masks
文件夹里;字体默认为微软雅黑。自定义字体请放在fonts
内。 -
参数:
- _content: 分过词的内容
- _file_name: 保存的词云图名
- _max_words: 可以显示的最大词数
- _width: 宽
- _height: 高
- _mask_name: 遮罩图片的名字
- _font_name: 字体名
整活:为上面的小爬虫写一个UI。计划采用~~pygame
~~库来实现
计划采用tkinter
库来实现
设计了6个界面:
- 爬虫选项界面
- 爬取中提示界面
- 爬取结束界面
- 词云生成界面
- 生成中界面
- 生成成功界面
界面由元素构成。为Frame
对象
设计了一个PanelMgr
模块用来管理界面
设计 Delegate
来实现多播委托
设计 DataKeeper
模块来全局暂存数据,用于界面、线程之间信息交换
设计 EventCenter
模块,用来解决主,副线程之间通信的问题
补充设计了其他模块来保证运行安全性
每一个界面都写一个文件,每一个文件都写一个函数,函数返回的就是frame类型的变量
每个函数设置一个变量,为该面板的唯一标识符。方便直接将所有面板都放进一个多播委托之内。
当函数传入的参数跟自己的标识符不一致的时候直接返回None, 一致的时候返回生成的frame面板
以下为界面设计初稿, 与最终设计可能存在偏差
-
done
-
关键词 -- 输入框
-
搜索数 -- 高级输入框
-
保存文件名 -- 输入框
-
启动! -- 按钮
-
done
-
爬取中 -- 文本框
-
用时 -- 文本框
-
done
-
第i条 - 文本框
-
弹幕 - 文本框
-
上一页, 下一页 -- 按钮
-
已保存为 xx.csv -- 文本框
-
去生成词云 -- 按钮
- done
- 生成图片名 -- 输入框
- 最大次数 -- 高级输入框, 默认100
- 图片尺寸 -- 输入框
- 字体 -- 复合框
- 遮罩 -- 复合框
- 图片 -- 图片
- 启动 -- 按钮
-
done
-
生成中 -- 文本框
-
done
-
生成成功,保存为xxx, 以下为预览 -- 文本框
-
图片 -- 图片
-
再来一次 -- 按钮
用来管理UI面板的单例类
主要方法: SwitchPanel(self, _root: tk.Tk, _id: int)
- 用于切换到目标ID的界面
实现了多播委托,重载了部分运算符。初步确保了安全性,用于降低代码耦合程度
用来解决面板之间、面板与其他模块之间信息传递的问题
降低代码耦合程度
SendData(self, name: str, data)
- 向
DataKeeper
模块存储信息
- 向
GetData(self, name: str)
- 向
DataKeeper
模块读取信息
- 向
事件中心,用来降低代码耦合,解决不同线程之间通信问题
有加必有减!
AddEventListener(self, name: str, action)
- 添加事件监听, 事件名为 name, 事件为 action
RemoveEventListener(self, name: str, action)
- 移除事件监听, 事件名为 name, 事件为 action
EventTrigger(self, name: str, *args, **kwargs)
- 触发事件, 事件名为 name
DeleteEvent(self, name: str)
- 删除事件, 事件名为 name
Clear(self)
- 清除所有的事件