You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1.4 MiB

https://code.educoder.net/p4fmntoqa/102201510

一、PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 20
· Estimate · 估计这个任务需要多少时间 1200 1440
Development 开发 1320 1440
· Analysis · 需求分析 (包括学习新技术) 360 300
· Design Spec · 生成设计文档 120 90
· Design Review · 设计复审 120 180
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 60 60
· Design · 具体设计 180 240
· Coding · 具体编码 240 270
· Code Review · 代码复审 120 180
· Test · 测试(自我测试,修改代码,提交修改) 120 120
Reporting 报告 240 210
· Test Repor · 测试报告 60 60
· Size Measurement · 计算工作量 60 60
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 120 90
· 合计 1580 1670

二、任务要求的实现

1. 项目设计与技术栈

从阅读完题目到完成作业这一次的任务被你拆分成了几个环节你分别通过什么渠道、使用什么方式方法完成了各个环节列出你完成本次任务所使用的技术栈。5'

我个人将本次任务拆为了四个部分,分别是弹幕数据获取、数据处理与转存、词云图绘制以及附加的弹幕情绪分析。

  1. 弹幕数据获取主要是通过在B站上学习爬虫内容查阅各种爬虫文件辅以浏览器自带的抓包工具最终编写出了自己的b站爬虫程序。
  2. 数据处理和转存大部分内容都是通过我个人之前的知识积累,自行完成的,部分难题则通过查找导入的第三方库函数说明文档解决。
  3. 词云图绘制仅有绘制词云图的部分去网络上搜索了相关的内容,剩余部分则是以自己的能力编写的内容。
  4. 弹幕情绪分析是通过网络上下载相关的自然语言分析模型,进行对应的情感分析,并最终输出成柱状图的形式,模型的调用部分参考了模型的说明文档。

用到的技术栈有如下内容:

  1. 文本处理和自然语言处理: jieba: 中文分词库 paddlenlp: 自然语言处理库
  2. 数据分析和科学计算: numpy: 数值计算库 pandas: 数据处理和分析库 scikit_learn: 机器学习库
  3. 数据可视化: matplotlib: 数据可视化库 wordcloud: 词云生成库
  4. 文件处理: openpyxl: Excel文件处理库 Pillow: 图像处理库
  5. 深度学习: paddlepaddle: 深度学习框架
  6. 网络请求: Requests: HTTP请求库
  7. 开发工具: pipreqs: 自动生成requirements文件 unittest: 单元测试框架 coverage: 代码覆盖率测试工具 viztracer: 代码性能分析工具 git: 版本控制工具

2. 爬虫与数据处理

说明业务逻辑简述代码的设计过程例如可介绍有几个类几个函数他们之间的关系并对关键的函数或算法进行说明。20'

本程序主要功能是对b站相关视频的弹幕进行数据处理和分析全程共用到了15个库及其库函数自定义了13个函数以完成程序的功能设计。程序的四个部分均有一个较为主要的函数。以下是对主要函数的说明并会附上对应程序的函数代码

  1. 弹幕数据获取中的正则匹配函数re.findall()。 该部分的所有函数几乎都用到了re.findall()所有有效信息的获取也都离不开re.findall()。它一共需要两个参数一个是匹配字段文本一个是数据文本返回值是list形式的匹配字段。
# 获取当前页码的视频链接地址
def GetAllSearchVideoUrl(url, headers):
    response = requests.get(url, headers = headers)
    response.encoding = 'utf-8'
    html_data = response.text
    content_list = re.findall('<a href="(.*?)" .*? target="_blank" data-v-4caf9c8c><div class=".*?" data-v-4caf9c8c>', html_data)
    return content_list

# 获取当前视频的弹幕接口cid地址
def GetVideoCid(url, headers):
    response = requests.get(url, headers = headers)
    response.encoding = 'utf-8'
    html_data = response.text
    content = re.findall('"dynamic":.*?,(.*?),"dimension":.*?', html_data)
    back = re.search('"cid":', content[0])
    num = back.span()[1]
    cid = content[0][num:]
    return cid

# 获取当前cid地址下的视频弹幕数据
def GetVideoBarrage(url, headers):
    response = requests.get(url, headers = headers)
    response.encoding = 'utf-8'
    html_data = response.text
    content_list = re.findall('<d p=".*?">(.*?)</d>', html_data)
    return content_list
  1. 数据处理与转存中的数据类型转换函数ChangeDfToString()。 该部分的后续函数都是基于ChangeDfToString()转换出来的字符串进行进行处理的。用dataframe正常转换出来字符串会有很多的空格以及莫名其妙的字符通过这个函数可以去除无效的空格并对每一个有效内容加以逗号分隔。它一共可以接受4个参数原dataframe分隔字符sep是否保存标志isSave保存路径filePath返回值是分隔好的字符。
# 读取弹幕文件
def ReadXlsx(filePath=''):
    df = pd.read_excel(filePath, sheet_name=0)
    df.dropna(axis=1, how='all')
    return df

# 将dataframe类型转为string类型
def ChangeDfToString(df,sep=',', isSave=False, filePath=''):
    string_data = df.to_string(index=False, header=False, na_rep='')
    string = string_data.replace('\n', ' ')
    str = re.sub(' +', sep, string)
    if isSave:
        with open(filePath, mode="w",encoding='utf-8') as file:
            file.write(str)
    return str

# 根据关键词进行检索
def GetKeyFromList(keyWords, origin_list):
    filtered_list = [item for item in origin_list if any(keyword in item for keyword in keyWords)]
    counter_list = Counter(filtered_list)
    sorted_list = sorted(counter_list.items(), key = lambda x:x[1], reverse=True)
    return sorted_list
  1. 词云绘制部分的词频转换函数ChangeToFreq()。 该函数可以将分隔好的词语用TF-IDF关键词提取并统计各类词语的词频实现正则化对后续的词云图绘制有较大的帮助。它接受一个参数分隔好的字符串返回值是词组频率的字典键值对是词组和频率。
# 将弹幕文本分隔成易于处理的字词
def ReadAndCutWords(filePath):
    with open(filePath, 'r', encoding='utf-8') as file:
        text = file.read()
    words = jieba.cut(text, cut_all=False)
    word_list = ' '.join(words)
    return word_list

# 利用TF-IDF将字词按频率划分
def ChangeToFreq(word_list):
    documents = [word_list]
    vectorizer = TfidfVectorizer()
    tfidf_matrix = vectorizer.fit_transform(documents)
    feature_names = vectorizer.get_feature_names_out()
    word_freq = dict(zip(feature_names, tfidf_matrix.toarray().sum(axis=0)))
    return word_freq

# 根据字词频率来生成图云
def CreateWordCloud(word_freq, width, height, maskImgPath, saveImgPath, save=False):
    if maskImgPath == '':
        mask = None
    else:
        mask = np.array(Image.open(maskImgPath))
    wordcloud = WordCloud(font_path='simhei.ttf',
                        mask= mask,
                        width=width, 
                        height=height, 
                        background_color='white').generate_from_frequencies(word_freq)
    if maskImgPath != '':
        image_colors = ImageColorGenerator(mask)
        wordcloud.recolor(color_func=image_colors)
    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis('off')
    plt.show()
    if save:
        wordcloud.to_file(saveImgPath)
  1. 弹幕情绪分析部分的模型加载类Taskflow()。 该类是paddlenlp库中的Taskflow类。panddnlp是基于百度的飞浆平台搭建的自然语言处理NLP模型库对中文语言分析有非常优秀的表现。利用Taskflow()类可以搭载模型model设定语言处理的模式schema最后会返回一个ie模型对象之后就可以使用ie对文本进行语言处理了。
# 加载弹幕字符文本
def loadText(sep, filePath):
    with open(filePath, 'r', encoding='utf-8') as file:
        text = file.read()
    t_list = text.split(sep)
    return t_list

# 加载自然语言处理模型
def loadModel(schema, model):
    ie = Taskflow('information_extraction', schema=schema, model=model)
    return ie

# 计算情感方向的数量以及平均的可能性
def emoChange(emo, pro, count, probability):
    if emo == '正向':
        count[0] += 1
        probability[0] = probability[0] + (pro - probability[0])/count[0]
    else:
        count[1] += 1
        probability[1] = probability[1] + (pro - probability[1])/count[1]

# 绘制柱形图
def createBar(count, probability, savePath):
    x_data = [f'正向(可能性:{probability[0]})', f'负向(可能性:{probability[1]})']
    y_data = count
    plt.rcParams["font.sans-serif"] = ["SimHei"]
    plt.rcParams["axes.unicode_minus"] = False
    plt.figure(figsize=(10, 7))
    for i in range(len(x_data)):
        plt.bar(x_data[i], y_data[i], width=0.7)
    plt.title("弹幕情感方向数量统计")
    plt.text(x_data[0], y_data[0]+0.01, count[0], ha="center", va="bottom", fontsize=17)
    plt.text(x_data[1], y_data[1]+0.01, count[1], ha="center", va="bottom", fontsize=17)
    plt.xlabel("弹幕情感方向")
    plt.ylabel("数量")
    plt.savefig(fname=savePath, dpi=500)
    plt.show()

3. 数据统计接口部分的性能改进

记录在数据统计接口的性能上所花费的时间描述你改进的思路并展示一张性能分析图例如可通过VS /JProfiler的性能分析工具自动生成并展示你程序中消耗最大的函数。6'

由于B站反爬虫的机制为了防止被ban我对程序自行设定了一定的延时该部分就是所需时间最长的一部分函数。 其他的函数性能消耗都不会很大除了使用ie模型对文本进行语言分析处理。针对此类性能消耗,我缩小了文本量,从全文本处理改成了随机抽样处理,数据结果相差不大,但性能消耗下降了非常多。 以下是除了b站爬虫程序以外的其他程序性能消耗 avatar

可以看到性能消耗最大的函数是ChangeDfToString(),其余函数的性能消耗都被挤到了角落 avatar 可以看到显示性能消耗最大的函数是CreateWordCloud(),但这个函数会绘制图片,关闭图片才结束统计,有一定的误差 avatar 可以看到显示性能消耗最大的是loadModel()函数后面的一串点点点,这里的每一个部分都是一次文本模型处理,性能开销非常大 avatar 这里展示的是代码的单元测试及覆盖率的内容,因为找不到适合的地方就放在这里了

4. 数据结论的可靠性

介绍结论的内容以及通过什么数据以及何种判断方式得出此结论6'

本程序得出的结论比较多,以下是结论介绍和相关的数据判断:

  1. b站用户对于弹幕讨论巴黎奥运会的ai使用并不感兴趣。 统计了b站搜索“2024巴黎奥运会”综合排序前300的视频弹幕并对弹幕应用了ai、智能等关键字提取最终发现基本没几个相关弹幕弹幕数量最多的还是“该内容疑似使用AI技术合成请谨慎甄别”不能说和巴黎奥运会没有关系只能说和巴黎奥运会毫不相关。
  2. b站用户在弹幕讨论中正向情绪远大于负向情绪。 不仅可以从词云图中看出b站用户在巴黎奥运会相关视频发送的最多的弹幕是“哈哈哈”、“好看”、“加油”等等积极正向的词语也能通过后续的弹幕情绪分析中看出1000个弹幕中正向情绪的弹幕有658个负向情绪的弹幕有341个正向接近负向的两倍而且弹幕的情绪可信度也非常高正向与负向的情绪可信度均接近90%。

5. 数据可视化界面的展示

在博客中介绍数据可视化界面的组件和设计的思路。15'

数据可视化主要是通过matplotlib: 数据可视化库、wordcloud: 词云生成库以及Pillow: 图像处理库函数来实现的。

  1. 考虑到词云生成为默认的长方形不够美观,因此特地从网络上找到了巴黎奥运会吉祥物的标志性图片,并将词云图中的文字按图片颜色排版,最终得到了现在的词云图片,观感好上了不少。 avatar

    弹幕词云图

  2. 虽然我利用了自然文本处理模型,对弹幕文本进行了情绪倾向分析,但这些都只是文本的内容。个人认为,单纯的文本内容表述不足以给出直观的数据展示,因此我将这部分内容以信息量最大、比较直观的正向负向柱形图的形式展现出来。

avatar

弹幕情绪倾向图

三、心得体会

在这儿写下你完成本次作业的心得体会,当然,如果你还有想表达的东西但在上面两个板块没有体现,也可以写在这儿~10'

本次作业是我第一次尝试以python完成一个这么大类的一个程序,也是我第一次接触到项目管理中的单元测试、代码覆盖率等待程序性能优化相关的内容,受益匪浅。不论是代码编写能力还是程序的设计能力,都有了足量的提升。 不过这里想吐槽一下 在2024巴黎奥运会的视频中寻找ai真的没有搞错什么吗(爬虫爬得都不自信了)