新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python爬虫实战:从豆瓣短评到中文词云生成保姆级教程

发布时间:2026/10/1 12:27:50来源:尧图网络
Python爬虫实战:从豆瓣短评到中文词云生成保姆级教程
前两天帮朋友处理了一个小需求把一部电影在豆瓣上的最新短评爬下来生成一张词云图看看观众都在聊什么。当时顺手写了个Python脚本从requests爬评论到jieba分词再到wordcloud生成词云前后加起来不到两百行。朋友看完直呼“就这么简单”所以今天把这套流程整理成一份完整教程放出来。标题里三个关键词——Python、网络爬虫、词云wordcloud——正好覆盖了从数据采集到可视化输出的整个链路这也是很多入门者最想一次性打通的一条线。这篇文章会带着你从零开始先搭好Python环境和爬虫依赖再实际爬取豆瓣最新评论然后把评论内容清洗、分词最后生成矩形、圆形、心形、白底黑字等各式词云。无论你是刚装好Python还没摸清语法的纯新手还是写了几个小爬虫想再学点可视化技巧的老手这篇文章都能直接照着抄作业。1. 整体设计与思路拆解1.1 项目目标与完整数据链路这个项目说白了就是一条数据流水线从豆瓣短评页面把观众写的最新评论抓下来切成一个个有意义的词再按照词频高低把高频词放大、低频词缩小拼出一张有观赏性的图形。整条链路分四步。第一步是数据采集用requests向豆瓣电影短评页面发送HTTP请求拿回HTML响应第二步是解析提取用BeautifulSoup定位页面里的评论节点把评论文本全部抠出来第三步是文本加工调用jieba做中文分词顺便把“我们”“这个”“真的”这类对主题表达毫无帮助的停用词过滤掉第四步是可视化把处理后的词列表交给wordcloud设置字体、背景、mask蒙版输出成PNG图片。之所以要把这四个环节拆开讲是因为后面排查问题基本都是按环节定位的。比如生成的词云带乱码那大概率是第四步字体问题词云里冒出一堆“我们”“你们”那问题出在第三步停用词没过滤干净压根没爬到数据那要回到第一步看请求头或Cookie。脑子里有了这条链路再往下走就清楚自己在干嘛了。1.2 为什么选豆瓣评论当练手案例想练爬虫第一反应都是去爬豆瓣。不光是它的页面结构规整更因为短评内容是现成的优质中文文本。具体来说豆瓣短评有几点很适合拿来入门。第一页面是静态的。豆瓣短评的HTML由服务端直接渲染评论内容就在标签结构里不需要处理动态加载和XHR接口对新手友好得多。第二数据结构规整。每一条短评都被包在classcomment-item的div里正文放在span.short用户和评分有各自的标签选对CSS选择器之后一抓一个准。第三评论语言质量高。豆瓣用户写短评往往有个人判断高频词能直观反映大众对电影的讨论焦点比如“特效”“剧情”“演技”“泪点”生成的词云一眼就能看出门道。当然也要说清楚豆瓣近两年对未登录用户看短评做了限制这个后面会给出解决方案。只需要把浏览器里的Cookie带进请求头就能正常抓取不影响学习流程。1.3 核心工具选型解析项目里要装的Python库有requests、beautifulsoup4、lxml、jieba、wordcloud、matplotlib、numpy、Pillow。下面这张表是我选定它们的原因也列了备选方案供参考。环节推荐库备选方案选择理由网络请求requestsurllib语法简洁、自动处理编码、会话复用方便HTML解析beautifulsoup4 lxml正则表达式选择器直观页面改版后调整成本低中文分词jiebasnownlp、thulac使用简单、支持自定义词典、生态成熟词云生成wordcloudstylecloud、pyecharts原生支持mask蒙版和自定义字体可控性强图片处理Pillow numpyOpenCV生成和读取mask图片够用没有额外安装负担很多老教程喜欢用正则从HTML里抠数据不是说不行而是页面结构一改你就得跟着改一大堆匹配规则。换成BeautifulSoup用CSS选择器之后维护成本低得多。词云库这里wordcloud是社区里积累最久、文档最全的选择而且支持mask蒙版这才是后面能生成心形、圆形造型的关键。2. 环境准备与核心细节解析2.1 Python环境安装与虚拟环境配置先把环境捣鼓好。很多入门者不是卡在代码上而是卡在Python装不上、库装不对。第一步是下载Python安装包。Windows用户去官网下载3.9到3.12之间任意稳定版本安装时一定记得勾选Add Python to PATH不然命令行里敲python会没反应。macOS用户用brew install python3.11就行。装完Python后我强烈建议建一个虚拟环境这样这个项目单独装一套库不会和系统其它项目互相污染。在项目根目录执行python -m venv wordcloud_env进入虚拟环境Windows是wordcloud_env\Scripts\activatemacOS/Linux是source wordcloud_env/bin/activate。接着一次性安装依赖pip install requests beautifulsoup4 lxml jieba wordcloud matplotlib numpy pillow如果你用的VS Code装完后按CtrlShiftP打开命令面板搜索“Python: Select Interpreter”把解释器指到刚才建的wordcloud_env路径下运行代码时才会走到虚拟环境里。这一步我见过太多新手漏掉结果终端里明明是venv编辑器却还在用全局Python导致库永远找不到代码始终报ModuleNotFoundError。2.2 发送HTTP请求的关键细节环境准备好之后真正写爬虫前得先把HTTP请求的基础打好。所谓爬虫本质上就是用程序代替人重复发送HTTP请求并解析响应。豆瓣这类网站做基础反爬第一个检测项就是User-Agent。如果requests请求头里没有UA服务器很可能直接拒绝访问或者返回异常页面。所以我习惯在headers里放一个完整的浏览器UA让请求看起来像Chrome发出的。headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept-Language: zh-CN,zh;q0.9, # Cookie: 登录豆瓣后复制浏览器里的Cookie到这里 }Accept-Language告诉服务器希望返回中文页面可以避免拿到默认语言不对的页面。第二是超时与重试。requests不设timeout的话一旦服务器不响应脚本会一直挂在那里。给请求加上timeout10超时后再捕获异常重试整个脚本才不会在某个页面卡死。第三是分页参数。豆瓣短评列表的URL长这样https://movie.douban.com/subject/{电影ID}/comments其中srotnew_score表示按最新排序start0表示从第0条开始每页最多返回20条。爬下一页只需要把start变成20、40这个逻辑不复杂但新手经常忘记把start写进params里结果翻来覆去只爬到第一页。2.3 HTML解析与评论提取拿到HTML响应之后不要急着用正则匹配先用BeautifulSoup解析成DOM结构再操作。豆瓣短评页面的评论文本在classcomment-item的div下面定位选择器是.comment-item .short。用select(.comment-item .short)能一次性拿到当前页全部评论节点然后逐个取.text并strip掉首尾空白。这样做的好处是页面改版时往往只需要微调选择器而不需要重写整个解析逻辑。清洗这一步别偷懒。我从页面抠出来的文本可能带有换行、多个空格甚至混进一些无关字符。最简单的方式是content node.text.strip().replace(\n, )处理完的评论先写进一个列表等所有页抓完再统一落盘。如果某个页面没有正常返回评论BeautifulSoup会解析出一个空列表代码里要判断一下列表为空就停掉翻页避免继续空转。3. 实操过程与核心环节实现3.1 爬取豆瓣短评数据先贴完整代码后面一行行解释关键位置。这个脚本用《流浪地球2》演示电影ID是35456179。import time import random import requests from bs4 import BeautifulSoup MOVIE_ID 35456179 # 流浪地球2可换成其它电影ID COMMENT_URL fhttps://movie.douban.com/subject/{MOVIE_ID}/comments headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept-Language: zh-CN,zh;q0.9, # Cookie: 登录豆瓣后复制浏览器里的Cookie到这里, } def fetch_comments(url, params): try: resp requests.get(url, headersheaders, paramsparams, timeout10) if resp.status_code ! 200: print(f请求失败{resp.status_code}) return [] soup BeautifulSoup(resp.text, lxml) nodes soup.select(.comment-item .short) return [node.text.strip().replace(\n, ) for node in nodes] except Exception as e: print(f请求异常{e}) return [] all_comments [] for page in range(5): params { sort: new_score, status: P, start: page * 20, limit: 20, } comments fetch_comments(COMMENT_URL, params) if not comments: print(没有拿到评论停止翻页) break all_comments.extend(comments) print(f第{page 1}页抓到{len(comments)}条累计{len(all_comments)}条) time.sleep(random.uniform(1, 3)) with open(comments.txt, w, encodingutf-8) as f: f.write(\n.join(all_comments)) print(爬取结束评论已保存到 comments.txt)这里有几个关键点。一是params不要手拼到URL里用params参数传给requests它会自己处理编码。二是每次翻页start递增20循环5页能攒下100条评论对词云来说够了想多爬就多循环几页。三是最后用sleep做随机延时不要每秒发一次请求既是为了自己的IP不被封也是给豆瓣服务器少添点麻烦。如果运行后发现页面提示需要登录或者只返回一页就在headers里把Cookie那一行补上。打开浏览器登录豆瓣按F12切到Network面板随便找一条请求从请求头里复制Cookie值粘贴到代码里即可。注意复制的时候别把换行带进去Cookie就是一行字符串。提示Cookie相当于你的登录凭证千万别随手传到GitHub或者公共代码仓库里泄露后别人可以直接拿你的账号身份操作。3.2 分词与停用词过滤评论爬下来之后是一个个完整的句子直接扔给wordcloud效果会很差因为wordcloud默认按空格切分词中文句子没有空格它会把一整句当成一个词块。所以要先分词。import jieba import string with open(comments.txt, r, encodingutf-8) as f: text f.read() stopwords set(的 了 是 我 你 他 她 它 我们 你们 他们 这个 那个 一个 真的 就是 觉得 但是 电影 很 太 有 在.split()) punctuation set(string.punctuation 。、“”‘’《》【】…—) words jieba.lcut(text) filtered [ w.strip() for w in words if w.strip() and len(w.strip()) 1 and w.strip() not in stopwords and w.strip() not in punctuation ]这里我把常见的停用词直接写死在代码里你也可以从网上下载一份中文停用词表存成stopwords.txt然后逐行读取。实际效果更推荐把“电影”“觉得”这类评论里的高频废话也放进去因为它们对分析观众讨论焦点没有贡献。还有一句比较重要的话过滤条件里len(w.strip()) 1的意思是去掉单个字很多时候单个字的信息量不足但如果你想保留“燃”“爽”这类关键词可以把这个条件去掉。分词完成后可以用Counter看一眼词频分布验证数据质量from collections import Counter counter Counter(filtered) for word, count in counter.most_common(10): print(word, count)如果排前10的还是“我们”“真的”这类词说明停用词表不够把没用的词加进去重新跑一遍就行。3.3 生成基础词云词云的核心是wordcloud库但第一次用中文最容易踩坑的是字体。wordcloud默认字体不支持中文不指定字体就会导出一片方框或乱码。所以要给font_path传入一个中文字体路径。Windows可以直接用微软雅黑msyh.ttcmacOS用系统里的PingFang.ttcLinux可以用思源黑体。更省事的做法是到网上下载思源黑体放到项目目录路径写成相对路径换机器不踩坑。from wordcloud import WordCloud import matplotlib.pyplot as plt text_for_cloud .join(filtered) wc WordCloud( font_pathmsyh.ttc, width800, height600, background_colorwhite, max_words200, max_font_size150, random_state42, collocationsFalse, ).generate(text_for_cloud) wc.to_file(basic_wordcloud.png) plt.figure(figsize(10, 8)) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show()说几个参数的含义。width和height是画布尺寸越大图片越清晰但生成越慢。background_color控制底色white就是白底改成black就是黑底。max_words限制最多展示200个词词太多了画面会挤。max_font_size是最大字号防止特别高频的词撑爆画布。random_state是随机数种子wordcloud布局本身有随机性固定之后每次生成结果一致方便反复调参对比。collocationsFalse是我强烈建议加的wordcloud默认会去识别两个词的组合中文语境下容易把“流浪地球”这种词组拼成一个整体你想按单个词展示就把它关掉。3.4 生成各式词云圆形、心形与白底效果基础版出来之后就能玩点花样了。wordcloud的mask参数允许传一张模板图它会只在模板的非白色区域绘制词语其它区域留白这样就实现了圆形、心形等各式形状。先说圆形词云。找一张白底带黑色或彩色圆形的图片或者自己用Pillow画一张from PIL import Image, ImageDraw import numpy as np size (600, 600) img Image.new(RGB, size, white) draw ImageDraw.Draw(img) draw.ellipse((60, 60, 540, 540), fillblack) # 圆形区域填黑 img.save(circle_mask.png) mask np.array(img.convert(L))然后生成词云时把mask传进去wc WordCloud( font_pathmsyh.ttc, maskmask, background_colorwhite, max_words200, max_font_size120, random_state42, colormapBlues, ).generate(text_for_cloud) wc.to_file(circle_wordcloud.png)注意mask一旦设定width和height会失效实际尺寸由图片大小决定。想做心形词云同理关键在于准备一张“白底心形填充”的mask图。我习惯用参数方程现场画一个不发散找素材import numpy as np from PIL import Image, ImageDraw size (600, 600) img Image.new(RGB, size, white) draw ImageDraw.Draw(img) points [] scale 12 for t in range(0, 360): rad np.radians(t) x 300 scale * 16 * np.sin(rad) ** 3 y 300 - scale * ( 13 * np.cos(rad) - 5 * np.cos(2 * rad) - 2 * np.cos(3 * rad) - np.cos(4 * rad) ) points.append((x, y)) draw.polygon(points, fillblack) img.save(heart_mask.png)如果你不想自己画也能直接下载一张白底红色心形PNG只要背景是纯白、心形区域不是白色就行。这里有个容易踩的坑很多素材背景不是纯白带渐变或半透明直接转数组后背景区域也会被填词。判断标准很简单用PIL打开后缩略图看看四个角是否都是纯白像素。生成经典“白底心形红字”词云的完整代码from wordcloud import WordCloud import matplotlib.pyplot as plt import numpy as np from PIL import Image mask np.array(Image.open(heart_mask.png).convert(L)) wc WordCloud( font_pathmsyh.ttc, maskmask, background_colorwhite, max_words200, max_font_size120, random_state42, collocationsFalse, contour_width2, contour_colorcrimson, colormapReds, ).generate(text_for_cloud) wc.to_file(heart_wordcloud.png) plt.figure(figsize(8, 8)) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.show()这里再讲两个参数。contour_width和contour_color是给形状描边数值越大边越粗颜色用crimson这种和Reds配色接近的红色会显得协调。colormap控制文字配色想做出白底红字的心形词云效果就用Reds。想换风格的话背景改成black、colormap改成plasma又是另一番感觉。其他任意形状也完全是同一套思路。比如想生成猫形、五角星、地图形状只需要找到对应的白底剪影图传给mask就行代码都不用变。4. 常见问题与排查技巧实录4.1 高频问题速查表把这段时间实操时遇到的问题整理成了一张速查表方便你将来对号入座问题现象可能原因解决办法词云图全是方框/乱码没设置font_path给WordCloud传入中文字体路径词云只有一两个超大词其它糊成一片max_words太小或者停用词没过滤干净加大max_words完善停用词表输出图片边缘有白色块mask图片背景不纯白换纯白底素材或用PIL重新生成爬到几页后返回403/429请求频率太高或UA被识别加随机延时、换UA必要时补Cookie评论总是抓不到、解析结果为空Cookie过期或页面结构改版登录后重新复制Cookie检查选择器命令行打印中文报UnicodeEncodeErrorWindows控制台默认编码问题先把数据写入文件不要直接print大量中文词云显示“流浪地球”而不是“流浪”“地球”wordcloud默认合并了bigram加上collocationsFalsemask无效或者报图片读取错误图片路径不对或mask带透明通道检查路径确保图片是RGB/灰度模式4.2 反爬与稳定性实战心得爬虫这一块最容易被新手忽略的是稳定性。我第一次爬豆瓣时傻乎乎地每秒发一次请求结果爬到第三页就被拦了后面半小时都在等解封。后来学乖了有几个习惯真的建议大家养成。第一请求间隔做随机化。time.sleep(random.uniform(1, 3))和固定sleep差别很大随机间隔能让请求节奏更接近真实用户操作。第二失败重试。requests请求偶尔会因为网络波动抛异常我的fetch_comments函数里用try/except兜底了但这只是最低保障。更稳妥的做法是重试三次每次间隔递增for attempt in range(3): try: resp requests.get(url, headersheaders, paramsparams, timeout10) break except Exception as e: print(f第{attempt 1}次请求失败{e}) time.sleep(attempt * 3)第三把中间数据落盘。每次跑完脚本评论、清洗后的词都要保存成文件。我之前就是没存清洗后的词列表调整参数重跑时发现原始评论又变了前后对比搞得一团乱。第四别硬扛登录限制。豆瓣短评没登录能看的页数很有限与其频繁换代理硬扛不如登录后带Cookie跑稳定得多。4.3 词云美化的进阶建议基础能跑通接下来就能琢磨怎么让词云更好看了。分享几个实际经验。字体是出效果的第一要素。同一个心形图用默认黑体做的效果偏硬换成年轮体、圆体气质立刻不一样。推荐思源黑体、站酷小薇LOGO体这类开源字体注意商用前确认授权。配色别用单一纯色colormap换个参数效果差异巨大viridis、magma、plasma、Reds、Oranges这几个我轮流试过都挺稳定。想自定义配色还可以传一个函数根据词频返回不同颜色做出深浅变化。布局参数也值得调。prefer_horizontal默认是0.9表示90%的词横向排布改成0.5就会横竖各半适合窄长图。relative_scaling决定词频对字号的影响程度默认0.5想突出高频词就调到0.8。最后是小图和大图的区别想发公众号或者做PPT建议把width、height设到1600x1200配合scale2再放大一圈导出图片细节更清楚放大也不会糊。生成速度会慢一些但效果完全值得。最后说一个我个人的体会爬虫和词云单独拿出来都不难难的是把它们串成一条完整链路并且在每个环节都留好缓存、兜底和错误提示。只要一次跑通了剩下的玩法就多了。比如把评论按时间分成前后两组分别生成两张词云对比就能直观看到观众关注点的变化或者把词频数据导出成Excel结合评分做进一步分析。写这份教程的时候我顺手把最后生成的心形词云打印出来贴在了工位旁边别的不说视觉上确实挺有成就感。你完全可以照这个流程动手跑一次改一两个参数就会发现自己也能做出挺专业的词云图。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

用CC-Switch统一管理DeepSeek与Codex API接入全指南 2026/10/2 5:21:32

用CC-Switch统一管理DeepSeek与Codex API接入全指南

如果你手头同时有 DeepSeek 的 API Key,又装好了 Codex CLI,大概率会遇到同一个问题:两边各自为战,切来切去非常别扭。我一度在手动改config.toml和重新配置环境变量之间反复折腾,后来拿到 CC-Switch 这个开源切换工具…

阅读更多 →
Windows 10家庭中文版启用WSL 2完整实践与避坑指南 2026/10/2 5:21:32

Windows 10家庭中文版启用WSL 2完整实践与避坑指南

手边这台笔记本预装的就是Windows 10 家庭中文版,出厂状态下一堆东西是锁着的:没有组策略编辑器,没有 Hyper-V 管理器,控制面板里也找不到完整的虚拟化入口。但项目里要用到的编译链、脚本工具和几个只在 Linux 下跑得顺的服务&am…

阅读更多 →
手写数据挖掘十大算法:k-means、kNN、CART源码实战与避坑指南 2026/10/2 5:21:32

手写数据挖掘十大算法:k-means、kNN、CART源码实战与避坑指南

简介:数据挖掘十大经典算法的Python实现源代码包,覆盖关联规则、分类、回归、聚类、混合模型与链接分析等核心任务,面向数据挖掘初学者、课程设计学生和算法研发人员,帮助解决从理论到代码落地之间的难题。压缩包仅15个文件&#…

阅读更多 →
基于机器学习的信用评分卡搭建:WOE分箱、模型选型与分数映射 2026/10/2 5:21:32

基于机器学习的信用评分卡搭建:WOE分箱、模型选型与分数映射

简介:面向金融风控与数据建模人员的信用风险评分系统完整实现,基于机器学习对信用卡申请历史数据进行清洗、特征工程与建模,输出信用风险等级评估,帮助银行、消费金融等机构高效筛选高风险客户,提升审批效率与自动化水…

阅读更多 →
少女与机甲绘画指南:佛系更图如何凭练习图圈粉 2026/10/2 5:21:32

少女与机甲绘画指南:佛系更图如何凭练习图圈粉

1. 从“少女与机甲”这个组合说起第一次看到“少女与机甲”这个题材,我脑子里蹦出来的不是高达,也不是EVA,而是一个很具体的画面:一个穿着宽松卫衣的女孩,坐在一堆机械零件中间,手里拿着扳手,脸…

阅读更多 →
DINOv3微调与层解冻:数据量决定该动多少参数 2026/10/2 5:21:26

DINOv3微调与层解冻:数据量决定该动多少参数

直接说结论:这个问题的答案没那么玄,核心就是一句话——你的数据量和目标分布决定了你动多少参数。但我猜你问这个问题,多半是已经被各种教程里"微调""解冻""冻结backbone"的说法绕晕了,而且想搞清…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉