一、项目概述与技术栈
我们的目标是分析某个特定快手视频(或一系列视频)的评论舆情。整个流程分为两大核心模块:
- 数据获取模块:通过模拟请求,抓取目标视频下的所有评论数据。
- 舆情分析模块:对抓取的评论进行文本分析,包括情感极性判断和关键词/主题提取。
技术栈:
- 爬虫库:
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">requests</font>(发送HTTP请求),<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">json</font>(解析API返回数据) - 数据分析库:
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">pandas</font>(数据处理),<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">numpy</font>(数值计算) - 文本处理库:
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">jieba</font>(中文分词),<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">sklearn</font>(特征提取) - 情感分析库:
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">snownlp</font>(适用于中文的情感分析) - 可视化库:
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">matplotlib</font>,<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">wordcloud</font>(生成词云)
二、实战步骤一:抓取快手评论数据
与抓取公开网页不同,快手App的数据主要通过其内部API接口传输。因此,我们的核心在于找到并模拟这个接口。
2.1 定位API与参数分析
通过浏览器的“开发者工具”(F12),切换到“网络”(Network)选项卡,然后刷新快手视频页面并向下滑动加载评论,可以捕获到多个网络请求。仔细查找,会发现一个返回JSON格式评论数据的请求。这个请求的URL通常是类似的模式。
经过分析,我们找到核心API并构造请求参数。
2.2 Python爬虫代码实现
import requests
import json
import pandas as pd
import time
import random
# 代理配置信息
proxyHost = "www.16yun.cn"
proxyPort = "5445"
proxyUser = "16QMSOML"
proxyPass = "280651"
# 构造代理地址
proxyMeta = f"http://{proxyUser}:{proxyPass}@{proxyHost}:{proxyPort}"
proxies = {
"http": proxyMeta,
"https": proxyMeta
}
def fetch_kuaishou_comments(video_id, max_count=500):
"""
抓取快手视频的评论数据
:param video_id: 快手视频ID,通常可以从视频URL中获取
:param max_count: 想要抓取的最大评论数
:return: 包含评论的DataFrame
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36',
'Cookie': '你的Cookie(如需)', # 注意:可能需要登录后的Cookie才能抓取更多数据
'Referer': f'https://v.kuaishou.com/{video_id}'
}
# 评论API基础URL(此为示例,实际需根据抓包结果更新)
base_url = "https://www.kuaishou.com/graphql"
all_comments = []
pcursor = "" # 分页游标,第一页为空
while len(all_comments) < max_count:
# 构造GraphQL查询参数(此为简化示例,实际查询体非常复杂)
payload = {
"operationName": "commentListQuery",
"variables": {
"photoId": video_id,
"pcursor": pcursor
},
"query": "..." # 这里需要替换为完整的、从抓包中获取的GraphQL查询语句
}
try:
# 在requests.post中添加proxies参数
response = requests.post(
base_url,
headers=headers,
json=payload,
timeout=10,
proxies=proxies # 添加代理配置
)
data = response.json()
# 解析评论列表
comments_list = data['data']['commentList']['comments'] # 路径根据实际JSON结构调整
if not comments_list:
print("没有更多评论了。")
break
for comment in comments_list:
# 提取用户昵称、评论内容、点赞数、时间等
user_name = comment.get('author', {}).get('name', '')
content = comment.get('content', '').strip()
like_count = comment.get('likeCount', 0)
timestamp = comment.get('timestamp', '')
all_comments.append({
'user_name': user_name,
'content': content,
'like_count': like_count,
'timestamp': timestamp
})
# 更新游标,用于下一页
pcursor = data['data']['commentList'].get('pcursor', '')
if not pcursor: # 如果游标为空,说明已是最后一页
break
print(f"已获取 {len(all_comments)} 条评论...")
# 随机休眠,模拟人类行为,避免被封IP
time.sleep(random.uniform(1, 2))
except requests.exceptions.ProxyError as e:
print(f"代理连接失败: {e}")
break
except requests.exceptions.ConnectTimeout as e:
print(f"连接超时: {e}")
break
except requests.exceptions.RequestException as e:
print(f"网络请求异常: {e}")
break
except json.JSONDecodeError as e:
print(f"JSON解析失败: {e}")
print(f"响应内容: {response.text[:200]}...") # 打印前200个字符用于调试
break
except Exception as e:
print(f"请求失败: {e}")
break
# 转换为DataFrame
df_comments = pd.DataFrame(all_comments)
return df_comments
# 使用示例
if __name__ == '__main__':
# 假设视频ID为 "3x8y9zabcde"
video_id = "你的视频ID"
try:
comments_df = fetch_kuaishou_comments(video_id, max_count=300)
# 保存到CSV文件
if not comments_df.empty:
comments_df.to_csv(f'kuaishou_comments_{video_id}.csv', index=False, encoding='utf-8-sig')
print(f"评论数据抓取完成!共获取 {len(comments_df)} 条评论。")
else:
print("未获取到任何评论数据。")
except Exception as e:
print(f"程序执行失败: {e}")
重要提示:快手的API接口和参数加密策略会频繁更新。上述代码中的<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">base_url</font>、<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">payload</font>结构以及数据解析路径均为示例,在实际操作中,您必须使用开发者工具进行实时抓包分析,找到正确的请求方式和参数,才能成功获取数据。
三、实战步骤二:评论数据的文本分析
数据抓取完成后,我们得到一个包含评论内容的CSV文件。接下来是舆情分析的核心。
3.1 数据清洗与预处理
import jieba
import re
from snownlp import SnowNLP
# 加载数据
df = pd.read_csv('kuaishou_comments_你的视频ID.csv')
# 1. 去重
df = df.drop_duplicates(subset=['content'])
# 2. 数据清洗函数
def clean_text(text):
if pd.isna(text):
return ""
# 移除URL、@用户、表情符号等噪音
text = re.sub(r'http\S+', '', text) # URL
text = re.sub(r'@\S+', '', text) # @用户
text = re.sub(r'\[.*?\]', '', text) # 表情符号
# 移除多余空格和换行符
text = re.sub(r'\s+', ' ', text).strip()
return text
df['content_cleaned'] = df['content'].apply(clean_text)
# 3. 使用jieba进行中文分词
def chinese_word_cut(text):
# 可以添加自定义词库以提高分词的准确性,特别是网络用语
# jieba.load_userdict("user_dict.txt")
return " ".join(jieba.cut(text))
df['content_cut'] = df['content_cleaned'].apply(chinese_word_cut)
print("数据清洗与分词完成!")
3.2 情感分析
我们使用<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">SnowNLP</font>库,它是一个专门为中文文本处理而开发的库,其情感分析功能基于朴素贝叶斯模型训练,对商品评论、社交媒体文本有较好的效果。
# 情感分析函数
def get_sentiment(text):
try:
s = SnowNLP(text)
return s.sentiments # 返回一个0(负面)到1(正面)之间的值
except:
return 0.5 # 中性作为默认值或错误值
# 应用情感分析,这步可能较慢
print("正在进行情感分析,请稍候...")
df['sentiment'] = df['content_cleaned'].apply(get_sentiment)
# 根据情感得分打标签
def get_sentiment_label(score):
if score > 0.6:
return '正面'
elif score < 0.4:
return '负面'
else:
return '中性'
df['sentiment_label'] = df['sentiment'].apply(get_sentiment_label)
# 查看情感分布
sentiment_dist = df['sentiment_label'].value_counts()
print(sentiment_dist)
3.3 可视化情感分布
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 绘制情感分布饼图
plt.figure(figsize=(8, 8))
sentiment_dist.plot.pie(autopct='%1.1f%%', startangle=90, colors=['#ff9999','#66b3ff','#99ff99'])
plt.title('快手评论情感分布')
plt.ylabel('') # 隐藏y轴标签
plt.show()
3.4 生成词云与关键词提取
词云可以直观地展示评论中的高频词汇。
from wordcloud import WordCloud
from sklearn.feature_extraction.text import CountVectorizer
# 将所有分词后的评论合并成一个字符串
all_words = ' '.join(df['content_cut'])
# 生成词云
wordcloud = WordCloud(
font_path='simhei.ttf', # 指定中文字体路径
width=800,
height=600,
background_color='white',
max_words=100
).generate(all_words)
plt.figure(figsize=(10, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.title('快手评论词云图')
plt.show()
# 使用CountVectorizer进行关键词词频统计
vectorizer = CountVectorizer(stop_words=['的', '了', '是', '我', '有', '在', '就', '都', '不', '也']) # 添加停用词
X = vectorizer.fit_transform(df['content_cut'])
word_freq = dict(zip(vectorizer.get_feature_names_out(), X.sum(axis=0).A1))
# 输出前20个高频词
top_keywords = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:20]
print("高频关键词TOP20:")
for word, freq in top_keywords:
print(f"{word}: {freq}")
四、舆情洞察与总结
通过以上步骤,我们完成了从数据抓取到分析可视化的全过程。现在,我们可以得出一些有价值的舆情洞察:
- 整体情绪基调:通过情感分布饼图,我们可以一目了然地看到对该视频的舆论是“褒”大于“贬”,还是争议较大(中性居多)。
- 核心讨论点:词云图和高频关键词列表直接揭示了用户讨论的焦点。例如,如果视频是关于一款新手机,高频词可能会出现“屏幕”、“价格”、“续航”、“流畅”等,从而知道用户最关心什么。
- 深度关联分析:我们可以进行更深入的分析,例如:
- 高赞评论分析:将
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">like_count</font>作为权重,分析高赞评论的情感和高频词,这些代表了“主流声音”或“核心观点”。 - 负面评论溯源:筛选出所有“负面”评论,仔细阅读其具体内容,精准定位产品、服务或内容中存在的具体问题。
- 高赞评论分析:将
五、注意事项与伦理
- 合规性:本技术文章仅用于学习和研究目的。在实际应用中,务必遵守
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">Robots协议</font>、平台用户协议及相关法律法规(如《网络安全法》、《个人信息保护法》),尊重用户隐私和知识产权,避免对目标网站造成过大访问压力。 - 技术时效性:短视频平台的反爬策略日新月异,文中爬虫代码可能需要根据平台变动进行调整。
- 模型局限性:
<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">SnowNLP</font>的情感分析模型并非完美,对于反讽、网络新梗等复杂语言现象可能判断不准。在重要商业决策中,可能需要人工标注样本训练更专用的模型。