商品評論與口碑分析:如何抓取商品詳情頁評價並進行情感分析與質素評估
商品评论与口碑分析:抓取商品详情评价数据,做情感分析与质量评估
文章示範以 Python 建立商品評價分析流程,涵蓋抓取、清洗去重、情感分析、質素評估與結果視覺化。抓取可優先使用評價 JSON 接口,或在需要時以 Playwright 載入頁面;情感分析可先用 SnowNLP,也可微調中文 BERT。評估會按做工、外觀、物流、性價比及售後等維度統計提及率與情感分,並計算綜合口碑分。
在电商场景里,商品详情页的评论区往往藏着比商品参数更真实的信息。用户会在这里吐槽物流、夸赞做工、抱怨色差,也会用一句话概括“值不值”。把这些评价数据抓下来,做情感分析和质量评估,就能把零散的口碑变成可量化的决策依据。
本文从工程落地角度出发,完整走一遍「抓取 → 清洗 → 情感分析 → 质量评估 → 可视化」的链路,代码以 Python 为主,尽量保证可以直接复制运行。
一、整体思路与技术选型
整个流程可以拆成四个阶段,每个阶段都有明确的输入输出,便于单独调试和替换。
flowchart TD
A[商品详情页] --> B[评价数据抓取]
B --> C[数据清洗与去重]
C --> D[情感分析]
C --> E[质量维度抽取]
D --> F[口碑评分聚合]
E --> F
F --> G[可视化与结论]
阶段 目标 常用方案
抓取 拿到评价文本、评分、时间、SKU requests + 接口逆向,或 Playwright 渲染
清洗 去重、去广告、过滤无效短评 正则 + SimHash
情感分析 判断正负面及强度 SnowNLP 基线,或微调 BERT
质量评估 按维度打分 关键词规则 + 情感加权
提示:抓取前务必确认目标站点的 robots.txt 与服务条款,控制请求频率,只采集公开可见的评价内容,不要触碰用户隐私字段。
二、评价数据抓取
2.1 优先找评价接口
大多数电商详情页的评价是异步加载的,翻页时前端会请求一个 JSON 接口。打开浏览器开发者工具的 Network 面板,筛选 XHR,翻一页评价就能看到类似 comment/list?itemId=xxx&page=1 的请求。相比解析 HTML,直接请求接口更稳定。
import time
import random
import requests
HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0 Safari/537.36"
),
"Referer": "https://example.com/",
}
def fetch_comments(item_id: str, max_page: int = 20):
"""按页抓取评价,返回原始 JSON 列表。"""
results = []
for page in range(1, max_page + 1):
params = {"itemId": item_id, "page": page, "pageSize": 20}
resp = requests.get(
"https://example.com/api/comment/list",
params=params,
headers=HEADERS,
timeout=10,
)
resp.raise_for_status()
data = resp.json()
comments = data.get("data", {}).get("comments", [])
if not comments:
break
results.extend(comments)
随机休眠,避免触发风控
time.sleep(random.uniform(1.0, 2.5))
return results
2.2 需要渲染时用 Playwright
如果评价内容由前端 JS 渲染且没有独立接口,可以用 Playwright 模拟滚动加载。
from playwright.sync_api import sync_playwright
def fetch_by_render(url: str, scroll_times: int = 10):
texts = []
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url, wait_until="networkidle")
for _ in range(scroll_times):
page.mouse.wheel(0, 2000)
page.wait_for_timeout(1200)
nodes = page.query_selector_all(".comment-item .content")
texts = [n.inner_text().strip() for n in nodes]
browser.close()
return texts
三、数据清洗与去重
原始评价里混着大量“此用户未填写评价”“系统默认好评”、表情符号和重复刷屏内容,直接送进模型会污染结果。
import re
import hashlib
DEFAULT_PATTERNS = [
r"此用户未填写评价",
r"系统默认好评",
r"^\s*$",
]
def clean_text(text: str) -> str:
text = re.sub(r"[\U00010000-\U0010ffff]", "", text) # 去 emoji
text = re.sub(r"\s+", " ", text).strip()
return text
def is_valid(text: str, min_len: int = 5) -> bool:
if len(text) < min_len:
return False
return not any(re.search(p, text) for p in DEFAULT_PATTERNS)
def simhash(text: str, bits: int = 64) -> int:
"""简化版 SimHash,用于近似去重。"""
tokens = list(text)
v = [0] * bits
for token in tokens:
h = int(hashlib.md5(token.encode("utf-8")).hexdigest(), 16)
for i in range(bits):
v[i] += 1 if (h >> i) & 1 else -1
result = 0
for i in range(bits):
if v[i] > 0:
result |= 1 << i
return result
def dedup(texts, threshold: int = 3):
seen, kept = [], []
for t in texts:
h = simhash(t)
if all(bin(h ^ s).count("1") > threshold for s in seen):
seen.append(h)
kept.append(t)
return kept
四、情感分析
4.1 快速基线:SnowNLP
如果只是做趋势判断,SnowNLP 足够快,适合先跑通链路。
from snownlp import SnowNLP
def sentiment_score(text: str) -> float:
"""返回 0~1 的正面概率。"""
try:
return SnowNLP(text).sentiments
except Exception:
return 0.5
def label(score: float) -> str:
if score >= 0.6:
return "positive"
if score <= 0.4:
return "negative"
return "neutral"
4.2 更准的方案:微调中文 BERT
电商评论有大量口语和反讽,通用模型容易误判。用几千条标注数据微调一个中文预训练模型,效果通常有明显提升。
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
Trainer,
TrainingArguments,
)
model_name = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=3)
def encode(batch):
return tokenizer(
batch["text"],
truncation=True,
padding="max_length",
max_length=128,
)
dataset 需包含 text 与 label(0/1/2) 两列
train_ds = dataset.map(encode, batched=True)
args = TrainingArguments(output_dir="./out", num_train_epochs=3,
per_device_train_batch_size=16, learning_rate=2e-5)
trainer = Trainer(model=model, args=args, train_dataset=train_ds)
trainer.train()
实践建议:先用规则和 SnowNLP 跑一版,人工抽查 200 条,统计误判类型,再决定是否值得投入标注成本。
五、质量评估:从情感分到维度分
单纯的正负比例不足以说明商品质量。更实用的做法是把评价拆成若干维度,分别统计提及率和情感倾向。
维度 关键词示例 评估含义
做工 做工、质感、毛边、缝隙 制造工艺水平
外观 色差、颜值、实物、图片 与详情页描述一致性
物流 发货、快递、包装、破损 履约体验
性价比 值、划算、贵、智商税 价格感知
售后 客服、退换、态度 服务保障
from collections import defaultdict
DIMENSIONS = {
"做工": ["做工", "质感", "毛边", "缝隙", "开线"],
"外观": ["色差", "颜值", "实物", "图片", "颜色"],
"物流": ["发货", "快递", "包装", "破损", "物流"],
"性价比": ["值", "划算", "贵", "智商税", "价格"],
"售后": ["客服", "退换", "态度", "售后"],
}
def evaluate(comments):
stats = defaultdict(lambda: {"count": 0, "score_sum": 0.0})
for c in comments:
text = c["text"]
score = c["score"]
for dim, words in DIMENSIONS.items():
if any(w in text for w in words):
stats[dim]["count"] += 1
stats[dim]["score_sum"] += score
result = {}
total = len(comments) or 1
for dim, s in stats.items():
result[dim] = {
"提及率": round(s["count"] / total, 3),
"平均情感分": round(s["score_sum"] / s["count"], 3) if s["count"] else 0.0,
}
return result
5.1 综合口碑分
把各维度得分按提及率加权,再结合整体情感分布,得到一个 0~100 的口碑分,便于横向对比不同商品。
def reputation_score(dim_result: dict, overall_positive: float) -> float:
if not dim_result:
return round(overall_positive * 100, 1)
weighted, weight_sum = 0.0, 0.0
for dim, info in dim_result.items():
w = info["提及率"]
weighted += info["平均情感分"] * w
weight_sum += w
dim_score = weighted / weight_sum if weight_sum else overall_positive
# 维度分占 70%,整体正面率占 30%
return round((dim_score * 0.7 + overall_positive * 0.3) * 100, 1)
六、结果可视化
用 matplotlib 画一张维度雷达图,再配一张情感分布柱状图,基本能一眼看出问题集中在哪。
import matplotlib.pyplot as plt
import numpy as np
def plot_radar(dim_result: dict):
dims = list(dim_result.keys())
values = [dim_result[d]["平均情感分"] for d in dims]
angles = np.linspace(0, 2 * np.pi, len(dims), endpoint=False).tolist()
values += values[:1]
angles += angles[:1]
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw={"polar": True})
ax.plot(angles, values, linewidth=2)
ax.fill(angles, values, alpha=0.25)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(dims)
ax.set_ylim(0, 1)
plt.title("各维度情感得分")
plt.tight_layout()
plt.savefig("radar.png", dpi=150)
七、工程化注意事项
增量抓取:按评价时间戳做增量,避免每次全量重跑。
限流与重试:对 429/503 做指数退避,单域名并发控制在个位数。
数据落库:评价文本、评分、时间、SKU 分开存,方便后续按维度聚合。
模型版本管理:情感模型更新后,历史结果要能复现,建议记录模型版本号。
合规:只采集公开评价,不存储用户昵称、头像等可识别信息。
八、总结
商品评论分析的价值不在于“抓了多少条”,而在于能否把非结构化文本转成可比较的指标。抓取阶段优先找接口,清洗阶段重点去重和过滤默认好评,情感分析先用轻量方案跑通再考虑微调模型,质量评估则要落到具体维度上,才能给选品、运营和售后提供真正可用的结论。
从工程角度看,这条链路的关键是可替换、可复现:每个阶段都保持清晰的输入输出,抓取层换站点、情感层换模型、评估层换维度权重,都不需要改动其他环节。建议先用小批量数据跑通全流程,验证指标合理后再逐步扩大采集规模,同时把模型版本、清洗规则和评分公式一并记录下来,方便后续对比和回溯。如有任何疑问,欢迎留言探讨!
來源:DEV Community · dev.to