1. 项目概述与核心价值
最近在分析豆瓣影评数据时,我发现用Python生成词云是个直观展示观众反馈的好方法。这个教程将带你从零开始,用requests和BeautifulSoup爬取豆瓣最新评论,再用wordcloud库生成专业级词云图。不同于基础教程,我会重点分享如何通过参数调整实现不同风格的词云效果——从默认矩形到自定义形状,再到颜色渐变的高级玩法。
这个技能组合特别适合需要快速洞察文本特征的数据分析场景。比如影视公司可以据此评估观众对某部电影的关注点,自媒体作者能发现热点话题,甚至HR也能用它分析求职者简历中的技能关键词分布。下面我会用豆瓣《流浪地球2》的短评区作为示例,但方法适用于任何豆瓣条目页。
提示:本文所有代码均基于Python 3.8+环境测试通过,建议使用Jupyter Notebook分步执行
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具选型
2.1 必备库安装与版本选择
首先通过pip安装核心依赖库。这里有个版本搭配的坑要特别注意:
bash复制pip install requests==2.28.1 beautifulsoup4==4.11.1 wordcloud==1.8.2.2 matplotlib==3.6.2 jieba==0.42.1
为什么选择这些特定版本?因为:
- requests 2.28.1修复了SSL验证问题,避免豆瓣HTTPS连接报错
- wordcloud 1.8.2.2与matplotlib 3.6.2的兼容性最好,不会出现中文乱码
- jieba分词对豆瓣特有的网络用语(如"yyds")识别效果更好
2.2 反爬策略应对方案
豆瓣对爬虫有一定反制措施,需要配置这些参数:
python复制headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Cookie': '你的登录cookie(非必须)',
'Accept-Language': 'zh-CN,zh;q=0.9'
}
proxies = {
'http': 'http://代理IP:端口',
'https': 'http://代理IP:端口'
}
实测发现两个关键点:
- 不加Accept-Language头部时,豆瓣可能返回英文页面导致解析失败
- 单个IP连续请求超过20次会触发验证码,建议每爬10页随机sleep 3-8秒
3. 豆瓣评论爬取实战
3.1 页面结构分析与XPath定位
以《流浪地球2》短评页为例,其URL格式为:
code复制https://movie.douban.com/subject/35267208/comments?start=0&limit=20&status=P&sort=new_score
通过浏览器开发者工具检查元素,发现短评内容所在的HTML结构是:
html复制<div class="comment-item">
<span class="short">这个特效太震撼了!</span>
</div>
对应的XPath选择器应为:
python复制comments = soup.select('div.comment-item span.short')
但这里有个隐藏坑点:部分长评会默认折叠,需要点击"展开"才能看到完整内容。解决方法是在请求参数中添加percent_type=h来优先获取长评。
3.2 分页爬取与异常处理
完整爬取函数示例:
python复制def crawl_douban_comments(movie_id, max_pages=5):
comments = []
for page in range(max_pages):
try:
url = f"https://movie.douban.com/subject/{movie_id}/comments?start={page*20}"
resp = requests.get(url, headers=headers, proxies=proxies, timeout=10)
soup = BeautifulSoup(resp.text, 'html.parser')
# 提取当前页评论
items = soup.select('div.comment-item span.short')
comments.extend([item.text.strip() for item in items])
# 随机延迟防止封禁
time.sleep(random.uniform(3, 8))
except Exception as e:
print(f"第{page+1}页抓取失败: {str(e)}")
continue
return comments
关键注意事项:
- 一定要设置timeout参数,豆瓣服务器有时响应较慢
- 使用random.uniform而不是固定sleep时间,更模拟人类操作
- 建议将爬取结果实时保存到JSON文件,避免程序中断导致数据丢失
4. 文本预处理技巧
4.1 中文分词优化方案
直接使用wordcloud处理中文会出现词语割裂问题。我们需要先用jieba分词:
python复制import jieba
import jieba.analyse
# 添加豆瓣特有词汇到词典
jieba.add_word('yyds', freq=2000)
jieba.add_word('绝绝子', freq=2000)
text = ' '.join(comments)
# 使用TF-IDF提取关键词
keywords = jieba.analyse.extract_tags(text, topK=200, withWeight=True)
word_freq = {word: weight for word, weight in keywords}
4.2 停用词过滤清单
创建stopwords.txt文件,包含:
code复制的 了 是 我 你 他 这 那 就 都 也 很 在 一个 没有 不是 但是 什么 怎么 可以
然后加载使用:
python复制with open('stopwords.txt', 'r', encoding='utf-8') as f:
stopwords = set([line.strip() for line in f])
filtered_freq = {k:v for k,v in word_freq.items() if k not in stopwords}
5. 词云生成进阶技巧
5.1 基础词云生成
python复制from wordcloud import WordCloud
import matplotlib.pyplot as plt
wc = WordCloud(
font_path='msyh.ttc', # 微软雅黑字体
background_color='white',
max_words=200,
width=1000,
height=700,
colormap='viridis'
)
wc.generate_from_frequencies(filtered_freq)
plt.imshow(wc)
plt.axis('off')
plt.show()
5.2 自定义形状词云
首先准备一张黑白遮罩图(如地球轮廓):
python复制from PIL import Image
import numpy as np
mask = np.array(Image.open('earth_mask.png'))
wc = WordCloud(mask=mask, contour_width=3, contour_color='steelblue')
5.3 颜色渐变与方向控制
通过colormap参数实现渐变效果:
python复制# 使用matplotlib内置色图
colormaps = ['spring', 'summer', 'autumn', 'winter', 'cool', 'hot']
# 控制词语方向
wc = WordCloud(
prefer_horizontal=0.8, # 80%词语水平显示
colormap=random.choice(colormaps)
)
6. 样式优化与输出配置
6.1 边缘羽化效果
添加高斯模糊使边缘更柔和:
python复制from scipy.ndimage import gaussian_filter
def grey_color_func(word, font_size, position, orientation, random_state=None, **kwargs):
return f"hsl(0, 0%, {random.randint(60,100)}%)"
wc.recolor(color_func=grey_color_func)
image = wc.to_array()
image = gaussian_filter(image, sigma=0.5)
6.2 多图组合输出
将不同风格的词云组合对比:
python复制fig, axes = plt.subplots(2, 2, figsize=(20, 14))
styles = [
{'colormap': 'plasma', 'background_color': 'black'},
{'mask': mask, 'contour_color': 'red'},
{'prefer_horizontal': 0.3, 'colormap': 'twilight'},
{'color_func': grey_color_func}
]
for ax, style in zip(axes.flatten(), styles):
wc = WordCloud(**style).generate(text)
ax.imshow(wc)
ax.axis('off')
plt.tight_layout()
plt.savefig('combined.png', dpi=300, bbox_inches='tight')
7. 性能优化与批量处理
7.1 使用多进程加速
对于大量电影评论分析:
python复制from multiprocessing import Pool
movie_ids = ['35267208', '30174085', '30458948']
def process_movie(movie_id):
comments = crawl_douban_comments(movie_id)
wc = WordCloud().generate(' '.join(comments))
wc.to_file(f'{movie_id}.png')
with Pool(3) as p:
p.map(process_movie, movie_ids)
7.2 内存优化技巧
处理超长文本时:
python复制# 分块处理
chunk_size = 1000
for i in range(0, len(comments), chunk_size):
chunk = comments[i:i+chunk_size]
wc = WordCloud(max_words=100).generate(' '.join(chunk))
plt.figure()
plt.imshow(wc)
plt.close() # 及时释放内存
8. 实际应用案例
8.1 情感分析结合
使用SnowNLP进行情感值计算:
python复制from snownlp import SnowNLP
sentiments = [SnowNLP(c).sentiments for c in comments]
positive_words = [w for w,s in zip(comments, sentiments) if s > 0.7]
wc = WordCloud().generate(' '.join(positive_words))
8.2 时间趋势分析
按日期统计高频词:
python复制import pandas as pd
df = pd.DataFrame({
'date': pd.to_datetime(dates),
'comment': comments
})
weekly = df.resample('W', on='date')['comment'].apply(lambda x: ' '.join(x))
for week, text in weekly.items():
WordCloud().generate(text).to_file(f'{week.date()}.png')
9. 常见问题排查
9.1 中文显示为方框
解决方案:
- 确认font_path指向正确的中文字体文件
- 在WordCloud参数中添加:
python复制font_path='/System/Library/Fonts/STHeiti Medium.ttc' # Mac font_path='C:/Windows/Fonts/msyh.ttc' # Windows
9.2 词云形状不完整
可能原因:
- 遮罩图片背景不是纯白(#FFFFFF)
- 图片分辨率太低,应使用至少1000x1000像素的图片
- 尝试调整contour_width参数
9.3 高频词缺失
检查步骤:
- 确认停用词列表没有过度过滤
- 调整jieba的topK参数
- 检查WordCloud的max_words参数是否设置过小
10. 扩展应用思路
- 动态词云视频:用matplotlib.animation生成词云演变过程
- 交互式词云:使用pyecharts创建可点击放大的网页版词云
- 主题聚类:结合LDA模型先对评论分类,再为每个主题生成独立词云
- 跨平台部署:用Flask搭建Web服务,接受URL参数实时生成词云
我在实际项目中发现的几个实用技巧:
- 对科幻电影评论,添加"特效""宇宙""科技"等词到jieba词典能提升分词准确率
- 使用HSL颜色空间可以生成更协调的渐变色词云
- 将词云与豆瓣评分分布图组合展示,能更全面反映影片口碑
