实战!Python爬京东商品评论:从采集到情感分析+词云可视化,新手30分钟跑通
电商商品评论里藏着黄金数据——用户对产品的真实反馈、痛点需求、满意度评价,不管是做市场调研、产品优化还是竞品分析,都是核心素材。但手动复制评论效率太低,用Python不仅能批量爬取,还能自动做情感分析、生成词云,快速提炼关键信息。
本文以京东商品为例(反爬宽松、结构清晰,新手友好),全程实战「评论爬取→数据清洗→情感分析→词云生成」全流程,用最基础的技术栈(requests+BeautifulSoup+SnowNLP),不用复杂配置,30分钟就能从0到1跑通,还能理解数据处理的核心逻辑。
一、核心流程与技术栈
1. 整体流程(新手必记)
- 爬取评论:向电商评论页发送请求,获取用户评论、评分、时间等数据;
- 数据清洗:过滤无效评论(空评论、重复评论)、处理特殊字符,让数据更干净;
- 情感分析:用中文情感分析库(SnowNLP)给评论打分(0-1分,越接近1越正面);
- 词云生成:拆分评论关键词,过滤无意义词汇(如“的”“了”),生成可视化词云;
- 结果展示:用图表呈现情感分布、关键词频率,直观看懂用户反馈。
2. 技术栈选型(新手友好,无需复杂配置)
| 功能 | 库/工具 | 作用说明 |
|---|---|---|
| 网络请求 | requests | 模拟浏览器获取评论页HTML数据 |
| 页面解析 | beautifulsoup4 | 从HTML中提取评论、评分、时间等字段 |
| 数据处理 | pandas | 存储数据、清洗数据、统计分析 |
| 中文情感分析 | snownlp | 轻量中文情感识别,无需训练,直接调用 |
| 中文分词 | jieba | 拆分评论为关键词(如“续航给力”→[续航, 给力]) |
| 词云生成 | wordcloud | 可视化关键词频率,生成美观词云图 |
| 图表展示 | matplotlib | 绘制情感分布柱状图、评分分布饼图 |
3. 环境准备(5分钟搞定)
(1)安装Python
已安装的跳过,未安装的去官网下载:https://www.python.org/downloads/(推荐3.8-3.11版本),安装时Windows勾选“Add Python to PATH”,Mac默认自动配置。
验证是否成功:终端输入 python --version(或python3 --version),显示版本号即可。
(2)安装核心库
终端复制粘贴以下命令(国内用户下载慢可先换清华源:pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple):
pip installrequests==2.31.0 beautifulsoup4==4.12.3 pandas==2.2.2 pip installsnownlp==0.12.3 jieba==0.42.1 wordcloud==1.9.3 matplotlib==3.8.4 二、第一步:爬取京东商品评论(核心实战)
1. 目标分析:京东评论页结构
先搞清楚评论数据藏在哪里,这是爬虫的关键:
- 打开京东任意商品页(比如:https://item.jd.com/100012345678.html),下拉到“商品评价”,点击“查看全部评价”;
- 按F12打开Chrome开发者工具,切换到「Elements」标签,用左上角“箭头图标”点击任意一条评论,右侧会定位到对应的HTML代码;
- 关键发现:
- 每一条评论都包裹在
<div>标签中; - 评论内容:
<p>; - 评分:
<div>(通过class中的“star-X”判断,X=1-5); - 用户名:
<div>; - 评论时间:
<span>;
- 每一条评论都包裹在
- 分页逻辑:评论页的分页参数是
page,比如第1页page=1,第2页page=2,URL格式为:https://club.jd.com/comment/productPageComments.action?productId=商品ID&score=0&page=页码&pageSize=10。
核心参数说明:
productId:商品唯一ID(从商品详情页URL中提取,比如上面链接的100012345678);score:评分筛选(0=全部评论,1=差评,2=中评,3=好评);pageSize:每页评论数(默认10条,可改20条,太多易被反爬)。
2. 爬取代码(带详细注释)
import requests from bs4 import BeautifulSoup import pandas as pd import time import random # ---------------------- 配置参数(新手只需修改这3处)---------------------- PRODUCT_ID ="100012345678"# 商品ID(从京东商品页URL提取) MAX_PAGE =5# 爬取页数(1页10条,5页=50条,新手先测试3-5页) HEADERS ={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/128.0.0.0 Safari/537.36","Referer":f"https://item.jd.com/{PRODUCT_ID}.html",# 模拟从商品页跳转,更像真实用户"Cookie":"你的京东Cookie"# (可选)登录京东后F12复制Cookie,避免爬取受限(不填也能爬少量数据)}# ------------------------------------------------------------------------defcrawl_jd_comments():"""爬取京东商品评论""" all_comments =[]# 存储所有评论数据 base_url ="https://club.jd.com/comment/productPageComments.action"print(f"开始爬取商品ID:{PRODUCT_ID} 的评论,共{MAX_PAGE}页...")for page inrange(1, MAX_PAGE +1):# 构造当前页评论URL params ={"productId": PRODUCT_ID,"score":0,# 0=全部评论,1=差评,2=中评,3=好评"page": page,"pageSize":10,"isShadowSku":0,"rid":0,"fold":1}try:# 发送请求(添加随机延迟,避免高频反爬) time.sleep(random.uniform(0.8,1.5)) response = requests.get( url=base_url, headers=HEADERS, params=params, timeout=10) response.raise_for_status()# 状态码非200抛出异常 response.encoding ="gbk"# 京东评论页编码为GBK,避免中文乱码# 解析HTML(京东评论页是静态HTML,直接用BS4解析) soup = BeautifulSoup(response.text,"lxml") comment_items = soup.find_all("div", class_="comment-item")ifnot comment_items:print(f"第{page}页未找到评论,可能已爬取到最后一页")break# 提取每条评论的核心字段for item in comment_items:# 评论内容(容错:无内容则填“无评论”) comment_con = item.find("p", class_="comment-con") content = comment_con.text.strip()if comment_con else"无评论"# 评分(从class中提取,如"star-5"→5分) star_div = item.find("div", class_="comment-star") score = star_div["class"][1].split("-")[1]if star_div else"0"# 用户名 user = item.find("div", class_="comment-user").text.strip()if item.find("div", class_="comment-user")else"匿名用户"# 评论时间 comment_time = item.find("span", class_="comment-time").text.strip()if item.find("span", class_="comment-time")else"未知时间"# 存入列表 all_comments.append({"用户名": user,"评分": score,"评论内容": content,"评论时间": comment_time })print(f"第{page}页爬取完成,新增{len(comment_items)}条评论,累计{len(all_comments)}条")except Exception as e:print(f"第{page}页爬取失败:{str(e)}")continue# 转换为DataFrame,方便后续处理 df = pd.DataFrame(all_comments)return df # 测试爬取if __name__ =="__main__": comment_df = crawl_jd_comments()# 保存为CSV(可选,方便查看原始数据) comment_df.to_csv("京东商品评论_原始数据.csv", index=False, encoding="utf-8-sig")print(f"\n爬取完成!共获取{len(comment_df)}条评论,原始数据已保存为CSV文件")3. 关键配置修改(新手必看)
- 修改
PRODUCT_ID:打开京东商品页,从URL中复制商品ID(比如https://item.jd.com/100012345678.html的ID是100012345678); - 可选:添加Cookie:登录京东后,按F12→「Network」→任意请求→「Headers」→复制
Cookie字段,粘贴到HEADERS中,可避免爬取页数受限; - 运行代码:复制代码到编辑器(VS Code/PyCharm),点击运行,终端会输出爬取进度,完成后生成
京东商品评论_原始数据.csv。
三、第二步:数据清洗(让数据更干净)
爬取的原始数据可能有重复、空评论、特殊字符等“噪音”,需要清洗后再做分析,否则会影响结果准确性:
defclean_comments(df):"""数据清洗:去重、过滤无效评论、处理字段格式"""print("\n开始数据清洗...")# 1. 去重(根据“评论内容+用户名”去重,避免重复爬取) df_clean = df.drop_duplicates(subset=["评论内容","用户名"], keep="first")# 2. 过滤无效评论(空评论、评论长度<2字的无意义评论) df_clean = df_clean[df_clean["评论内容"].str.len()>=2]# 3. 处理评分格式(转换为整数类型) df_clean["评分"]= pd.to_numeric(df_clean["评分"], errors="coerce").fillna(0).astype(int)# 4. 过滤特殊字符(只保留中文、数字、字母,去除表情/符号) df_clean["评论内容"]= df_clean["评论内容"].str.replace(r"[^\u4e00-\u9fa5a-zA-Z0-9\s]","", regex=True)# 5. 重置索引 df_clean = df_clean.reset_index(drop=True)print(f"清洗完成!原始数据{len(df)}条,清洗后{len(df_clean)}条")return df_clean # 调用清洗函数(承接上一步的comment_df) df_clean = clean_comments(comment_df)# 保存清洗后的数据 df_clean.to_csv("京东商品评论_清洗后数据.csv", index=False, encoding="utf-8-sig")print("清洗后的数据已保存为CSV文件")清洗效果对比
| 原始数据问题 | 清洗后效果 |
|---|---|
| 重复评论、空评论 | 已删除 |
| 评分是字符串(如"5") | 转换为整数(5) |
| 评论含表情、特殊符号(如“👍”) | 只保留中文、数字、字母 |
| 无意义短评论(如“好”) | 保留(长度≥2字,有参考价值) |
四、第三步:情感分析(给评论“打分”)
用SnowNLP做中文情感分析,无需复杂训练,直接调用接口即可——它会给每条评论打一个0-1分的情感得分,越接近1表示越正面,越接近0表示越负面。
情感分析代码
from snownlp import SnowNLP defanalyze_sentiment(df):"""情感分析:给每条评论打分,分类正面/中性/负面"""print("\n开始情感分析...")# 定义情感得分计算函数defget_sentiment_score(text): s = SnowNLP(text)returnround(s.sentiments,3)# 保留3位小数# 给每条评论计算情感得分 df["情感得分"]= df["评论内容"].apply(get_sentiment_score)# 根据得分分类(自定义阈值,可调整)defclassify_sentiment(score):if score >=0.7:return"正面"elif score <=0.3:return"负面"else:return"中性" df["情感分类"]= df["情感得分"].apply(classify_sentiment)# 统计情感分布 sentiment_count = df["情感分类"].value_counts()print("\n情感分布统计:")print(sentiment_count)# 统计评分与情感分类的对应关系(验证准确性) score_sentiment = pd.crosstab(df["评分"], df["情感分类"])print("\n评分与情感分类对应关系:")print(score_sentiment)return df # 调用情感分析函数 df_with_sentiment = analyze_sentiment(df_clean)# 保存带情感分析结果的数据 df_with_sentiment.to_csv("京东商品评论_情感分析结果.csv", index=False, encoding="utf-8-sig")print("\n情感分析完成!结果已保存为CSV文件")结果说明
- 情感得分:0.98→强烈正面(如“续航超给力,颜值也高”);
- 情感得分:0.12→强烈负面(如“质量差,用了2天就坏了”);
- 情感得分:0.5→中性(如“中规中矩,符合预期”);
- 验证逻辑:5分评论大概率是正面,1分评论大概率是负面,通过
pd.crosstab可查看匹配度(一般准确率80%以上,新手足够用)。
五、第四步:词云生成(可视化关键词)
词云能直观展示用户评论中出现频率最高的关键词,比如“续航”“颜值”“质量”等,快速抓住用户关注的核心点。
词云生成代码(解决中文显示问题)
import jieba from wordcloud import WordCloud import matplotlib.pyplot as plt import numpy as np from PIL import Image defgenerate_wordcloud(df):"""生成词云图:分别生成正面、负面评论的词云"""print("\n开始生成词云图...")# ---------------------- 准备工作:定义停用词、字体路径 ----------------------# 停用词:过滤无意义词汇(如“的”“了”“我”,可根据需求添加) stopwords =set(["的","了","是","我","在","有","和","就","都","而","及","与","也","还","很","非常","比较","一下","这个","那个","什么","怎么","没有","可以","但是","因为","所以","如果","虽然","不过","其实"])# 字体路径(关键!解决中文显示乱码问题)# Windows:默认字体路径(无需修改) font_path ="C:/Windows/Fonts/simhei.ttf"# Mac:替换为以下路径(取消注释)# font_path = "/System/Library/Fonts/PingFang.ttc"# Linux:替换为系统中文字体路径(如"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc")# ------------------------------------------------------------------------# 1. 提取正面/负面评论的所有内容 positive_comments =" ".join(df[df["情感分类"]=="正面"]["评论内容"].tolist()) negative_comments =" ".join(df[df["情感分类"]=="负面"]["评论内容"].tolist())# 2. 中文分词(将句子拆分为关键词)defcut_words(text): words = jieba.lcut(text)# 精确分词# 过滤停用词和长度<2的词 filtered_words =[word for word in words if word notin stopwords andlen(word)>=2]return" ".join(filtered_words) positive_words = cut_words(positive_comments) negative_words = cut_words(negative_comments)# 3. 定义词云样式(可自定义颜色、形状)defcreate_wordcloud(words, title, save_path):# 可选:自定义词云形状(如圆形、心形,需要提前准备图片)# mask = np.array(Image.open("circle.png")) # 替换为图片路径 mask =None# 无形状(默认矩形) wc = WordCloud( font_path=font_path,# 中文字体 width=800, height=600,# 图片大小 background_color="white",# 背景色 max_words=200,# 最多显示关键词数 mask=mask,# 自定义形状(可选) colormap="viridis"# 颜色映射(可修改为"plasma"、"coolwarm"等)).generate(words)# 显示词云图 plt.figure(figsize=(10,6)) plt.imshow(wc, interpolation="bilinear") plt.axis("off")# 隐藏坐标轴 plt.title(title, fontsize=16, fontproperties=font_path) plt.tight_layout()# 保存词云图 wc.to_file(save_path)print(f"{title}词云已保存为:{save_path}")# 生成正面、负面评论词云 create_wordcloud(positive_words,"正面评论关键词词云","正面评论词云.png") create_wordcloud(negative_words,"负面评论关键词词云","负面评论词云.png")# 调用词云生成函数 generate_wordcloud(df_with_sentiment)关键说明
- 字体路径:必须指定中文字体,否则词云会显示方块乱码,Windows/Mac/Linux的字体路径已标注,按需修改;
- 停用词:可根据实际评论添加更多无意义词汇(如“京东”“商品”“购买”等与评价无关的词);
- 自定义形状:准备一张白色背景的图片(如圆形、心形),替换
mask参数的图片路径,即可生成对应形状的词云。
六、第五步:结果可视化(直观展示分析结论)
用matplotlib绘制情感分布柱状图和评分分布饼图,让分析结果更直观:
defvisualize_results(df):"""结果可视化:情感分布柱状图、评分分布饼图"""print("\n开始生成可视化图表...")# 字体设置(解决中文显示问题) plt.rcParams['font.sans-serif']=['SimHei']# Windows:黑体# plt.rcParams['font.sans-serif'] = ['PingFang SC'] # Mac:苹方 plt.rcParams['axes.unicode_minus']=False# 解决负号显示问题# 1. 情感分布柱状图 plt.figure(figsize=(10,5)) sentiment_count = df["情感分类"].value_counts() bars = plt.bar(sentiment_count.index, sentiment_count.values, color=["#2E8B57","#FFD700","#DC143C"])# 在柱子上添加数值标签for bar in bars: height = bar.get_height() plt.text(bar.get_x()+ bar.get_width()/2., height +0.5,f"{int(height)}条", ha="center", va="bottom", fontsize=12) plt.title("商品评论情感分布", fontsize=16) plt.xlabel("情感分类", fontsize=12) plt.ylabel("评论数量", fontsize=12) plt.grid(axis="y", alpha=0.3) plt.savefig("情感分布柱状图.png", dpi=300, bbox_inches="tight")print("情感分布柱状图已保存")# 2. 评分分布饼图 plt.figure(figsize=(8,8)) score_count = df["评分"].value_counts().sort_index() colors =["#DC143C","#FF6347","#FFD700","#9ACD32","#2E8B57"] wedges, texts, autotexts = plt.pie( score_count.values, labels=[f"{score}分"for score in score_count.index], colors=colors, autopct="%1.1f%%",# 显示百分比(保留1位小数) startangle=90)# 美化文本for autotext in autotexts: autotext.set_color("white") autotext.set_fontsize(12) plt.title("商品评论评分分布", fontsize=16) plt.savefig("评分分布饼图.png", dpi=300, bbox_inches="tight")print("评分分布饼图已保存")# 调用可视化函数 visualize_results(df_with_sentiment)七、最终成果展示
运行完所有代码后,你会得到以下文件:
- 数据文件:
京东商品评论_原始数据.csv、京东商品评论_清洗后数据.csv、京东商品评论_情感分析结果.csv; - 可视化文件:
正面评论词云.png、负面评论词云.png、情感分布柱状图.png、评分分布饼图.png。
示例成果:
- 正面词云:高频词“续航给力”“颜值高”“手感好”→用户满意点;
- 负面词云:高频词“发热”“续航短”“客服差”→产品待优化点;
- 情感分布:正面85%、中性10%、负面5%→整体用户满意度高;
- 评分分布:5分占78%、4分占15%→产品口碑较好。
八、新手避坑指南(我踩过的坑,你别再踩)
1. 爬取评论时中文乱码
- 问题:终端/CSV文件中评论显示问号;
- 解决方案:京东评论页编码是GBK,在
response.encoding = "gbk",保存CSV时用encoding="utf-8-sig"。
2. 词云显示方块乱码
- 问题:词云只有形状,没有中文关键词(全是方块);
- 解决方案:确保
font_path指向正确的中文字体文件,Windows/Mac/Linux的路径已在代码中标注。
3. 情感分析结果不准
- 问题:5分评论被判定为“中性”;
- 解决方案:调整情感分类阈值(如将正面阈值从0.7降到0.6),或过滤无意义短评论(如“好”“不错”)。
4. 爬取页数受限
- 问题:爬2-3页后就爬不到数据;
- 解决方案:登录京东后复制Cookie到
HEADERS中,或延长延迟时间(如time.sleep(random.uniform(1.5, 2.5)))。
5. 分词效果差(关键词拆分错误)
- 问题:“续航给力”被拆分为“续航”“给力”(正确),“颜值高”被拆分为“颜值”“高”(正确);若拆分错误(如“性价比”拆分为“性”“价比”);
- 解决方案:给jieba添加自定义词典,比如
jieba.add_word("性价比"),提前定义专业词汇。
九、合规与伦理说明
- 本文爬虫仅用于个人学习、数据分析,不得用于商业用途或批量爬取京东数据,避免给平台服务器造成压力;
- 爬取的数据仅包含公开的用户评论,不得泄露用户隐私(如用户名、手机号等);
- 遵守《网络安全法》和京东用户协议,若平台明确禁止爬虫,需立即停止爬取行为。
十、进阶方向(爬完这一步,下一步学什么?)
- 爬取更多数据:扩展代码爬取多商品评论,做竞品对比分析;
- 情感分析升级:用更精准的模型(如BERT、LSTM)替换SnowNLP,提升情感识别准确率;
- 实时监控评论:添加定时任务(如Celery),每天自动爬取最新评论,监控产品口碑变化;
- 多维度分析:提取评论中的“价格敏感”“功能需求”等维度,做更细致的用户画像;
- 生成分析报告:用Python自动生成Word/Excel分析报告,包含数据表格、可视化图表和结论建议。
通过本文实战,你不仅学会了爬虫,还掌握了数据清洗、情感分析、可视化的完整流程——这套逻辑适用于任何电商平台(淘宝、天猫、拼多多),只要修改页面解析的CSS选择器和URL参数,就能快速适配新需求。现在就去试试爬取你关注的商品评论,看看用户到底在吐槽什么、好评什么吧!