1. 项目概述
最近在分析电影评论数据时,发现词云(wordcloud)是一种非常直观的信息可视化方式。它能将文本中出现频率高的关键词以视觉突出的方式呈现,让观众一眼就能抓住文本主旨。本文将详细介绍如何使用Python从豆瓣电影抓取最新评论,并通过词云进行可视化展示。
这个项目特别适合以下人群:
- 想学习Python网络爬虫的初学者
- 对数据分析和可视化感兴趣的人
- 需要快速了解用户评论倾向的产品经理或市场人员
我们将以最新上映的《异形:夺命舰》(Alien: Romulus)为例,完整演示从数据抓取到词云生成的全过程。过程中会用到requests、BeautifulSoup、jieba和wordcloud等Python库。
2. 核心技术与工具选型
2.1 技术栈解析
这个项目主要涉及三个关键技术环节:
- 数据采集层:使用requests库发送HTTP请求,BeautifulSoup解析HTML页面
- 数据处理层:通过正则表达式清洗数据,jieba进行中文分词
- 可视化层:wordcloud生成词云,matplotlib展示结果
选择这些工具的主要考虑是:
- requests比urllib更简洁易用
- BeautifulSoup是Python最流行的HTML解析库
- jieba在中文分词领域表现优异
- wordcloud功能强大且高度可定制
2.2 环境准备
在开始前,请确保已安装以下Python库:
bash复制pip install requests beautifulsoup4 jieba wordcloud matplotlib pillow numpy
提示:如果安装速度慢,可以使用国内镜像源,如:
bash复制pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名
3. 数据采集实现
3.1 豆瓣电影页面分析
首先我们需要分析豆瓣电影页面的结构。以广州地区正在上映的电影页面为例:
python复制url = 'https://movie.douban.com/nowplaying/guangzhou'
通过浏览器开发者工具检查,可以发现:
- 电影列表位于id为"nowplaying"的div中
- 每部电影信息存储在class为"list-item"的li标签内
- 电影ID保存在data-subject属性中
- 电影名称在img标签的alt属性中
3.2 实现爬虫函数
基于上述分析,我们编写获取正在上映电影列表的函数:
python复制def getNowPlayingMovieList():
url = 'https://movie.douban.com/nowplaying/guangzhou'
headers = {
'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 Edg/127.0.0.0'
}
try:
resp = requests.get(url, headers=headers)
resp.raise_for_status()
html = resp.text
except requests.exceptions.RequestException as err:
print(f"请求错误: {err}")
return []
soup = bs(html, 'html.parser')
nowplaying_movie = soup.find('div', id='nowplaying')
if not nowplaying_movie:
return []
nowplaying_movie_list = nowplaying_movie.find_all('li', class_='list-item')
nowplaying_list = []
for item in nowplaying_movie_list:
nowplaying_dict = {}
nowplaying_dict['id'] = item['data-subject']
nowplaying_dict['name'] = item.find('img')['alt']
nowplaying_list.append(nowplaying_dict)
return nowplaying_list
关键点说明:
- 添加User-Agent模拟浏览器访问
- 使用try-except处理网络请求异常
- 通过BeautifulSoup解析HTML结构
- 提取电影ID和名称存储到字典中
3.3 获取电影评论
获取到电影ID后,我们可以爬取该电影的评论:
python复制def getCommentsById(movieId, pageNum):
eachCommentList = []
if pageNum <= 0:
return eachCommentList
start = (pageNum - 1) * 20
url = f'https://movie.douban.com/subject/{movieId}/comments?start={start}&limit=20'
headers = {
'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 Edg/127.0.0.0'
}
try:
resp = requests.get(url, headers=headers)
resp.raise_for_status()
html = resp.text
except requests.exceptions.RequestException as err:
print(f"请求错误: {err}")
return []
soup = bs(html, 'html.parser')
comment_div_lits = soup.find_all('div', class_='comment')
for item in comment_div_lits:
if item.find('p'):
eachCommentList.append(item.find('p').text.strip())
return eachCommentList
这个函数可以获取指定页面的评论内容,每页有20条评论。我们通常会抓取多页评论以获得足够的数据量。
4. 数据处理与清洗
4.1 数据清洗流程
获取到原始评论数据后,需要经过以下处理步骤:
- 合并所有评论:将多页评论合并为一个长文本
- 去除特殊字符:使用正则表达式去除非中文字符和标点
- 中文分词:使用jieba进行分词和关键词提取
- 停用词过滤:移除无意义的常见词汇
4.2 具体实现代码
python复制# 合并评论
commentList = []
for i in range(1, 11): # 爬取1-10页评论
comments_temp = getCommentsById(movieId, i)
commentList.extend(comments_temp)
comments = " ".join(commentList)
# 清洗数据
pattern = re.compile(r'[^\w\s]') # 去除非字母数字和空格的字符
cleaned_comments = pattern.sub('', comments)
# 中文分词和关键词提取
result = jieba.analyse.textrank(cleaned_comments, topK=150, withWeight=True)
keywords = {word: weight for word, weight in result}
# 停用词过滤
stopwords = set(STOPWORDS)
with open('./StopWords.txt', encoding="utf-8") as f:
stopwords.update(word.strip() for word in f)
keywords = {word: score for word, score in keywords.items() if word not in stopwords}
注意:StopWords.txt是一个停用词表文件,包含常见无意义词汇如"的"、"了"等。可以从GitHub上找到中文停用词表资源。
5. 词云生成与定制
5.1 WordCloud基础使用
wordcloud库的核心是WordCloud类,基本用法如下:
python复制from wordcloud import WordCloud
wc = WordCloud(
font_path="simhei.ttf", # 指定中文字体
background_color="white", # 背景色
max_words=200, # 最大词数
max_font_size=100 # 最大字体大小
)
wc.generate_from_frequencies(keywords) # 从词频生成词云
5.2 关键参数详解
WordCloud提供了丰富的定制选项,以下是一些重要参数:
font_path:指定中文字体路径,否则无法显示中文width/height:词云图片的宽高,默认400x200background_color:背景颜色,默认为黑色max_words:显示的最大词数,默认200stopwords:停用词集合mask:指定词云形状的遮罩图片colormap:设置颜色映射,如"viridis"、"plasma"等
5.3 高级定制技巧
5.3.1 使用遮罩图片
要让词云呈现特定形状,可以使用mask参数:
python复制from PIL import Image
import numpy as np
mask = np.array(Image.open("shape.png"))
wc = WordCloud(mask=mask, background_color="white")
提示:遮罩图片中白色部分将不会被填充,其他颜色区域会用于显示文字。
5.3.2 从图片提取颜色
可以让词云颜色与遮罩图片保持一致:
python复制from wordcloud import ImageColorGenerator
image_colors = ImageColorGenerator(mask)
wc.recolor(color_func=image_colors)
5.3.3 调整布局参数
prefer_horizontal:控制词语水平排列的概率(0-1)relative_scaling:词频与字体大小的关联强度collocations:是否考虑词语搭配
6. 完整实现与效果展示
6.1 主函数实现
将前面各模块组合起来,完整的main函数如下:
python复制def main():
# 获取正在上映电影列表
NowPlayingMovie_list = getNowPlayingMovieList()
if not NowPlayingMovie_list:
print("没有获取到电影列表")
return
# 选择第一部电影获取评论
movieId = NowPlayingMovie_list[0]['id']
movieName = NowPlayingMovie_list[0]['name']
print(f"正在处理电影: {movieName}")
# 获取并处理评论
commentList = []
for i in range(1, 11): # 爬取1-10页评论
comments_temp = getCommentsById(movieId, i)
commentList.extend(comments_temp)
print(f"已获取第{i}页评论,当前总数: {len(commentList)}")
comments = " ".join(commentList)
pattern = re.compile(r'[^\w\s]')
cleaned_comments = pattern.sub('', comments)
# 分词和关键词提取
result = jieba.analyse.textrank(cleaned_comments, topK=150, withWeight=True)
keywords = {word: weight for word, weight in result}
# 停用词过滤
stopwords = set(STOPWORDS)
with open('./StopWords.txt', encoding="utf-8") as f:
stopwords.update(word.strip() for word in f)
keywords = {word: score for word, score in keywords.items() if word not in stopwords}
# 生成词云
wordcloud = WordCloud(
font_path="simhei.ttf",
background_color="white",
max_words=200,
max_font_size=80,
width=800,
height=600,
stopwords=stopwords
).generate_from_frequencies(keywords)
# 显示词云
plt.figure(figsize=(12, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.title(f"《{movieName}》豆瓣评论词云", fontsize=16)
plt.show()
# 保存词云图片
wordcloud.to_file(f"{movieName}_wordcloud.png")
print('词云生成完成!')
6.2 效果展示
运行程序后,会生成类似下面的词云图:

从词云中可以直观看出观众对电影的评价关键词,如"特效"、"剧情"、"演技"等高频词会以较大字体显示。
6.3 形状定制效果
如果使用遮罩图片,可以得到更有创意的词云形状:

7. 常见问题与解决方案
7.1 中文显示为方框
问题:生成的词云中中文显示为方框或乱码。
原因:未指定中文字体或字体路径错误。
解决方案:
- 确保系统中存在中文字体文件(.ttf)
- 正确指定font_path参数:
python复制wc = WordCloud(font_path="simhei.ttf") # 使用黑体
7.2 词云形状不符合预期
问题:使用mask参数后词云形状与预期不符。
原因:遮罩图片不符合要求。
解决方案:
- 确保遮罩图片背景为纯白色(#FFFFFF)
- 形状部分使用其他颜色
- 图片分辨率不宜过高,建议800×600左右
7.3 爬虫被封禁
问题:请求被豆瓣拒绝或返回403错误。
原因:请求频率过高或被识别为爬虫。
解决方案:
- 增加请求间隔时间:
python复制import time time.sleep(1) # 每次请求间隔1秒 - 更换User-Agent字符串
- 使用代理IP(需谨慎)
7.4 分词效果不理想
问题:jieba分词结果不准确,重要词汇被拆分。
解决方案:
- 添加自定义词典:
python复制jieba.load_userdict("userdict.txt") - 调整分词模式:
python复制jieba.cut(text, cut_all=False) # 精确模式 - 使用jieba.analyse提取关键词而非全部分词
8. 项目优化与扩展
8.1 性能优化建议
- 缓存已爬取数据:将评论数据保存到本地文件或数据库,避免重复爬取
- 多线程爬取:使用concurrent.futures提高爬取效率
- 增量更新:记录已爬取的评论ID,只获取新评论
8.2 功能扩展方向
- 情感分析:结合SnowNLP等库分析评论情感倾向
- 时间趋势分析:按时间维度分析评论关键词变化
- 多电影对比:生成多部电影的对比词云
- 交互式词云:使用pyecharts创建可交互的词云图
8.3 实际应用场景
- 影视分析:快速了解观众对电影的评价焦点
- 产品反馈:分析用户评论中的高频需求和问题
- 舆情监控:追踪社交媒体话题关键词
- 教学演示:数据分析和可视化教学案例
我在实际使用中发现,词云虽然直观,但要获得有意义的分析结果,关键在于数据清洗和停用词设置。建议多尝试不同的停用词组合,并关注中低频但可能具有分析价值的关键词。