Python学习笔记 | 爬取B站视频评论并进行数据分析

Bruce
2024-09-21 / 0 评论 / 34 阅读 / 正在检测是否收录...

最近在做用户反馈,需要分析B站某视频下的评论。由于用户评论数量庞大,因此使用Python爬取评论,并进行简单的分析处理。本文介绍此过程中使用的方法,基本思路为:

  1. 爬取评论数据保存到CSV文件
  2. 对爬取的评论进行情感分析
  3. 对评论数据进行可视化分析

一、获取评论

根据视频链接解析oid参数,将爬取的数据保存到CSV文件中。

爬取信息包括:用户姓名、性别、IP属地、评论内容、点赞数量、评论数量。

# 参考来源:https://www.bilibili.com/video/BV1K9Hse8EwM/?share_source=copy_web&vd_source=d4744805a3e716c7d611be8c989392d9

import csv
import hashlib
import time
from datetime import datetime
import requests
from urllib.parse import quote
import json
import re

# 构造函数,解析w_rid加密参数
def GetSign(data_time, next_page, oid):
    pagination_str = '{"offset":%s}' % next_page
    print(pagination_str)

    l = [
        "mode=3",
        f"oid={oid}",
        f"pagination_str={quote(pagination_str)}",
        "plat=1",
        "type=1",
        "web_location=1315875",
        f"wts={data_time}"
    ]

    y = '&'.join(l)

    string = y + 'ea1db124af3c7062474693fa704f4ff8'

    MD5 = hashlib.md5()
    MD5.update(string.encode('utf-8'))
    w_rid = MD5.hexdigest()
    print(w_rid)
    return w_rid

# 构造获取B站评论内容函数
def GetInfo(next_page, oid, csv_writer):

    # url构造
    url = "https://api.bilibili.com/x/v2/reply/wbi/main"
    data_time = int(time.time())
    w_rid = GetSign(data_time, next_page, oid)
    data = {
        'oid': oid,
        'type': '1',
        'mode': '3',
        'pagination_str': '{"offset":%s}' % next_page,
        'plat': '1',
        'web_location': '1315875',
        'w_rid': w_rid,
        'wts': data_time
    }

    response = requests.get(url=url, params=data, headers=headers)
    json_data = response.json()
    replies = json_data['data']['replies']
    for index in replies:
        comment_time = datetime.fromtimestamp(index['ctime']).strftime('%Y-%m-%d %H:%M:%S')
        dit = {
            '昵称': index['member']['uname'],
            '性别': index['member']['sex'],
            '地区': index['reply_control'].get('location', '').replace('IP属地:', ''), #一些较早视频没有地区信息,如果没有地区信息返回空值
            '评论': index['content']['message'],
            '点赞数': index['like'],
            '评论数': index['reply_control'].get('sub_reply_title_text', '0').replace('相关回复共', ''),
            '评论时间': comment_time
        }
        csv_writer.writerow(dit)
        print(dit)

        # 检查是否有二级评论
        if 'replies' in index and index['replies'] is not None:
            for sub_reply in index['replies']:
                sub_comment_time = datetime.fromtimestamp(sub_reply['ctime']).strftime('%Y-%m-%d %H:%M:%S')
                sub_dit = {
                    '昵称': sub_reply['member']['uname'],
                    '性别': sub_reply['member']['sex'],
                    '地区': sub_reply['reply_control'].get('location', '').replace('IP属地:', ''),
                    '评论': sub_reply['content']['message'],
                    '点赞数': sub_reply['like'],
                    '评论数': '0',  # 二级评论下无其他评论,则值设为0
                    '评论时间': sub_comment_time
                }
                csv_writer.writerow(sub_dit)
                print(sub_dit)

    next_page = json_data['data']['cursor']['pagination_reply']['next_offset']
    next_offset = json.dumps(next_page)
    print(next_offset)
    return next_offset

# 构造函数,通过视频链接获取oid
def get_oid(author_url):
    rsp = requests.get(author_url, headers=headers)
    oid = re.findall(r'"aid":(\d+),', rsp.text)[0]
    print('成功获取oid:',oid)
    return oid

if __name__ == '__main__':

    headers = {
        "cookie": "", #输入cookie,否则无法获取完整评论
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
    }

    # 输入视频链接和文件名
    author_url = input("请输入视频链接: ")
    oid = get_oid(author_url)
    filename = input("请输入要保存的文件名: ") + '.csv'

    # 创建文件对象
    with open(file=filename, mode='w', encoding='utf-8-sig', newline='') as f:
        csv_writer = csv.DictWriter(f, fieldnames=['昵称', '性别', '地区', '评论','点赞数','评论数','评论时间'])
        csv_writer.writeheader()

        next_page = '""'
        for page in range(1, 100):# 可以根据需要修改爬取范围
            next_page = GetInfo(next_page, oid, csv_writer)

此爬虫代码仅能爬取一级评论和展开的二级评论,无法爬取到分页的二级评论,因此爬取数量会比实际数量少。

二、情感分析

为了快速筛选出CSV文件中含有负面情感的示例,考虑使用NLP或大语言模型进行情感分析。

使用SnowNLP分析评论情感:

SnowNLP是一个基于 Python 的自然语言处理工具包,它提供了文本情感分析、关键词提取、文本分类等功能。该工具包具有简单易用的接口,可帮助用户快速实现文本处理和情感分析任务。
# 参考来源:https://mp.weixin.qq.com/s/NqSmswl8Cad1MCWWwQj3gQ

from snownlp import SnowNLP
import pandas as pd

def sentiment_analysis(text):
    """
    使用SnowNLP进行中文文本情感分析。
    :param text: 中文文本字符串。
    :return: 情感分析结果,包括情感倾向(正面情感、负面情感)和情感值。
    """
    # 创建SnowNLP对象
    snlp = SnowNLP(text)

    # 获取情感倾向和情感值
    sentiment = snlp.sentiments

    # 根据情感值判断情感倾向
    if sentiment > 0.5:
        sentiment_polarity = '正面情感'
    else:
        sentiment_polarity = '负面情感'

    return sentiment_polarity, sentiment

# 读取CSV文件
df = pd.read_csv(r'./xuangu.csv')  # 修改此处

# 获取评论列的值
comments = df['评论'].values

# 初始化情感倾向列表和情感值列表
inclinations = []   # 情感倾向列表
values = []         # 情感值列表

# 遍历评论进行情感分析
for comment in comments:
    sentiment_polarity, sentiment_score = sentiment_analysis(comment)
    inclinations.append(sentiment_polarity)
    values.append(sentiment_score)
    print(f"情感倾向: {sentiment_polarity}, 情感值: {sentiment_score}")

# 打印情感倾向列表查看结果
print(inclinations)

# 将分析结果添加到DataFrame
df['情感倾向'] = inclinations
df['情感值'] = values

# 将更新后的DataFrame保存到新的CSV文件
df.to_csv('./xuangu_snetiments_analysis.csv', index=False, encoding='utf-8-sig')

使用Zhipu分析评论情感:

智普AI大模型开放平台提供免费API供用户调用,可前往申请:https://open.bigmodel.cn/
import pandas as pd
import time  # 导入time模块用于调用sleep函数
from zhipuai import ZhipuAI

def analyze_comment_sentiment(comment):
    """
    分析用户评论的情感倾向。

    参数:
    - comment: str, 用户的评论内容

    返回:
    - str, 评论的情感倾向(正向、中性、负向)
    """
    # 初始化ZhipuAI客户端
    client = ZhipuAI(api_key="")  # 请填写您自己的APIKey

    # 发送请求进行情感分析
    response = client.chat.completions.create(
        model="GLM-4-Flash",  # 模型名称,可根据实际情况选择,模型列表见https://bigmodel.cn/dev/howuse/model
        messages=[
            {"role": "system",
             "content": "#Role:用户评论情感分析专家"
                        "## Goals:理解用户评论的情感态度,判断情感态度"
                        "## Output_format:正向、中性、负向"
                        "## Constrains:不要解释原因,直输出结论"
             },
            {"role": "user",
             "content": comment},  # 使用函数参数
        ],
    )

    # 返回分析结果
    return response.choices[0].message.content

# 读取CSV文件
df = pd.read_csv(r'./xuangu.csv')  # 读取保存评论的文档

# 获取评论列的值
comments = df['评论'].values

# 初始化情感倾向列表
inclinations = []

# 遍历评论进行情感分析
for comment in comments:
    sentiment = analyze_comment_sentiment(comment)
    inclinations.append(sentiment)
    print(f"评论: {comment}, 情感倾向: {sentiment}")
    time.sleep(3)  # 每次调用后等待3秒,可根据实际情况更改数值

# 将分析结果添加到DataFrame
df['情感倾向'] = inclinations

# 将更新后的DataFrame保存到新的CSV文件
df.to_csv('./xuangu_zhipu_sentiments_analysis.csv', index=False, encoding='utf-8-sig')

三、数据可视化

飞书多维表格

飞书多维表格提供丰富的数据图标模板,将生成的CSV文件上传至飞书云文档多维表格,然后利用仪表盘生成数据表。

image-20240921171115148

Pyecharts

此外,还可以使用PyeCharts进行数据可视化。

PyeCharts是一个开源可视化工具,提供丰富的图标组件

示例代码:https://gallery.pyecharts.org/#/Map/china_gdp_from_1993_to_2018

import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Map

# 读取CSV文件
df = pd.read_csv('wuxia.csv')  # 确保文件路径正确

# 创建一个映射,将常见的省份和直辖市名称映射到pyecharts能识别的名称
name_mapping = {
    '北京': '北京市', '天津': '天津市', '上海': '上海市', '重庆': '重庆市',
    '河北': '河北省', '山西': '山西省', '辽宁': '辽宁省', '吉林': '吉林省',
    '黑龙江': '黑龙江省', '江苏': '江苏省', '浙江': '浙江省', '安徽': '安徽省',
    '福建': '福建省', '江西': '江西省', '山东': '山东省', '河南': '河南省',
    '湖北': '湖北省', '湖南': '湖南省', '广东': '广东省', '海南': '海南省',
    '四川': '四川省', '贵州': '贵州省', '云南': '云南省', '陕西': '陕西省',
    '甘肃': '甘肃省', '青海': '青海省', '台湾': '台湾省',
    '内蒙古': '内蒙古自治区', '广西': '广西壮族自治区', '西藏': '西藏自治区',
    '宁夏': '宁夏回族自治区', '新疆': '新疆维吾尔自治区',
    '香港': '香港特别行政区', '澳门': '澳门特别行政区'
}

# 使用映射更新地区名称
df['地区'] = df['地区'].map(name_mapping)

# 计算每个地区的数量
region_counts = df['地区'].value_counts().reset_index()
region_counts.columns = ['地区', '数量']
print(region_counts)

# 准备数据
data = [list(z) for z in zip(region_counts['地区'], region_counts['数量'])]

# 创建地图
c = (
    Map()
    .add("", data, "china")
    .set_global_opts(
        title_opts=opts.TitleOpts(title="用户来源"),
        visualmap_opts=opts.VisualMapOpts(max_=100),# 根据图表数据修改取值范围
    )
    .render("map_visualmap_piecewise.html")
)

image-20240921175353621

Wordcloud库

使用python的jieba和wordcloud库可以生成词云图,代码如下:

# 导入必要的库
import matplotlib
matplotlib.use('TkAgg')  
import matplotlib.pyplot as plt

from wordcloud import WordCloud
import jieba
import pandas as pd

# 读取停用词
with open("stopwords_cn.txt", "r", encoding="utf-8") as f:
    stopwords = set([line.strip() for line in f.readlines()])

# 读取csv文件
df = pd.read_csv("wuxia.csv", encoding="utf-8")
comments = df["评论"].tolist()

# 将评论列的内容合并为一个字符串
s = " ".join(comments)

# 中文分词
text = ' '.join(jieba.cut(s))

# 生成词云对象
wc = WordCloud(font_path="msyh.ttc",  # 字体路径,确保路径正确
               background_color='white',
               max_words=200,
               width=1920,  
               height=1080, 
               stopwords=stopwords).generate(text)

# 使用Matplotlib显示词云
plt.imshow(wc, interpolation='bilinear')
plt.axis("off")
plt.show()

# 保存到文件
wc.to_file("wuxia_comments_wordcloud.png")

Figure_1

附词云停用词表:

主要参考来源:

  1. 【Python爬虫可视化:采集分析各大平台用户评论数据(B站、抖音、京东、天猫、网易云、微博、知乎)】 https://www.bilibili.com/video/BV1K9Hse8EwM/?share_source=copy_web&vd_source=d4744805a3e716c7d611be8c989392d9
  2. python例子:对评论内容进行情感分析,https://mp.weixin.qq.com/s/NqSmswl8Cad1MCWWwQj3gQ
3

评论 (0)

取消