ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python爬取京东评论并做中文情感分析实战

Python爬取京东评论并做中文情感分析实战 简介这份资源面向Python爬虫与自然语言处理方向的初学者及课程设计者围绕京东商品评论的采集、清洗、情感分析与可视化展开可作为数据挖掘大作业或实战练手项目。压缩包共20个文件约5.87MB以py脚本、csv数据表、txt文本、jpg与png图表为主另含zbak备份与md说明文档覆盖爬虫代码、训练脚本、情感语料及结果数据等模块。已有76人学习下载。读者可从中获得完整的评论抓取流程、数据去重与格式标准化思路、基于机器学习的情感分类实现以及词云、情感比例等可视化图表并附有原始评论、处理后数据与情感结果三类CSV文件便于对照复现与二次开发。资源来源于网络分享仅限学习交流请勿用于商业用途。1. 京东评论爬取与情感分析从零搭一套能跑通的链路京东商品评论里藏着最真实的用户反馈但很多人卡在第一步——评论数据拿不到或者拿到了不知道怎么变成结论。这个标题讲的就是一条完整链路用 Python 把京东商品评论爬下来做中文情感分析最后用可视化把结果呈现出来。适合有 Python 基础、想做一个能写进简历或直接给运营团队用的实战项目的人。整条链路的核心难点不在爬虫本身而在评论接口的翻页逻辑、中文分词的准确性以及情感得分的阈值怎么定。我做过几轮下来发现最容易被低估的是数据清洗环节——京东评论里夹杂大量默认好评、表情符号和重复内容不处理干净后面情感分析的结果基本没法看。下面按「先跑通再优化」的思路把每一步拆开讲。2. 评论数据怎么拿接口分析与翻页策略2.1 先搞清楚评论数据从哪来京东商品页的评论不是直接写在 HTML 里的而是通过异步接口加载。打开商品详情页按 F12 切到 Network 面板筛选 XHR 请求翻到评论区点击下一页就能看到类似club.jd.com/comment/productPageComments.action的请求。这个接口返回 JSON 格式的评论数据包含用户昵称、评分、评论内容、时间、点赞数等字段。关键参数有几个productId是商品 IDscore控制评论类型0 全部、1 差评、2 中评、3 好评sortType控制排序方式5 推荐排序、6 时间排序page是页码pageSize每页条数默认 10。我一般会把pageSize设成 10因为设大了容易被限制。注意京东评论接口对请求频率有隐性限制连续快速翻页会返回空数据或触发验证。建议每次请求间隔 1-2 秒翻页到 100 页左右就停再往后数据重复率高且容易触发风控。2.2 用 requests 写一个能翻页的爬虫下面是最小可运行版本核心逻辑是构造请求头、循环翻页、解析 JSON、存入列表。import requests import time import json import pandas as pd def fetch_jd_comments(product_id, max_pages50): 爬取京东商品评论 product_id: 商品ID从商品页URL中提取 max_pages: 最大翻页数建议不超过100 base_url https://club.jd.com/comment/productPageComments.action 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, Referer: fhttps://item.jd.com/{product_id}.html } all_comments [] for page in range(max_pages): params { productId: product_id, score: 0, # 0全部评论 sortType: 6, # 6按时间排序 page: page, pageSize: 10, isShadowSku: 0, fold: 1 } try: resp requests.get(base_url, paramsparams, headersheaders, timeout10) data resp.json() comments data.get(comments, []) if not comments: print(f第{page}页无数据停止翻页) break for c in comments: all_comments.append({ nickname: c.get(nickname, ), score: c.get(score, 0), content: c.get(content, ).strip(), creation_time: c.get(creationTime, ), useful_count: c.get(usefulVoteCount, 0), product_color: c.get(productColor, ), product_size: c.get(productSize, ) }) print(f第{page}页抓取{len(comments)}条) time.sleep(1.5) # 控制频率避免触发限制 except Exception as e: print(f第{page}页出错: {e}) time.sleep(3) continue df pd.DataFrame(all_comments) df.to_csv(fjd_comments_{product_id}.csv, indexFalse, encodingutf-8-sig) print(f共抓取{len(df)}条评论已保存) return df if __name__ __main__: # 替换成你要爬的商品ID fetch_jd_comments(100012043978, max_pages30)这段代码的逻辑很直白循环构造带page参数的请求解析返回 JSON 里的comments数组把需要的字段抽出来存进 DataFrame最后导出 CSV。几个参数需要根据实际情况调max_pages控制翻页上限我一般设 30-50 页就够分析用了sortType设 6 是按时间排序能拿到最新评论设 5 是按推荐排序拿到的评论质量更高但时间分布不均匀time.sleep(1.5)是请求间隔别低于 1 秒。2.3 翻页翻不动了怎么办最常见的翻车场景是爬到十几页后返回空数据。原因通常是触发了频率限制或者page参数超出了实际评论页数。排查方法很简单先手动在浏览器里翻到最后一页看最大页码是多少如果页码没超但返回空就是频率问题把time.sleep调到 3 秒以上再试。另一个坑是productId拿错了——京东商品 URL 里可能有两个 IDitem.jd.com/后面那个才是正确的商品 ID别把 SKU ID 和商品 ID 搞混。3. 中文情感分析从分词到打分3.1 为什么不用英文那套直接翻译过来中文情感分析和英文有本质区别。英文靠空格分词中文需要先做分词再判断情感。更麻烦的是中文评论里大量存在「不推荐」「不是很好」「还行吧」这类否定和模糊表达直接套用英文情感词典会翻车。我试过用 TextBlob 翻译后再分析准确率不到 60%后来换成 SnowNLP 加自定义词典才把准确率拉到 80% 以上。常见做法是先用 SnowNLP 做基础情感打分再针对京东评论的特点做后处理。SnowNLP 返回的是 0 到 1 之间的情感得分越接近 1 越正面越接近 0 越负面。但它的默认模型是在电商评论上训练的对京东数据有一定适配性不过遇到「手机壳手感不错但物流太慢」这种混合情感就会失准。3.2 SnowNLP 基础打分与阈值调整from snownlp import SnowNLP import pandas as pd import re def clean_text(text): 清洗评论文本去表情、去特殊符号、去多余空格 if not isinstance(text, str): return # 去掉表情符号和特殊字符 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、], , text) # 去掉连续重复字符 text re.sub(r(.)\1{3,}, r\1\1, text) return text.strip() def analyze_sentiment(df): 对评论做情感分析返回带情感得分和标签的DataFrame df[clean_content] df[content].apply(clean_text) # 过滤空评论和默认好评 df df[df[clean_content].str.len() 3].copy() scores [] labels [] for text in df[clean_content]: try: s SnowNLP(text) score s.sentiments except Exception: score 0.5 # 分析失败给中性分 scores.append(score) # 阈值调整0.6以上正面0.4以下负面中间中性 if score 0.6: labels.append(正面) elif score 0.4: labels.append(负面) else: labels.append(中性) df[sentiment_score] scores df[sentiment_label] labels return df # 使用示例 df pd.read_csv(jd_comments_100012043978.csv) df analyze_sentiment(df) print(df[sentiment_label].value_counts()) df.to_csv(jd_comments_with_sentiment.csv, indexFalse, encodingutf-8-sig)这段代码做了三件事清洗文本、逐条计算情感得分、按阈值打标签。clean_text函数里的正则[^\u4e00-\u9fa5a-zA-Z0-9。、]是只保留中文、英文、数字和常用标点表情符号和特殊字符全部去掉。阈值设 0.6 和 0.4 是我在几千条京东评论上试出来的经验值比默认的 0.5 分界更合理——因为 SnowNLP 对正面表达偏保守很多明显好评得分只有 0.55 左右。3.3 用自定义词典修正领域词SnowNLP 的默认词典对京东品类词覆盖不够比如「续航」「散热」「屏幕素质」这些词的情感倾向它判断不准。解决办法是加载自定义词典把领域词和对应的情感倾向加进去。from snownlp import sentiment # 自定义正面词和负面词 pos_words [续航强, 散热好, 屏幕清晰, 手感舒适, 物流快, 包装严实, 性价比高] neg_words [续航差, 散热烂, 屏幕有坏点, 手感差, 物流慢, 包装破损, 性价比低] # 将自定义词加入SnowNLP词典需在分析前执行 for word in pos_words: sentiment.add_word(word, 1.0) # 1.0表示正面 for word in neg_words: sentiment.add_word(word, 0.0) # 0.0表示负面 # 重新训练模型首次使用需要 # sentiment.train(sentiment.marshal) # sentiment.save(sentiment.marshal)这里有个坑add_word只是把词加进词典但 SnowNLP 的模型不会自动更新需要重新训练并保存。如果不想重新训练更简单的做法是在打分后做规则修正——检测到正面词就加分检测到负面词就减分。我一般用规则修正因为重新训练需要标注语料成本太高。提示自定义词典的正面词和负面词要成对出现避免出现「续航强」是正面但「续航弱」没定义的情况。另外京东评论里「还行」「一般」「凑合」这类词的情感倾向很模糊建议归到中性不要强行打正面或负面。4. 可视化让情感分析结果能直接汇报4.1 用 pyecharts 做交互式图表情感分析结果如果只输出一个 CSV运营团队根本不会看。可视化才是让数据产生价值的关键一步。我一般用 pyecharts 做三张图情感分布饼图、评分与情感得分对比柱状图、评论时间趋势折线图。from pyecharts import options as opts from pyecharts.charts import Pie, Bar, Line, Grid import pandas as pd df pd.read_csv(jd_comments_with_sentiment.csv) # 图1情感分布饼图 label_counts df[sentiment_label].value_counts() pie ( Pie() .add(, [list(z) for z in zip(label_counts.index, label_counts.values)]) .set_global_opts( title_optsopts.TitleOpts(title京东商品评论情感分布), legend_optsopts.LegendOpts(orientvertical, pos_leftleft) ) .set_series_opts(label_optsopts.LabelOpts(formatter{b}: {c} ({d}%))) ) pie.render(sentiment_pie.html) # 图2评分与情感得分对比 score_sentiment df.groupby(score)[sentiment_score].mean().reset_index() bar ( Bar() .add_xaxis([str(int(s)) 星 for s in score_sentiment[score]]) .add_yaxis(平均情感得分, [round(v, 3) for v in score_sentiment[sentiment_score]]) .set_global_opts( title_optsopts.TitleOpts(title评分与情感得分对比), yaxis_optsopts.AxisOpts(min_0, max_1) ) ) bar.render(score_vs_sentiment.html) # 图3评论时间趋势 df[date] pd.to_datetime(df[creation_time]).dt.date daily df.groupby(date).size().reset_index(namecount) line ( Line() .add_xaxis([str(d) for d in daily[date]]) .add_yaxis(每日评论数, daily[count].tolist()) .set_global_opts( title_optsopts.TitleOpts(title评论时间趋势), xaxis_optsopts.AxisOpts(name日期), yaxis_optsopts.AxisOpts(name评论数) ) ) line.render(comment_trend.html)这三张图分别回答三个问题整体情感倾向是什么饼图、评分和情感分析结果是否一致柱状图、评论集中在什么时间段折线图。pyecharts 生成的是 HTML 文件可以直接用浏览器打开也可以嵌入到 Web 页面里。如果要做可视化大屏把这三个 HTML 用 iframe 嵌到一个页面里就行。4.2 用 matplotlib 做静态图用于报告如果是要放进 PPT 或 Word 报告matplotlib 更合适因为可以导出高清 PNG。import matplotlib.pyplot as plt import pandas as pd # 设置中文字体 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False df pd.read_csv(jd_comments_with_sentiment.csv) fig, axes plt.subplots(1, 2, figsize(14, 5)) # 左图情感分布 label_counts df[sentiment_label].value_counts() axes[0].pie(label_counts.values, labelslabel_counts.index, autopct%1.1f%%, startangle90, colors[#66b3ff, #ff9999, #99ff99]) axes[0].set_title(情感分布) # 右图情感得分直方图 axes[1].hist(df[sentiment_score], bins30, color#66b3ff, edgecolorwhite) axes[1].axvline(x0.4, colorred, linestyle--, label负面阈值) axes[1].axvline(x0.6, colorgreen, linestyle--, label正面阈值) axes[1].set_xlabel(情感得分) axes[1].set_ylabel(评论数) axes[1].set_title(情感得分分布) axes[1].legend() plt.tight_layout() plt.savefig(sentiment_report.png, dpi150) plt.show()matplotlib 的坑主要在中文显示上font.sans-serif设成SimHei是 Windows 下的做法Mac 上要改成Arial Unicode MSLinux 上需要先安装中文字体。另外axes.unicode_minus设成 False 是为了让负号正常显示不设的话负号会变成方块。5. 避坑与排查那些让我重跑过的坑5.1 爬虫返回空数据但状态码是 200现象请求返回 200但 JSON 里comments是空数组。原因通常是触发了京东的隐性频率限制或者page参数超出了实际页数。解决方法是先手动在浏览器里确认最大页码然后把请求间隔调到 3 秒以上如果还是空就换 IP 或等半小时再试。5.2 情感分析结果和评分完全对不上现象5 星好评的情感得分只有 0.31 星差评得分却有 0.7。原因是 SnowNLP 对反讽和混合情感识别不准比如「东西真好用了一天就坏了」会被判成正面。解决办法是在清洗阶段过滤掉包含「但是」「不过」「然而」的评论单独人工复核或者用规则修正——检测到转折词就把情感得分往中性拉。5.3 可视化图表中文显示成方块现象pyecharts 或 matplotlib 生成的图表里中文全是方块。原因是默认字体不支持中文。pyecharts 需要在set_global_opts里加title_optsopts.TitleOpts(title..., title_textstyle_optsopts.TextStyleOpts(font_familySimHei))matplotlib 需要设plt.rcParams[font.sans-serif]。Linux 服务器上如果没有中文字体需要先apt install fonts-wqy-zenhei或手动拷贝字体文件。5.4 CSV 用 Excel 打开乱码现象导出的 CSV 用 Excel 打开中文全是乱码。原因是 Excel 默认用 GBK 编码打开 CSV而 pandas 默认导出 UTF-8。解决办法是在to_csv里加encodingutf-8-sig这个编码带 BOM 头Excel 能正确识别。5.5 评论去重后数据量骤减现象爬了 5000 条评论去重后只剩 800 条。原因是京东评论里大量存在默认好评和重复内容尤其是「此用户未填写评价内容」这类。解决办法是在清洗阶段过滤掉长度小于 5 的评论和包含「此用户未填写」的评论同时按content字段去重保留useful_count最高的那条。6. 进阶技巧把情感分析准确率再拉高 10 个百分点如果基础版跑通了想让结果更准可以试两个方向。第一个是换模型——SnowNLP 毕竟是基于朴素贝叶斯的对复杂句式吃力。可以换成bert-base-chinese做微调用京东评论数据训练一个二分类模型。我试过用 2000 条标注数据微调 BERT准确率从 78% 拉到 89%但推理速度慢了很多5000 条评论要跑 10 分钟左右。如果只是做分析报告这个时间可以接受如果要实时分析还是用 SnowNLP 加规则修正更划算。第二个方向是做细粒度情感分析。现在只分了正面、负面、中性三类但实际运营更想知道「物流」「质量」「服务」分别是什么情感。做法是按关键词把评论分成几个维度每个维度单独跑情感分析。比如检测到评论里包含「物流」「快递」「发货」就归到物流维度包含「质量」「做工」「材质」就归到质量维度。这样输出的结果能直接告诉运营团队哪个环节出了问题。def dimension_analysis(df): 按维度拆分评论并分别做情感分析 dimensions { 物流: [物流, 快递, 发货, 配送, 收到], 质量: [质量, 做工, 材质, 手感, 品质], 服务: [客服, 服务, 售后, 态度, 回复], 价格: [价格, 性价比, 划算, 贵, 便宜] } results {} for dim, keywords in dimensions.items(): mask df[clean_content].apply( lambda x: any(kw in x for kw in keywords)) subset df[mask] if len(subset) 0: results[dim] { count: len(subset), avg_score: round(subset[sentiment_score].mean(), 3), positive_rate: round( (subset[sentiment_label] 正面).mean(), 3) } return pd.DataFrame(results).T # 使用 dim_df dimension_analysis(df) print(dim_df) dim_df.to_csv(dimension_analysis.csv, encodingutf-8-sig)这段代码按关键词把评论分到四个维度每个维度输出评论数、平均情感得分和正面率。运营团队拿到这个表一眼就能看出是物流拖了后腿还是质量有问题。我一般会把这个表和前面的可视化图表放在一起做成一个完整的分析报告。最后说个血泪经验别在爬虫上花太多时间。京东评论接口的翻页逻辑就那些能跑通就行真正决定分析价值的是清洗和维度拆分。我见过太多人卡在爬虫的反爬对抗上结果数据拿了一堆分析却做得很粗糙。先把链路跑通再回头优化爬虫这个顺序别搞反。希望帮到你。本文还有配套的精品资源点击获取
返回列表