CMS采集内容去重算法,避免重复文章发布

采集内容重复发布是很多站长头疼的问题,尤其是使用888 CMS批量采集时,同一篇文章可能被多次入库,影响SEO和用户体验。
本文面向零基础用户,讲解如何通过内容指纹和相似度算法,在888 CMS中配置去重逻辑,最终实现采集时自动跳过重复文章。

去重前需要理清的几个概念

内容指纹:
把文章正文通过哈希算法生成一串固定长度的字符串,
类似人的指纹,
用于快速判断两篇文章是否相同。SimHash:
一种局部敏感哈希算法,
能计算两篇文章的相似度,
适合检测“改了几个词”的伪原创内容。精确去重:
仅当两篇文章内容完全一致时才判定为重复。相似去重:
当相似度超过阈值(如90%)时判定为重复。

在888 CMS中,采集入库通常经过“获取内容→清洗→写入数据库”流程。
去重逻辑可以加在写入前,通过查询已有指纹库来判断。

准备工作:环境与数据表调整

假设你的888 CMS使用MySQL数据库,文章主表为cms_article。
首先需要新增一个字段存储内容指纹,并建立索引加速查询。

ALTER TABLE cms_article ADD COLUMN content_hash CHAR(64) DEFAULT NULL COMMENT 'SimHash指纹';
CREATE INDEX idx_content_hash ON cms_article(content_hash);

如果采集量较大,建议单独建一张指纹表cms_content_fingerprint,只存article_id和content_hash,避免主表过大。

CREATE TABLE cms_content_fingerprint (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  article_id INT UNSIGNED NOT NULL,
  content_hash CHAR(64) NOT NULL,
  created_at INT UNSIGNED DEFAULT 0,
  UNIQUE KEY uk_hash (content_hash),
  KEY idx_article (article_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

同时确认PHP环境已安装gmp或bcmath扩展,SimHash计算会用到位运算。

在采集入库前加入去重判断

888 CMS的采集入口通常在/admin/collect.php或类似文件中。
找到写入数据库前的代码段,插入以下逻辑。

第一步:生成内容指纹。
将文章标题和正文拼接后计算SimHash。
这里给出一个简化版PHP函数:

function simhash($text) {
    $words = preg_split('/[\s,,。.!!??;;::]+/u', strip_tags($text));
    $bits = array_fill(0, 64, 0);
    foreach ($words as $word) {
        if (empty($word)) continue;
        $hash = crc32($word);
        for ($i = 0; $i < 64; $i++) {
            $bit = ($hash >> $i) & 1;
            $bits[$i] += $bit ? 1 : -1;
        }
    }
    $fingerprint = '';
    for ($i = 0; $i < 64; $i++) {
        $fingerprint .= $bits[$i] > 0 ? '1' : '0';
    }
    return $fingerprint;
}

第二步:查询是否已存在相似指纹。
遍历指纹表,计算汉明距离(不同位的个数),如果距离小于等于3(经验值,可调整),则视为重复。

function isDuplicate($newHash, $pdo, $threshold = 3) {
    $stmt = $pdo->query("SELECT content_hash FROM cms_content_fingerprint");
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $distance = 0;
        for ($i = 0; $i < 64; $i++) {
            if ($newHash[$i] !== $row['content_hash'][$i]) $distance++;
        }
        if ($distance <= $threshold) return true;
    }
    return false;
}

第三步:入库时写入指纹。
如果判定为不重复,则在插入文章后,将新指纹写入指纹表。

if (!isDuplicate($newHash, $pdo)) {
    // 执行原有文章插入逻辑
    $articleId = insertArticle($data);
    $stmt = $pdo->prepare("INSERT INTO cms_content_fingerprint (article_id, content_hash, created_at) VALUES (?, ?, ?)");
    $stmt->execute([$articleId, $newHash, time()]);
} else {
    // 记录日志,跳过
    file_put_contents('/tmp/collect_skip.log', date('Y-m-d H:i:s')." 重复跳过\n", FILE_APPEND);
}

避坑指南:性能与误判处理

性能问题:如果已有文章超过1万篇,全表扫描汉明距离会拖慢采集速度。
建议先用精确匹配查一次content_hash,没有完全相同的再计算汉明距离。
或者将指纹分块存储,使用MySQL的BIT_COUNT函数加速。

误判处理:SimHash对短文本(少于50字)区分度较低,容易误判。
对于短内容,可以改用MD5精确去重。
同时,阈值3并非固定,文章越长可以适当放宽到5,但需要实际测试。

数据清理:删除文章时,记得同步删除指纹表中的记录,否则后续采集相同内容会被误判为重复。
可以在删除逻辑中增加DELETE FROM cms_content_fingerprint WHERE article_id = ?。

验证去重是否生效

完成配置后,手动采集一篇已存在的文章,观察日志/tmp/collect_skip.log是否出现跳过记录,同时检查数据库文章总数是否不变。
再采集一篇全新文章,确认能正常入库且指纹表新增记录。

如果使用宝塔面板,可以在“计划任务”中添加一个脚本,定期统计重复率:

#!/bin/bash
mysql -u root -p'密码' -e "SELECT COUNT(*) FROM cms_content_fingerprint" 你的数据库名

判断标准:正常情况下,重复采集同一来源的文章,第二次及以后都应被跳过。
如果发现重复入库,检查指纹表是否为空,或者汉明距离阈值是否过大。

常见疑问

采集时标题相同但正文不同,会判重吗?
如果指纹只基于正文,则不会。建议标题和正文一起计算,或者单独对标题做精确去重。

SimHash和MD5去重哪个更好?
MD5适合完全重复的内容,速度快;SimHash适合检测伪原创,但计算量稍大。可以两者结合:先MD5精确匹配,再SimHash相似匹配。

888 CMS升级后代码被覆盖怎么办?
将去重逻辑写成独立文件,通过插件钩子方式引入,或者记录修改点,升级后重新应用。

去重算法不是一劳永逸的,需要根据采集源的质量调整阈值。
建议先在小批量数据上测试,确认效果后再全量启用。

分享到:
上一篇
CMS站群服务器IP隔离,不同站点独立IP部署
下一篇
CMS模板缓存机制原理,修改模板不生效原因
1
系统公告

泽御云中秋国庆双节活动上线:新购8折,拼团3.99元起

尊敬的用户:
泽御云“月满中秋·礼贺国庆”双节活动现已开启,活动时间为2026年9月23日至10月10日。 活动期间可享以下福利:
1. 常规云服务器新购使用优惠码“泽御中秋国庆同乐”,符合条件的订单享8折优惠。
2. 香港精品云服务器5人拼团低至3.99元,部分4核4G套餐3人拼团年付388元,续费同价。
3. 新用户购买年付云服务器,符合活动规则可赠送2个月使用时长。
4. 老用户续费季度赠15天,续费年度赠2个月;活动期间升级配置免收配置迁移手续费。
5. 推荐好友成功下单,符合条件的推荐人可获赠7天服务器使用时长。
6. 活动期间享宕机补偿标准翻倍、简单网站迁移协助及技术工单优先处理权益。
温馨提示:优惠码不适用于拼团套餐、活动轻量产品、年付订单及续费订单;拼团套餐为独立特价活动,不与赠时类福利叠加。赠送时长不可折现、退款或跨账户转移,具体规则以活动页面说明为准。
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意