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升级后代码被覆盖怎么办?
将去重逻辑写成独立文件,通过插件钩子方式引入,或者记录修改点,升级后重新应用。
去重算法不是一劳永逸的,需要根据采集源的质量调整阈值。
建议先在小批量数据上测试,确认效果后再全量启用。