短视频评论的抓取及分析

短视频评论的抓取及分析

一.设计背景

目前,短视频已经成为大多数人娱乐消遣的主要方式。用户在观看视频内容的同时,也同样关注视频评论,并且很多时候评论带给人们的乐趣远远超过视频本身。但是各短视频平台都没有提供用户评论数据的可视化分析,基于该现状,本项目给出了解决方案。

在本项目中,我们对视频评论的文本进行分析,提取出现频率较高的一部分词汇形成词云,这样可以过滤掉大量文本,使用户一眼扫过就可以获取主要信息,并感知最突出且具有代表性的评论词汇;同时我们对每一条评论进行情感分析,统计各种情感倾向评论的数量,以可视化的方式展现给用户,以便用户掌握评论的舆情走向。除此之外,我们还对所有评论的IP进行分析,最终以地图的方式向用户展示全国各地的评论人数,使用户对该视频的地域性有所了解。

二.设计思想

1.评论数据抓取

首先分析视频页面源码以及服务器返回的各种数据,接下来定位评论数据,最后使用Fiddler抓包工具抓取服务器返回的JSON格式的评论数据并保存。

2.评论文本分析

(1)文本内容提取

分析JSON数据的层次,找到评论文本并提取。

(2)文本分析及可视化
(a)绘制词云

首先使用jieba库对全部评论分词并提取出现频率较高的词汇,然后利用wordcloud进行词云绘制。

(b)情感分析

首先调用百度智能云自然语言处理功能中的情感倾向分析,接下来对获取到的每一条评论进行情感分析,最后统计各种情感倾向的占比,并使用matplotlib绘制饼图,可视化展示分析结果。

image-20221223044337748

image-20221223044826401

3.评论IP分析

(1)IP信息提取

分析JSON数据层次,找到IP信息并提取。

(2)IP分析及可视化

使用collections库中的Counter方法对提取到的IP进行数量统计,得到每个省份评论人数的数据,然后使用pyecharts模块绘制体现各省份评论人数的中国地图。

三.数据获取流程

1.定位评论数据

通过分析页面源码发现,只有一小部分评论数据包含在页面源码中,显然直接爬取短视频页面的源码的做法并不可行。进一步分析发现,抖音评论数据为异步数据,即评论数据包随着用户下翻视频页面逐一从服务器发送给用户,每个数据包都为包含20条评论的JSON文件,并且具有唯一的URL。

image-20221221232702269

2.数据抓取

首先尝试使用requests带着cookie直接请求该数据包的URL,但是发现返回的数据为空,经过多次尝试,最终认为直接爬取该数据包的难度较大。所以另辟蹊径,使用Fiddler抓包工具抓取在下翻评论过程中服务器返回的所有数据包,然后利用评论数据包URL的特征进行筛选,得到返回的所有评论数据,最后将这些数据保存以备接下来从中提取所需数据。

QQ图片20221222005741

3.提取有用数据

将JSON文件内容复制粘贴到JSON解析网站,以便通过JSON视图更清晰的把握JSON数据的层次。

image-20221222210029163

不难发现,评论文本信息和IP信息都在comments下以序号为标签的字典中,ip_label对应IP信息,text对应文本信息。由此可以编写Python代码提取每个JSON数据中的文本和IP信息。

四.代码结构

代码主要有两部分,comments_analysis:评论文本分析及可视化,形成词云和反应情感倾向占比的饼图;IP_analysis:对IP信息进行统计并绘制反应各省份评论人数的中国地图。代码结构图如下:

getComments.py

get_ip.py

具体代码如下:

getComments.py

import json
import os
import re
import jieba.analyse
import wordcloud
from imageio import imread
from aip import AipNlp
import matplotlib.pyplot as plt

mk = imread('词云背景图.png')


def get_filepath(data_base_dir):
    """拿到json文件的路径及文件名,保存到'file_name.txt中'"""
    file_name = open('file_name.txt', 'w', encoding='utf-8')
    filelist = []
    for filePath in os.listdir(data_base_dir):
        filePath = data_base_dir + '\\' + filePath
        filelist.append(filePath)
    for i in filelist:
        file_name.write(i + '\n')
    file_name.close()


def get_1comments(js_path):
    """拿到一个json文件中的评论内容,保存到列表comment_1中并返回"""
    js = open(js_path, 'r', encoding='utf-8').read()
    data = json.loads(js)
    comment_1 = []
    for comment in data['comments']:
        comment_1.append(comment['text'])
    return comment_1


def get_allcomments(data_base_dir):
    """拿到所有json文件中的评论内容,保存到列表comments中并返回"""
    comments = []
    get_filepath(data_base_dir)
    file_name = open('file_name.txt', 'r', encoding='utf-8')
    for line in file_name:
        comments.extend(get_1comments(line.strip()))
    print('评论提取完毕!')
    return comments


def form_wordcloud(comments):
    """解析评论内容并形成词云"""
    word = ''.join(comments)
    # 使用jieba分词并提取出现频率前200的名词、动词、形容词等有代表性的词汇
    topWord_lis = jieba.analyse.extract_tags(word, topK=200, allowPOS='n''v''a''vn''an')
    topWord = ' '.join(topWord_lis)
    # 词云参数配置
    w = wordcloud.WordCloud(
        background_color='white',
        #  font_path='C:\Windows\Fonts\HGY2_CNKI.TTF',  # 字体
        width=2000,
        height=1500,
        max_words=1000,
        max_font_size=80,
        min_font_size=10,
        mode='RGBA',
        mask=mk,  # 背景图
    )

    w.generate(topWord)
    w.to_file('评论词云.png')
    print('词云形成!')


def get_emotion(comment):
    """对一条评论进行情感分析,返回该评论的情感属性(emotion_label可能为0,1,2,分别对应消极的、中肯的、积极的)"""
    # 百度API认证
    APP_ID = '********'
    API_KEY = '********'
    SECRET_KEY = '********'

    client = AipNlp(APP_ID, API_KEY, SECRET_KEY)
    comment = ''.join(re.findall('[\u4e00-\u9fa5]', comment))  # 去除评论文本中的特殊字符
    # 调用情感倾向分析
    dic = client.sentimentClassify(comment)
    # 可能存在没有文本的空评论,异常处理保证程序执行的连续性
    try:
        emotion_label = dic['items'][0]['sentiment']
    except KeyError:
        return 1  # 若无内容,则为中性评论
    return emotion_label


def emotion_analysis(comments):
    """对所有评论进行情感分析并绘制饼图"""
    pos_comment = 0  # 积极
    rel_comment = 0  # 中肯
    neg_comment = 0  # 消极
    for comment in comments:
        if get_emotion(comment) == 0:
            neg_comment += 1
        elif get_emotion(comment) == 1:
            rel_comment += 1
        else:
            pos_comment += 1

    plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文支持
    plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号
    plt.style.use('fivethirtyeight')  # 图表样式

    attitude = ['消极的', '积极的', '中肯的']  # 标签
    popularity = [neg_comment, pos_comment, rel_comment]  # 数据
    # 绘制饼图
    plt.pie(popularity, labels=attitude, autopct='%1.1f%%',
            counterclock=False, startangle=90, explode=[0, 0.1, 0])
    plt.title('评论情感分析')
    plt.tight_layout()
    plt.savefig('情感分析结果.png')
    plt.show()

    print('情感分析完毕!')


def main():
    data_base_dir = r'C:\Users\T-Rex\Desktop\PythonProject\douyin\data'  # 数据文件的路径
    comments = get_allcomments(data_base_dir)
    form_wordcloud(comments)
    emotion_analysis(comments)


if __name__ == "__main__":
    main()
    print('OK!')

get_ip.py

import json
import os
from collections import Counter
from pyecharts.charts import Map
from pyecharts.options import *


def get_filepath(data_base_dir):
    """拿到json文件的路径及文件名,保存到'file_name中'"""
    file_name = open('file_name', 'w', encoding='utf-8')
    filelist = []
    for filePath in os.listdir(data_base_dir):
        filePath = data_base_dir + '\\' + filePath
        filelist.append(filePath)
    for i in filelist:
        file_name.write(i + '\n')
    file_name.close()


def get_1data(js_path):
    """拿到一个json文件中每条评论的IP,保存到列表ip中并返回"""
    js = open(js_path, 'r', encoding='utf-8').read()
    js_dic = json.loads(js)
    ip = []
    for comment in js_dic['comments']:
        ip.append(comment['ip_label'])
    return ip


def get_data(data_base_dir):
    """提取所有json文件中评论的IP,保存到列表ip中并返回"""
    ip = []
    get_filepath(data_base_dir)
    file_name = open('file_name', 'r', encoding='utf-8')
    for line in file_name:
        ip.extend(get_1data(line.strip()))
    print('ip提取完毕!')
    return ip


def count(ip):
    """统计所有IP出现的次数"""
    ip_count = Counter(ip)
    ipCount_list = []
    ip_place = list(ip_count.keys())
    ip_people = list(ip_count.values())
    # 将IP数据封装成('省份',人数)的元组形式,保存到列表ipCount_list中
    for i in range(len(ip_place)):
        ipCount_list.append((ip_place[i], ip_people[i]))
    print('统计完毕!')
    return ipCount_list


def form_map(ipCount_list):
    """绘制IP分布地图"""
    MAP = Map()
    # 导入数据
    MAP.add("各省份评论人数", ipCount_list, "china")
    # 参数配置
    MAP.set_global_opts(
        title_opts=TitleOpts(title="IP分布地图"),
        visualmap_opts=VisualMapOpts(
            is_show=True,  # 是否显示
            is_piecewise=True,  # 是否分段
            pieces=[
                {
    
    "min": 1, "max": 20, "lable": "1~19人", "color": "#CCFFFF"},
                {
    
    "min": 20, "max": 40, "lable": "20~39人", "color": "#FFFF99"},
                {
    
    "min": 40, "max": 60, "lable": "40~59人", "color": "#FF9966"},
                {
    
    "min": 60, "max": 80, "lable": "60~79人", "color": "#FF6666"},
                {
    
    "min": 80, "max": 100, "lable": "80~99人", "color": "#CC3333"},
                {
    
    "min": 100, "lable": "100+", "color": "#990033"},
            ]
        )
    )
    # 绘图
    MAP.render("IP分布地图.html")
    print('绘图完毕!')


def main():
    data_base_dir = r'C:\Users\T-Rex\Desktop\PythonProject\douyin\data'  # 数据文件的路径
    ip = get_data(data_base_dir)
    ipCount_list = count(ip)
    form_map(ipCount_list)


if __name__ == "__main__":
    main()
    print('OK!')

五.可视化展示及分析

1.评论词云

评论词云

该词云展示出了全部评论中出现频率最高的词汇,如“医学”、“小白鼠”、“可爱”、“可怜”、“解剖”、“学医”等。通过词云用户可以对全部评论的主要信息一目了然,同时也可以看到评论中出现的“热词”。

2.情感倾向分布饼图

情感分析结果

可见,持积极态度和消极态度的评论者数量均衡,只有一小部分评论者持中肯的态度。由此可知,此视频引发了较大的争议,评论者在评论区各执己见,互相抨击。

3.IP分布地图

image-20221222213547522

从这张图可以看出,大部分评论者的IP为甘肃省。因为抖音会将用户创作的视频推给附近的人,所以可以推测,视频作者大概率身处甘肃。同时也可以看出,中东部地区以及新疆、广东评论者居多。

六.改进与完善

1.数据获取过程自动化程度降低,未来应进一步学习爬虫技术,找到可以直接通过URL一次性爬取全部评论数据的可行方法,同时提高代码的复用率。

2.词云中包含大量无用信息,如“不了”、“不用”、“觉得”、“感觉”、“看到”、“不想”、“时候”等。接下来应该编写一个包含常用中性词的字典,加入词云参数中用来过滤掉这些中性词。

3.情感倾向分析可能存在一定偏差。未来将进一步学习自然语言处理,利用针对短视频的评论情感倾向集来训练snownlp的情感分析模型,然后用该模型来进行情感分析以提高准确度。

4.继续学习pyecharts模块以及前端知识,使绘制的地图更美观。同时,地图图例中的数量分段应跟随评论总人数而变化,以期达到自适应的结果。

5.解决上述问题后,将设计一个可以嵌入浏览器的脚本,使用户在刷短视频的同时可以看到上述可视化成果。

猜你喜欢

转载自blog.csdn.net/zhangmou_9008/article/details/128415320