ARTICLE DETAIL

资讯详情

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

低成本搭建电商商品口碑监控系统|从实时数据采集到情感分析完整实战(可运行 Python 代码)

低成本搭建电商商品口碑监控系统|从实时数据采集到情感分析完整实战(可运行 Python 代码) 1. 电商口碑监控到底难在哪从人工翻页到 Python 自动化闭环做电商运营或者竞品分析绕不开的一件事就是看评论。一条商品链接下面几百上千条评价好评里藏着卖点差评里藏着产品缺陷和售后隐患。问题是靠人工翻页复制单品上千条数据至少耗掉半天而且你没法实时知道今天有没有新增差评等发现的时候可能已经影响转化了。我试过用纯手工的方式统计过一轮评论翻到第三页就放弃了——不是累是数据太零散根本没法做批量统计。后来换成 Python 做自动化才把「采集—落库—情感打分—出图」这条链路跑通。这套东西的核心检索词就是 Python 情感分析 数据采集 SQLite 可视化适合中小电商团队、数据分析实习生、个人卖家一台普通笔记本或者低配云服务器就能跑。整套系统拆成四块第一块是数据采集用 requests 按分页把评论全字段拉下来包括评论文本、星级、购买规格、评价时间、追评内容第二块是落库去重用 SQLite 建一张评论表以评论唯一 ID 做主键INSERT OR IGNORE保证增量更新不重复第三块是情感分析用 SnowNLP 给每条评论打一个 0 到 1 的情感分大于 0.5 归好评0.3 到 0.5 归中评小于 0.3 归差评第四块是可视化用 Matplotlib 出情感分布饼图和差评高频词 TOP15。为什么选 SQLite 而不是直接存 CSV因为你要做的是「监控」不是「一次性导出」。监控意味着每天甚至每半小时都有新数据进来CSV 每次追加都要重写整个文件而 SQLite 有主键约束天然帮你做去重查询也方便。后面你要按月对比口碑变化一条SELECT就能按时间聚合比翻 CSV 高效得多。情感分析这块要提前说清楚SnowNLP 是轻量级中文情感模型对「质量不错但物流太慢」这种混合语句会打分偏差它只能作为参考信号不能当唯一判据。实操中我会把 SnowNLP 分数和星级做交叉验证——比如五星但情感分低于 0.3 的评论往往是「好评返现」或者反讽这类要单独拎出来看。下面从环境准备开始一步步把可运行的代码和配置给出来。你不需要有很深的 Python 基础能看懂函数和循环就能跟下来。2. TaoToken 前置准备拿到 Base URL、API Key 和 Model ID在写采集和分析代码之前先把模型调用这条链路准备好。情感分析如果只用 SnowNLP遇到反讽和混合语义会翻车所以我会在关键环节接一个大模型做二次判断比如把 SnowNLP 打分在 0.3 到 0.5 之间的「模糊评论」丢给模型做语义复核。这一步需要你有一个可用的 API 入口。TaoToken 在这里的角色是提供统一的模型调用入口。你需要准备三样东西Base URL、API Key、Model ID。这三件套在后面的配置片段里会反复出现先记牢。Base URL 统一用https://taotoken.net/api注意这个地址后面不加任何查询参数。API Key 去控制台创建路径是 console 页面下的 api-keys 管理。Model ID 根据你用的模型填比如做中文语义判断可以选通用对话模型具体型号在模型对话页面能看到当前可用的列表。如果你用的是 Claude Code 这类编码工具做辅助开发配置方式略有不同。Claude Code 走的是 Anthropic 兼容协议需要在 settings 里指定 Base URL 和 Key。而 Codex 用的是auth.jsonCline 走 MCP 配置。这三种工具的配置我会在下一节给出完整片段你按自己用的工具对号入座。有一点要提醒API Key 不要硬编码在脚本里提交到 Git。实操中我会把它放到环境变量或者单独的config.py里.gitignore把配置文件排除掉。下面代码里为了演示方便直接写在常量位置你落地时记得改。准备好这三样之后先别急着写采集代码用一条最简单的请求验证 Key 是否可用。验证通过再往下走能省掉后面排查「到底是采集挂了还是 Key 挂了」的时间。3. 可复制配置settings、auth.json 与采集脚本完整片段这一节给的是可以直接复制粘贴的配置和代码。先给工具侧的配置再给采集和分析脚本。如果你用 Claude Code配置文件放在项目根目录的.claude/settings.json内容如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: 你的API_KEY, ANTHROPIC_MODEL: 你的Model_ID } }如果你用 Codex配置写在~/.codex/auth.json{ base_url: https://taotoken.net/api, api_key: 你的API_KEY, model: 你的Model_ID }如果你用 Cline 的 MCP 方式接入配置片段长这样{ mcpServers: { taotoken: { command: npx, args: [-y, your-mcp-package], env: { BASE_URL: https://taotoken.net/api, API_KEY: 你的API_KEY, MODEL_ID: 你的Model_ID } } } }三件套的核心就是 Base URL、Key、Model ID不管哪个工具这三个值填对就能通。接下来是采集脚本。先建项目、装依赖pip install requests pandas jieba snownlp matplotlibSQLite 是 Python 标准库自带不用单独装。建表 SQL 如下评论唯一 ID 做主键情感分字段留空等分析时回填CREATE TABLE IF NOT EXISTS comment_data ( comment_id TEXT PRIMARY KEY, nick TEXT, star INTEGER, content TEXT, sku TEXT, rate_date TEXT, has_pic INTEGER, add_feedback TEXT, emotion_score REAL );采集类的核心逻辑我把它整理成一个可直接运行的版本import requests import json import time import random import sqlite3 import pandas as pd from snownlp import SnowNLP ACCESS_KEY 你的API_KEY GATEWAY_URL https://taotoken.net/api class GoodsCommentCollector: def __init__(self, item_id): self.item_id item_id self.all_comment_list [] self.db_conn sqlite3.connect(goods_comment.db) self.init_db() def init_db(self): create_sql CREATE TABLE IF NOT EXISTS comment_data ( comment_id TEXT PRIMARY KEY, nick TEXT, star INTEGER, content TEXT, sku TEXT, rate_date TEXT, has_pic INTEGER, add_feedback TEXT, emotion_score REAL ) self.db_conn.execute(create_sql) self.db_conn.commit() def fetch_single_page(self, page_num1, page_size20): params { key: ACCESS_KEY, item_id: self.item_id, page: page_num, page_size: page_size, result_type: json } try: resp requests.get(GATEWAY_URL, paramsparams, timeout15) return json.loads(resp.text) except Exception as e: print(f第{page_num}页采集异常{str(e)}) return None def parse_raw_data(self, raw_json): if not raw_json or items not in raw_json: return False comment_items raw_json[items].get(item, []) if len(comment_items) 0: return False for item in comment_items: content item.get(rate_content, ).strip() if content in [此用户没有填写评价。, ]: continue comment_info { comment_id: item.get(rate_id, ), nick: item.get(display_user_nick, 匿名用户), star: int(item.get(user_star, 5)), content: content, sku: item.get(auction_sku, 无规格), rate_date: item.get(rate_date, ), has_pic: 1 if item.get(pics, []) else 0, add_feedback: item.get(add_feedback, 无追评) } self.all_comment_list.append(comment_info) return True def batch_crawl_all(self, max_page50): for page in range(1, max_page 1): print(f正在采集第{page}页...) raw_data self.fetch_single_page(page_numpage) if not self.parse_raw_data(raw_data): print(无更多评价采集完成) break time.sleep(random.uniform(1.2, 3.0)) print(f本次采集有效评价 {len(self.all_comment_list)} 条) def save_to_local_db(self): insert_sql INSERT OR IGNORE INTO comment_data (comment_id, nick, star, content, sku, rate_date, has_pic, add_feedback, emotion_score) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) for c in self.all_comment_list: score SnowNLP(c[content]).sentiments self.db_conn.execute(insert_sql, ( c[comment_id], c[nick], c[star], c[content], c[sku], c[rate_date], c[has_pic], c[add_feedback], score )) self.db_conn.commit() print(新评价已入库) def export_to_csv(self): df pd.DataFrame(self.all_comment_list) df.to_csv(f商品{self.item_id}_评价数据.csv, indexFalse, encodingutf-8-sig) print(CSV 导出完成)这段代码里有两个细节值得说。第一INSERT OR IGNORE配合主键comment_id重复评论会被自动跳过这就是增量监控的基础。第二time.sleep(random.uniform(1.2, 3.0))是随机休眠比固定间隔更平稳避免请求频率过于规律。情感分析和可视化部分import sqlite3 import pandas as pd import jieba import matplotlib.pyplot as plt def label_emotion(score): if score 0.5: return 好评 elif score 0.3: return 中评 else: return 差评 def draw_emotion_chart(item_id): conn sqlite3.connect(goods_comment.db) df pd.read_sql(SELECT emotion_score FROM comment_data, conn) conn.close() df[emotion_type] df[emotion_score].apply(label_emotion) emo_count df[emotion_type].value_counts() plt.rcParams[font.sans-serif] [SimHei] plt.figure(figsize(8, 6)) plt.pie(emo_count.values, labelsemo_count.index, autopct%1.2f%%, colors[#46b946, #ffcc5c, #ff5959]) plt.title(f商品{item_id}评价情感分布) plt.savefig(f商品{item_id}_口碑分布图.png, dpi300) plt.show() def get_negative_keywords(): conn sqlite3.connect(goods_comment.db) bad_df pd.read_sql( SELECT content FROM comment_data WHERE emotion_score 0.3, conn) conn.close() stop_words {的, 了, 很, 太, 就, 还, 有点, 但是, 感觉} all_words [] for text in bad_df[content]: for w in jieba.lcut(text): if len(w) 1 and w not in stop_words: all_words.append(w) word_series pd.Series(all_words).value_counts().head(15) print(差评高频痛点词 TOP15) print(word_series) return word_series主入口把流程串起来if __name__ __main__: TARGET_GOODS_ID 1234567890123 collector GoodsCommentCollector(TARGET_GOODS_ID) collector.batch_crawl_all(max_page30) collector.save_to_local_db() collector.export_to_csv() draw_emotion_chart(TARGET_GOODS_ID) get_negative_keywords()定时监控用schedule或者直接while True加time.sleep都行。生产环境建议用schedule库可读性更好import schedule import time def job(): collector GoodsCommentCollector(TARGET_GOODS_ID) collector.batch_crawl_all(max_page2) collector.save_to_local_db() collector.all_comment_list.clear() schedule.every(30).minutes.do(job) while True: schedule.run_pending() time.sleep(1)4. 验证请求与成功结果用样例数据跑通全流程配置写完之后不要直接上真实商品跑全量先用样例数据验证链路。这一步的目的是确认「采集—落库—打分—出图」每一环都通避免真实请求失败时你分不清是网络问题还是代码问题。先验证 API Key 是否可用。用一条最简单的请求import requests resp requests.post( https://taotoken.net/api/v1/chat/completions, headers{Authorization: Bearer 你的API_KEY}, json{model: 你的Model_ID, messages: [{role: user, content: 你好}]}, timeout15 ) print(resp.status_code) print(resp.text[:200])如果返回 200 并且有内容说明 Key 和 Base URL 都对。如果返回 401看下一节的排查。接着用样例数据验证情感分析和出图。手动往数据库插几条评论import sqlite3 from snownlp import SnowNLP conn sqlite3.connect(goods_comment.db) samples [ (s001, 用户A, 5, 质量很好面料舒服下次还来, 0.92), (s002, 用户B, 2, 尺寸偏小和描述不符退货了, 0.08), (s003, 用户C, 3, 还行吧物流有点慢, 0.35), ] for s in samples: conn.execute( INSERT OR IGNORE INTO comment_data (comment_id, nick, star, content, emotion_score) VALUES (?,?,?,?,?), s ) conn.commit() conn.close()然后跑draw_emotion_chart和get_negative_keywords。成功的话你会看到一张饼图好评、中评、差评三个扇区以及差评高频词里出现「尺寸」「偏小」「退货」这类词。这就是完整闭环跑通的标志。真实商品采集时观察控制台输出。正常情况是每页打印「正在采集第 N 页」直到某页返回空列表打印「无更多评价采集完成」。如果中途出现「采集异常」看异常信息里的状态码。采集完成后sqlite3 goods_comment.db SELECT COUNT(*) FROM comment_data;能查到总条数。增量验证再跑一次采集观察数据库条数是否只增加了新评论。如果条数没变说明去重生效如果翻倍了说明主键没起作用检查comment_id是否为空。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节按真实报错来对照。你大概率会遇到下面几种。401 Unauthorized。最常见的原因是 API Key 填错或者带了多余空格。检查config里的 Key 是否和控制台一致注意复制时不要带上换行。还有一种情况是 Base URL 写成了带路径的形式比如https://taotoken.net/api/v1而代码里又拼了一次/v1导致路径重复。Base URL 统一用https://taotoken.net/api路径拼接交给 SDK 或请求库。local proxy failed。这个报错通常出现在请求库尝试走系统代理但代理不可用时。检查环境变量HTTP_PROXY和HTTPS_PROXY是否被设置成了无效地址。在代码里显式禁用代理session requests.Session() session.trust_env False resp session.get(GATEWAY_URL, paramsparams, timeout15)reading choices 相关报错。这类错误一般出现在解析模型返回时返回结构里没有choices字段。原因可能是请求体格式不对比如messages写成了字符串而不是列表或者model字段填了一个不存在的 Model ID。检查 Model ID 是否和模型对话页面列出的完全一致大小写敏感。OAuth 相关报错。如果你用 Claude Code 接入报 OAuth 错误通常是settings.json里的ANTHROPIC_BASE_URL没生效工具还在尝试走默认的 OAuth 流程。确认配置文件路径正确且环境变量没有被系统级配置覆盖。可以用echo $ANTHROPIC_BASE_URL检查当前生效值。采集返回空列表。不一定是代码问题可能是商品 ID 填错或者该商品评论确实为空。先用浏览器打开商品页确认评论存在再检查item_id是否从链接里正确提取。SnowNLP 打分全部接近 0.5。这是模型对短文本和网络用语不敏感导致的。解决办法是维护一个自定义负面词库在打分前先做关键词命中判断命中负面词的直接降分。比如「退货」「偏小」「掉色」「破损」这些词命中就强制标记为差评候选。Matplotlib 中文显示方块。plt.rcParams[font.sans-serif] [SimHei]这行在 Linux 服务器上可能因为没装 SimHei 字体而失效。换成[WenQuanYi Micro Hei]或者提前apt install fonts-wqy-microhei。排查顺序建议先验证 Key 和 Base URL再验证单页采集再验证落库最后验证分析和出图。每一环单独验证出问题时定位范围小很多。6. 长期编码与 Agent 场景把监控系统接进你的工作流这套系统跑通之后下一步是让它真正融入日常工作流。几个方向可以拓展。差评实时告警。在save_to_local_db之后加一段逻辑查询本轮新增的差评emotion_score 0.3通过企业微信或者钉钉的 Webhook 推送。这样新增差评能在几分钟内触达运营而不是等第二天看报表。多商品并行监控。把GoodsCommentCollector实例化多次每个商品一个实例数据库表加一个item_id字段区分。查询时按item_id分组就能做竞品对比。大模型语义复核。SnowNLP 对模糊评论判断不准可以把0.3 emotion_score 0.5的评论批量丢给模型做二次判断。调用方式就是前面验证过的 chat completions 接口把评论内容作为 user message让模型返回「好评/中评/差评」三选一。这一步能把情感分析的准确率拉高一个档次。如果你长期做编码和 Agent 开发可以考虑用 Coding Plan 把模型调用额度固定下来避免按次计费带来的成本波动。接入文档里有完整的参数说明和示例API Keys 页面管理你的凭证。最后说一个实操技巧定时任务的间隔不要低于 30 分钟。评论数据不是秒级变化的高频轮询除了增加请求压力没有额外收益。把精力放在分析质量上比放在采集频率上更划算。数据库定期备份sqlite3 goods_comment.db .backup backup.db一条命令就能搞定历史数据是你做季度对比的底子。
返回列表