知识

如何大规模检测虚假评论和评论欺诈

美国、英国和欧盟均已禁止虚假评论,各平台也删除了数以亿计的虚假评论。如何在众多产品中检测评论欺诈,附经过测试的代码。

Matt Brown

Matt Brown

2026年10月2日 · 4 分钟阅读

假评论不再只是声誉问题。在美国、英国和欧盟,它现在也是一个法律问题,各平台正在以数亿条的规模删除假评论。对品牌、市场平台或信任与安全团队来说,这就提出了一个实际问题:如何在数千个产品中发现评论欺诈,而不仅仅是有人投诉的那一条商品?

本指南涵盖问题的规模、能真正区分刷单活动和真实顾客的信号、针对三个最有用信号的经过测试的代码,以及如何负责任地收集评论数据。

关键要点

  • 规模很大。Google 在 2025 年于 Maps 上拦截或删除了超过 2.92 亿条违反政策的评论,Amazon 表示在 2023 年阻止了超过 2.5 亿条疑似虚假评论。
  • 靠阅读评论来辨别是行不通的。在一项知名研究中,人工评审在识别虚假酒店评论时的准确率接近随机猜测,介于 53% 到 62% 之间,而一个经过训练的分类器达到了约 90%。
  • 协同刷单活动会留下行为痕迹:几天内评论激增、措辞近乎一致,以及没有其他历史记录的评论者。
  • 应结合多个信号。在我们的测试中,单靠措辞相似度噪声很大,而将激增与重复措辞或单评论账户结合后,捕获了所有植入的虚假评论,误报最多只有三条。
  • 将标记结果当作人工审核的线索,对评论者数据做假名化处理,并在根据发现采取行动前先核查法律立场。

问题有多大

各平台自己公布的透明度数据给出了问题规模的概览:

平台数据时间段
Google Maps拦截或删除超过 2.92 亿条违反政策的评论;移除超过 1300 万个虚假商家资料2025
Amazon阻止超过 2.5 亿条疑似虚假评论2023
Tripadvisor在提交的 3110 万条评论中有 270 万条属于欺诈;54% 的欺诈是商家自我刷单;移除了 214,000 条 AI 生成的评论2024

这些是被抓住的评论。它们也说明了欺诈大体上是什么样子:在 Tripadvisor 上,一半以上是商家或与其有关联的人进行的评论刷单,而不是精心策划的欺骗。

规则已经改变

目前三大市场明确禁止虚假评论:

  • 美国。 联邦贸易委员会关于消费者评论与证言的规则,自 2024 年 10 月起生效,禁止虚假评论、购买正面或负面评论、未披露的内部人员评论、以独立名义呈现的公司自营评论网站,以及评论压制行为,并允许该机构寻求民事处罚。
  • 英国。 自 2025 年 4 月 6 日起,提交或指使撰写虚假评论、隐瞒有激励的评论以及以误导方式发布评论均属被禁止的行为,发布评论的企业必须采取合理措施防止和移除虚假评论。监管机构可处以最高全球营业额 10% 的罚款。
  • 欧盟。 自 2022 年 5 月起,展示评论的经营者必须说明是否以及如何核实评论来自实际使用或购买过产品的顾客,提交或指使虚假评论属于被禁止行为。

对于市场平台和评论发布方而言,这使得检测从一项加分项变成了合规的一部分。对品牌而言,这为在竞争对手购买评论时采取行动提供了途径。这是一般性信息,不构成法律建议;请就自身情况咨询律师。

为什么阅读评论行不通

关于这一问题最著名的学术研究,由康奈尔大学的 Ott、Choi、Cardie 和 Hancock 完成,构建了一组 800 条酒店评论:400 条真实,400 条刻意撰写用以欺骗。三名人工评审对其进行分类。他们的准确率分别为 53.1%、56.9% 和 61.9%,其中两人的结果与随机猜测相比在统计上并无显著差异。三人都倾向于认为评论是真实的。一个基于词语模式训练的分类器达到了 89.8%。

这带来两点启示。人工抽查将漏掉大部分假评论。而且纯文本检测现在比 2011 年时更难:模型可以按需写出多样化、听起来自然的评论,这正是 Tripadvisor 现在将 AI 生成的评论单独列为一个类别的原因。更经得住考验的信号是行为性的:评论何时出现、谁撰写了它们,以及它们彼此之间有多相似。

经得住考验的信号

信号捕获的问题弱点
激增平时每天两条评论的产品,几天内突然出现数十条促销、发布或媒体报道后的真实高峰
近似重复措辞带有少量词语替换的模板化评论真实评论中常见的措辞;多样化的 AI 撰写文本
单评论账户为单次刷单活动创建的评论者新的真实顾客
评分形态突然出现一连串细节很少的五星评论真正优质的产品
跨产品重叠同一批评论者出现在某卖家的多个产品上忠实顾客
跨市场差异某产品在某一国家的店铺中评分明显不同本地版本或服务存在真实差异

单一信号都不可靠。激增可能是一次成功的发布;相似措辞可能只是常见短语。刷单活动往往同时表现出多个信号,这正是组合使用信号能够有效的原因。

代码

下面的模块实现了其中三个信号以及一种组合它们的方法。它不需要任何外部库。评论者姓名在分析前会被替换为加盐哈希,因为评论属于个人数据,而分析本身从不需要姓名。

import hashlib
import re
from collections import Counter, defaultdict
from statistics import median


def pseudonymise(author, salt):
    """Replace a reviewer's name with a stable token, so analysis never needs the name itself."""
    return hashlib.sha256((salt + author).encode()).hexdigest()[:12]


def review_bursts(reviews, k=6.0, min_count=5):
    """Flag days whose review count is far above the product's typical day, using a robust baseline."""
    daily = Counter(r["date"] for r in reviews)
    counts = list(daily.values())
    base = median(counts)
    spread = median(abs(c - base) for c in counts) or 1
    flagged = []
    for day, n in sorted(daily.items()):
        if n >= min_count and n > base + k * spread:
            day_reviews = [r for r in reviews if r["date"] == day]
            five_star = sum(r["rating"] == 5 for r in day_reviews) / n
            flagged.append({"date": day, "reviews": n, "baseline": base, "five_star_share": round(five_star, 2)})
    return flagged


def shingles(text, size=5):
    text = re.sub(r"\s+", " ", text.lower()).strip()
    return {text[i:i + size] for i in range(max(1, len(text) - size + 1))}


def near_duplicates(reviews, threshold=0.5):
    """Pairs of reviews by different reviewers whose wording overlaps heavily (Jaccard on 5-character shingles)."""
    sets = [shingles(r["text"]) for r in reviews]
    pairs = []
    for i in range(len(reviews)):
        for j in range(i + 1, len(reviews)):
            if reviews[i]["reviewer"] == reviews[j]["reviewer"]:
                continue
            overlap = len(sets[i] & sets[j]) / len(sets[i] | sets[j])
            if overlap >= threshold:
                pairs.append((reviews[i]["id"], reviews[j]["id"], round(overlap, 2)))
    return pairs


def one_review_accounts(reviews, history):
    """Share of reviewers in this set who have reviewed nothing else; history maps reviewer to their total reviews."""
    reviewers = {r["reviewer"] for r in reviews}
    return sum(history.get(x, 1) == 1 for x in reviewers) / len(reviewers)


def suspicious_reviews(reviews, history, threshold=0.5):
    """Combine the signals: a review is suspicious when it sits in a burst and either duplicates
    other wording or comes from a one-review account."""
    burst_days = {b["date"] for b in review_bursts(reviews)}
    duplicated = defaultdict(int)
    for a, b, _ in near_duplicates(reviews, threshold):
        duplicated[a] += 1
        duplicated[b] += 1
    return [r["id"] for r in reviews
            if r["date"] in burst_days and (duplicated[r["id"]] or history.get(r["reviewer"], 1) == 1)]

激增检测器使用中位数和中位数绝对偏差而不是均值和标准差,这样激增本身不会抬高被用来衡量它的基线。near_duplicates 中的两两比较对单个产品的评论来说是可行的;对整个目录而言,应先按产品或卖家对评论分组,或使用局部敏感哈希。

表现如何

我们在一个答案已知的构造数据集上测试了该代码:一个产品六个月的自然评论,数量在 256 到 285 条之间,平均每天几条,评分和措辞都较为真实多样,外加一个植入的刷单活动,即三天内来自新账户的 40 条模板化五星评论。我们用六个不同的随机种子分别运行了该代码。

检查项六次运行的结果
激增检测找出的刷单天数每次都是全部三天;相对基线每天 2 条,激增天数为每天 13 到 16 条
组合规则捕获的植入评论每次都是 40 条中的 40 条
组合规则误标的真实评论0 到 3 条
仅凭措辞涉及真实评论的近似重复配对数27 到 42
没有其他评论记录的评论者比例刷单天数为 81% 到 100%,整体为 27% 到 31%

最后两行是关键。单靠措辞相似度就标记出了数十个涉及真实顾客的配对,因为真实评论也会共用普通的措辞。只有当它与激增结合起来时,才变得精确。这正是值得借鉴的模式:让一个信号提出候选,另一个信号加以确认。

构造出来的测试并非真实世界。真实的刷单活动会将评论分散在数周内进行、变化文本措辞,并在使用账户前先让其”养号”。实践中应预期较低的召回率,根据已确认的案例调整阈值,并将每一个标记都视为交给人工审核的线索,而非最终结论。

收集评论数据

检测需要带有日期、评分,以及足以查看历史记录的评论者背景信息的评论。收集时需要注意以下几点:

  • 跨市场收集。 同一产品在不同国家的店铺中常常显示不同的评论,而刷单活动往往针对某一个市场。从目标国家内部分别采集每个店铺的数据,才能看到当地购物者所看到的内容,这与监控顾客评论所用的方法相同。
  • 保留历史记录。 激增和单评论账户只能通过一段时间的观察来衡量,因此应按计划定期采集并保留已采集的数据。
  • 最小化个人数据。 在可能的情况下存储经过假名化处理的评论者标识而非姓名,只保留分析所需的字段,并设定保留期限,具体做法见住宅代理与 GDPR。
  • 遵守规则范围。 以适度的频率采集公开的评论页面,遵守每个网站的使用条款,不要触碰需要登录才能访问的内容。

评论欺诈很少是孤立发生的。购买评论的卖家往往还会劫持商品列表或销售假冒产品,评论文本也越来越需要像任何其他AI 生成内容一样被仔细审查。对于需要在多个来源上大规模开展此项工作的团队,更广泛的工作流程见我们的大规模内容审核页面。

结论

虚假评论很常见,现在在最大的几个市场中已被明确列为非法,而且很难通过阅读来识别。暴露刷单活动的是行为:评论来得太快太多,彼此之间太相似,而且来自没有其他历史记录的账户。

应在一段时间内并跨市场持续收集评论,对撰写者进行假名化处理,组合多个信号以相互确认,并在任何人据此采取行动之前,把被标记的内容交给人工处理。

来源与参考文献

准备好开始了吗?

试用 Shifter 住宅代理,205M+ 个 IP,195+ 个国家,低至 $0.10/GB。

立即开始