尧图精选

Python爬虫与情感分析:构建淘宝京东商品评论分析系统

🕒 发布时间:2026/10/1 16:15:21 📁 来源:尧图网络
简介基于Python的淘宝、京东商品评论爬虫与情感分析评价系统是一份面向毕业设计、期末大作业和课程设计的高分优秀源码及文档包适合正在开展电商评论挖掘、舆情分析相关课题的本科生或研究生。系统完整覆盖商品评论数据采集、中文文本预处理、LSTM情感模型训练与结果可视化等关键环节所有源码均已本地编译运行通过评审分达98分项目难度适中。压缩包内共103个文件主要文件类型包括py爬虫与分析源码、csv评论数据集、pt训练模型、jpg和png可视化图表以及xml配置、txt说明和chromedriver驱动等数据文件涵盖淘宝、京东多个商品评论样本可直接用于复现实验。当前已有206人学习下载内容经助教审定能帮助使用者快速理解电商评论情感分析的全流程也便于按模块提取代码、改写算法或接入自己的数据。1. 商品评价系统到底是什么把爬虫和情感分析拧在一起的高分毕设做毕业设计最怕的不是代码难写而是“数据从哪来”。翻遍公开数据集不是太老就是字段对不上最后只能自己造数据答辩时一问就露馅。这个基于Python的淘宝、京东爬虫及商品评论情感分析系统解决的正是“真实数据获取”和“评论风向判断”两件事先爬取商品信息和评论再用情感分析把“好评、差评、中评”量化成可用指标最后落到一个可视化系统里。它非常适合电商数据分析方向的毕设也适合想入门爬虫和自然语言处理的人拿来做练习。我从一个能跑通的最小版本讲起把选型理由、实现代码、踩坑经历一次说清。2. 系统架构与技术选型从商品搜索到情感标签的数据链路2.1 五大核心模块与数据流这类系统无论怎么改数据流都是固定的采集端负责从淘宝、京东拿到商品信息和用户评论清洗端处理掉重复和噪音存储端把结构化数据落库分析端做情感打分展示端把结果渲染成图表供人查看。模块划分上我习惯拆成五个部分。采集模块分成两个独立爬虫一个管淘宝一个管京东因为两个平台的前端结构和反爬策略完全不同。清洗模块负责去重、去HTML标签、过滤表情和短评。存储模块选用MongoDB存原始评论JSON用MySQL或SQLite存统计结果混合存储的好处是原始数据保留完整统计字段查询快。分析模块以情感打分为核心附带词频统计和差评关键词提取。展示模块用Flask做后端接口前端用ECharts渲染好评率趋势、差评词云和商品价格对比。数据流的顺序是爬虫把数据写入MongoDB清洗脚本把干净文本抽出来分析程序逐条打分结果写回MySQL最后Flask查询并渲染到页面。这个流程里最容易被忽视的是“清洗”这一步。很多人把清洗当成可有可无的步骤结果情感分析时被“买回来看看”“物流很快”“666666”这类噪音反复干扰。我建议在采集后统一做一次清洗宁可多花十分钟也不要让噪音进模型。2.2 技术选型requests、snownlp、pymongo与sqlalchemy的取舍选型的核心原则是“毕业设计不要炫技要稳”。爬虫框架用Scrapy功能全但学习曲线陡反爬配置复杂requests配合Session、重试、随机延时在小规模采集场景下完全够用关键是出了问题好排查。存储层用pymongo直接驱动MongoDB比接一层ORM更直观因为评论文本是半结构化数据MongoDB的文档模型天然匹配。统计结果表我一般用SQLAlchemy建一个简单的ORM映射方便后期换数据库。情感分析这一层模型选择需要讲清楚边界。常见的方案有基于情感词典的规则法、基于机器学习的方法和基于深度学习的方法。深度学习方法效果最好但需要大量标注语料这在毕设场景里不现实。我推荐SnowNLP作为基线方案它是基于朴素贝叶斯训练的中文情感分析库开箱即用打分范围是0到1大于0.5偏正向。不过它训练语料偏向社交评论对电商场景有偏差所以后面要加自定义词典和否定词规则来修正。如果你手头有时间和机器也可以用BERT做微调但那属于加分项第一版不要上。数据库选型还有一个小技巧评论数据量超过十万条以后MongoDB的聚合查询会变慢。解决办法是提前在采集时就把评分、评论时间、商品ID这些字段单独抽出建立复合索引同时把每小时的好评率统计结果单独存一张表可视化时不再扫原始评论。这个设计从第一天就做后期能省大量时间。2.3 淘宝、京东的反爬边界cookie、滑块与限速淘宝和京东的反爬都在持续升级写爬虫前要先明白边界在哪里。淘宝的详情页依赖登录态和动态参数直接requests抓取很容易被识别。京东的商品信息和评论接口相对开放但返回格式经常调整。常见的反爬措施包括UA检测、频率限制、滑块验证、签名参数、IP封禁。毕业设计场景里我不建议去硬碰滑块验证更不建议去买各种现成的破解服务。正确做法是控制爬取频率并模拟真实浏览器行为。每条评论之间至少间隔1到3秒随机化延时比固定延时更有效。请求头里带上完整的User-Agent、Accept-Language和Referer模拟浏览器访问。如果发现返回异常或验证码出现立刻停止不要硬扛。另一个常用做法是维护一个cookie池从浏览器手动复制登录后的cookie加入请求头。这样能把封号风险降到一个可控范围当做完项目向评委演示时也能说明自己理解反爬机制而不是无脑请求。3. 动手实现商品信息与评论采集可复现的爬虫代码3.1 京东商品信息先跑通JSON接口再谈规则京东的商品搜索和评论数据分属不同接口好消息是两者都容易拿到JSON。商品评论的常规做法是请求评论摘要接口带上产品ID、评分类型和排序方式返回的JSON里有评论总数、好评率、以及每条评论的正文和时间。下面是一个京东商品信息采集的最小示例用requests直接请求搜索接口并解析商品基础信息。import requests import json import time import random HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.jd.com/, Accept-Language: zh-CN,zh;q0.9, } def fetch_jd_search(keyword, pages1): 通过京东搜索接口获取商品基础信息 :param keyword: 搜索关键词 :param pages: 需要采集的页数 :return: 商品列表 results [] for page in range(pages): params { keyword: keyword, page: page 1, pagesize: 30 } url https://search.jd.com/s_new.php try: resp requests.get(url, paramsparams, headersHEADERS, timeout10) # 搜索接口返回的是HTML片段商品数据包在li标签的data-sku属性里 # 这里用正则提取sku列表再拼出商品详情URL sku_ids re.findall(rdata-sku\(\d)\, resp.text) for sku in sku_ids: results.append({ platform: jd, sku_id: sku, product_url: fhttps://item.jd.com/{sku}.html }) except requests.RequestException as e: print(f[京东搜索异常] 第{page 1}页失败: {e}) # 随机延时降低被识别风险 time.sleep(random.uniform(1.5, 3.5)) return results if __name__ __main__: # 先跑通一个关键词再扩展到多个关键词和翻页 goods fetch_jd_search(无线耳机, pages2) print(f本次采集到 {len(goods)} 个商品) for item in goods[:5]: print(item)这段代码的逻辑是先请求搜索页从HTML片段里用正则抽出商品ID再拼出详情页URL。参数pagesize和page控制采集范围timeout设成10秒是为了避免网络卡住。HEADERS里的User-Agent不能省略缺了它京东会直接返回异常。运行时如果发现返回的HTML是空的先检查是不是触发了验证码办法是手动打开浏览器搜索同样关键词如果出现滑块说明当前IP或cookie已经被标记。3.2 淘宝商品信息从页面快照里取JSON不要硬解析HTML淘宝的商品详情页比京东麻烦但有一个比较稳定的做法详情页源码里嵌了一段包含商品信息的JSON数据通常以“window.INITIAL_DATA”或类似命名的变量存在。找到那段变量名后用正则截取JSON字符串再解析出店铺名、商品标题、价格区间和销量。import re import json import requests import time def parse_taobao_item(item_url, cookiesNone): 从淘宝商品详情页提取JSON数据 :param item_url: 商品详情页URL :param cookies: 登录后的cookie字符串防止被强制跳转 :return: 商品信息字典 headers { User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: https://www.taobao.com/ } if cookies: headers[Cookie] cookies resp requests.get(item_url, headersheaders, timeout10) # 匹配页面内嵌的商品数据 match re.search(rwindow\.__INITIAL_DATA__\s*\s*({.*?});, resp.text, re.S) if not match: return None try: data json.loads(match.group(1)) except json.JSONDecodeError as e: print(f[解析失败] {item_url} 内嵌JSON异常: {e}) return None # 字段名在淘宝改版后会有变化这里用get做容错 item data.get(item, {}) return { platform: taobao, item_id: item.get(itemId), title: item.get(title), price: item.get(price, {}).get(priceText), sales: item.get(sellCount, 未知), shop_name: item.get(shopName), image_url: item.get(picUrl) } if __name__ __main__: # 演示用法实际运行时需要手动替换成真实商品链接 url https://item.taobao.com/item.htm?id1234567890 info parse_taobao_item(url) print(info)这个实现的关键点在于正则里的非贪婪匹配因为内嵌JSON很长如果写成(.*)会贪婪到页面末尾导致解析失败。淘宝经常调整字段名所以代码里用get配合默认值做容错。另外强烈建议在采集淘宝前先用浏览器登录一次并复制cookie无登录状态访问详情页很多时候会返回滑块验证页。如果你发现自己写了半天代码却被反爬拦在门外先检查cookie这是最常见的“翻车”原因。3.3 清洗与入库去重、去表情、批量写入MongoDB评论数据到手后不要急着做情感分析先清洗。清洗规则我总结为四条。第一条去重同一条评论用户可能刷了多遍按“商品ID评论内容”组合去重。第二条去HTML和无意义字符比如“””“\u200b”这些残留。第三条过滤过短评论比如“好”“不错”“666”这类长度小于两个字的信息量太低。第四条针对特殊符号淘宝评论里常出现“【赠品】”之类的前缀也需要剔除。import re import hashlib from pymongo import MongoClient client MongoClient(mongodb://localhost:27017/) db client[goods_review] raw_coll db[raw_comment] clean_coll db[clean_comment] def clean_text(text): 输入原始评论文本输出清洗后的文本和MD5指纹 if not text: return , # 去掉HTML标签与实体 text re.sub(r[^], , text) text re.sub(r[a-zA-Z];, , text) # 去掉emoji与特殊符号保留中文、英文、数字和基础标点 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、,.!? ], , text) # 去掉过短评论 if len(text) 2: return , # 生成指纹用于去重 md5 hashlib.md5(text.encode(utf-8)).hexdigest() return text, md5 def process_comment(comment): 清洗单条评论并写入MongoDB comment结构需包含comment_text、sku_id、user_name等字段 content, fp clean_text(comment.get(comment_text, )) if not content: return doc { platform: comment.get(platform), sku_id: comment.get(sku_id), user_name: comment.get(user_name), comment_text: content, comment_date: comment.get(date), md5: fp, score: None # 情感分析阶段回填 } clean_coll.update_one({md5: fp}, {$setOnInsert: doc}, upsertTrue) if __name__ __main__: # 从raw_comment取一批未处理的评论 for raw in raw_coll.find({processed: {$ne: True}}): process_comment(raw) raw_coll.update_one({_id: raw[_id]}, {$set: {processed: True}})清洗后的评论通过MD5指纹做唯一约束用upsert避免重复写入。情感分析结果用score字段回填这样既保留了原始数据又给分析结果留了位置。入库时注意一个问题不要每处理一条就提交一次数据库连接批量写入比逐条写入快很多。把上面这个循环改成先攒够200条再调用insert_many速度至少提升五倍。4. 商品评论情感分析从分词、打分到可视化的一整条链路4.1 情感分析选型Snownlp、自定义词典和训练边界情感分析模块是整个系统的灵魂。常见做法是用SnowNLP做基线因为它简单、对中文支持好、不需要自己训练。下面这段代码展示了如何对清洗后的评论批量打分并把结果写回集合。from snownlp import SnowNLP def sentiment_score(text): 返回评论的情感倾向评分0到1之间越接近1越正向 if not text: return 0.5 s SnowNLP(text) return float(s.sentiments) # sentiments属性返回情感概率 # 批量更新score字段 for doc in clean_coll.find({score: None}): text doc.get(comment_text, ) score sentiment_score(text) clean_coll.update_one( {_id: doc[_id]}, {$set: {score: score}} )SnowNLP的sentiments属性基于朴素贝叶斯计算输出的是“这条评论属于正向”的概率。但它的训练语料偏社交网络在电商场景里会出现“质量太差”被判成中性、“一般般”被判成正向的情况。想改进有两个办法一是收集几百条自己商品的正负评论重新训练SnowNLP的贝叶斯模型二是在打分后面追加规则修正比如出现“真差”“太烂”“售后不行”这样的关键词直接把分数压到0.2以下。4.2 电商场景增强自定义词典、否定词和程度副词规则修正要处理三件事领域词、否定词、程度副词。领域词典包含“性价比”“掉漆”“续航”“漏电”这类电商高频词这些词在通用语料里是中性的但在商品评价里带有明显倾向。否定词的逻辑是“不错”和“真不错”都偏正向但“不太行”“一点也不值”要反转。程度副词可以加权重比如“很满意”比分“满意”更接近1。NEGATIVE_WORDS [差, 烂, 不值, 后悔, 假货, 垃圾, 失望, 太差] NEGATION_WORDS [不, 没, 别, 无, 莫, 非] INTENSIFIER_WORDS {很: 1.2, 非常: 1.5, 特别: 1.5, 有点: 0.8, 稍微: 0.9} def adjusted_sentiment(text, base_score): 在SnowNLP分值基础上做规则修正 score base_score # 命中负面词直接压低分数 for w in NEGATIVE_WORDS: if w in text: score min(score, 0.3) break # 处理否定词反转 for w in NEGATION_WORDS: if w 错 in text or w 满意 in text: score 1.0 - score break # 处理程度副词加权 for w, weight in INTENSIFIER_WORDS.items(): if w in text: score min(1.0, score * weight) break return round(score, 4) # 示例结合基础评分与规则修正 demo_text 这个耳机音质非常差不推荐 base sentiment_score(demo_text) final adjusted_sentiment(demo_text, base) print(f基础分: {base}, 修正后: {final})注意修正顺序很重要先处理负面词再做否定词反转最后加权。如果先做否定反转再把“不推荐”里的“不”当成纯否定标记会把“音质非常差不推荐”反转成正向结果完全颠倒。这个细节是我实际调试时踩过的坑很多教程里都不会提。最终分数不要超过1.0所以加权那一步要做min限制。4.3 生成统计结果并落地到可视化界面分析完成后下一步是把结果汇总成指标。常见指标包括平均好评率、每日情感得分趋势、差评Top词、不同价格区间的情感差异。统计逻辑不复杂关键是用SQLAlchemy把这些结果写进汇总表供可视化查询。from sqlalchemy import create_engine, Column, String, Float, Date from sqlalchemy.orm import declarative_base, sessionmaker Base declarative_base() class DailyStat(Base): __tablename__ daily_sentiment_stat id Column(String(32), primary_keyTrue) stat_date Column(Date, indexTrue) sku_id Column(String(32), indexTrue) good_rate Column(Float) # 好评率 avg_score Column(Float) # 平均情感分 sample_count Column(Float) # 样本数量 engine create_engine(mysqlpymysql://root:passwordlocalhost:3306/graduate_design) Base.metadata.create_all(engine) Session sessionmaker(bindengine) session Session() # 统计某商品每日的平均情感分写入汇总表 pipeline [ {$match: {sku_id: 1000123, score: {$ne: None}}}, {$group: {_id: {$dateToString: {format: %Y-%m-%d, date: $comment_date}}, avg_score: {$avg: $score}}} ] result clean_coll.aggregate(pipeline) for r in result: stat DailyStat(idf{r[_id]}_1000123, stat_datedatetime.strptime(r[_id], %Y-%m-%d).date(), sku_id1000123, avg_scorer[avg_score], good_rater[avg_score] * 100, sample_count1) session.merge(stat) session.commit()这里用MongoDB的聚合管道做分组统计再把结果写入MySQL因为前端可视化查询MySQL比查MongoDB的文档要稳定。汇总表设计成按天粒度字段包括好评率和平均分。注意SQLAlchemy里的merge方法比update_one更适合这种幂等写入场景重复执行不会产生重复记录。5. 商品评价系统的五个经典踩坑现场与排查清单5.1 爬虫被限制登录多线程一开就变黑色现象采集程序运行约五分钟后所有请求开始返回验证码页面京东搜索返回的数据为空淘宝详情页跳转到滑块验证。原因单一IP在短时间内高频请求触发了服务器的限流策略。我在初版把延时设成0.5秒又开了十个线程结果十分钟后整个IP被临时限制。解决把延时调大到1.5到3秒之间线程数限制在3个以内。另一个有效办法是准备多个浏览器cookie每采集200条切换一次。如果项目时间充裕可以加入内存代理池从免费代理网站抓一批代理但免费代理可靠性很差只适合演示场景。总体原则是“跑得慢但别停”。5.2 京东评论JSON接口悄悄换了返回格式现象昨天还能正常解析的评论列表今天变成了一个登录页面或一堆HTML源码。原因平台更新了接口的鉴权策略评论数据从无参数公开接口变成了需要时间戳签名。解决先手动用浏览器打开评论接口地址观察返回内容。如果确认签名参数双击打开开发者工具抓包看请求头多出了哪些参数把对应参数复制到代码里。这个方法不保证长期有效但足以支撑毕设演示。更稳妥的做法是直接把评论采集做成“小众低频”模式只在需要展示时跑一次而不是全天候挂机采集。5.3 情感分析把“质量太差”判成中性现象人工抽检时发现明显是差评的评论模型却给出了超过0.6的分数。原因SnowNLP的底层语料来自社交评论对电商领域的贬义词覆盖不足。“质量太差”这个词组合在社交语料里并不常见模型无法识别出负面倾向。解决引入商品评价领域词典把“质量太差”“掉漆”“续航不行”整理成负面词表在打分后做规则修正。同时准备300条手工标注的真实评论用于微调模型。微调不是必选项但做了之后准确率明显提升。5.4 入库太慢连接池耗尽现象爬虫采集速度快于入库速度MongoDB连接数飙升日志里不断报“Too many connections”。原因代码里针对每条评论都新建了一个MongoClient连接没有复用。解决把MongoClient对象全局只创建一次用pymongo的批量写接口处理攒够一定数量后统一insert_many。SQLAlchemy这边配置连接池设置pool_size和max_overflow参数。我一般把pool_size设成10max_overflow设为20足以应对毕设规模的数据量。5.5 爬虫进程崩溃后从头再来现象程序运行到一半因为网络异常退出重新启动后又要爬一遍全部数据。原因没有保存断点状态。requests抛异常后异常处理只打印日志已采集数据没有标记数据库里也没有去重机制。解决在每条原始评论里加采集状态字段处理完就标记为true。重新爬时先查已存在的数据MongoDB的upsert配合MD5指纹就能实现续爬。另外给requests包加上超时重试装饰器超过三次再放弃放弃的任务单独记录日志。这个优化花了半天时间但之后再也没有因为断点问题浪费过时间。6. 进阶验证用历史数据校准情感模型把系统变成舆情监控工具6.1 用一小批测试集快速校准模型模型好不好不能用感觉判断要用回测来说话。从清洗好的评论里随机抽出200条人工标注正负标签然后跑一遍情感分析程序统计准确率。def evaluate_model(test_data): test_data: list of (text, true_label) true_label为1表示正向0表示负向 correct 0 for text, label in test_data: base sentiment_score(text) final adjusted_sentiment(text, base) pred 1 if final 0.5 else 0 if pred label: correct 1 return correct / len(test_data) # 示例用法 sample [ (音质不错低音效果好, 1), (做工粗糙缝隙很大, 0), (物流很快包装完整, 1), (客服态度差不解决问题, 0) ] print(f准确率: {evaluate_model(sample)})这个流程建议在开发中期就做一次而不是等项目写完再补。如果你发现准确率低于70%优先扩充领域词典而不是换算法模型。词典规则的收益在样本量小于几百条时比换模型大得多。6.2 走向多模态分析的思路后面如果想让系统更完整可以考虑多模态方向。多模态情感分析的思路是把评论文本之外的表情、图片、视频信号也纳入分析比如美团和快手这类平台的数据就适合做图文融合。但这个题目范围很大毕设阶段不用强求懂原理比写代码重要答辩时能说清楚“为什么要引入多模态”就足够出彩。6.3 最后我养成的三个习惯这个系统我从零搭完用了大概两周真正花时间的不是写代码而是调参数。现在每跑一批数据我都要先做三件事检查采集日志里有没有异常请求、随机抽十条评论看情感打分是否合理、确认数据库里没有重复记录。这套流程是我最大的一条血泪经验数据质量不过关再漂亮的分析也没人信。希望这篇笔记能帮你的毕设少走几步弯路。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →