SEO在线检测优化源码这个东西,一开始我是真没打算自己写的。手头第三方工具的年费账单堆了好几个,某天接了个企业独立站的诊断需求,第三方报告堂而皇之甩出一百多个"待优化项",点开一看光是图片缺alt就占了40条,真正要命的——首页Canonical指向错误、全站超过五成的动态URL无限膨胀——反而藏在报告底部没标红。从那天起我决定自建一套能看日志、能跑规则、能存历史快照的检测分析系统。
这篇文章想分享的就是:我如何基于开源的检测源码思路,搭起一套"抓取数据—分析页面—输出优化任务—跟踪收录效果"的完整工具链。它适合三类人看:手头管着多个独立站或站群的站长,做源码建站和SEO外包的技术同学,以及所有对"检测报告为什么这么报""收录到底卡在哪个环节"有疑问的同行。检测只是手段,优化是过程,最终目标很直接——让网站获得更高收录。
1. 为什么我放弃第三方SEO体检工具,改自己搭检测源码
1.1 第三方工具的四个痛点
先说清楚,不是完全否定第三方工具。对于个人博客、新手站点,第三方免费版足够用了。但一套检测源码要能干事,得迈过四道坎,这四道坎恰恰是通用工具很难解决的。
第一个痛点是检测模板僵化。工具方为了覆盖大多数用户,规则写得很"通用":所有页面必须有meta description、所有图片必须有alt、H1必须唯一……规则本身没错,但套到电商站点、行业门户、企业官网上,误报率非常高。比如一个产品参数表格页面,本来就该用表格展示,工具非报"表格未加caption";一个纯JS渲染的页面,工具抓取不到正文就报"内容过短"。误报多到一定程度,团队就麻木了,真正重要的问题反而没人看。
第二个痛点是调度频率受限。第三方按URL数量计费还算温和,最难受的是API调用限制——一个站点每天只能触发几次全站检测,我今天改了20个页面的Title,要等24小时甚至一周才能复检。搜索引擎的收录反馈窗口就那几天,我不能等。
第三个痛点是无法对接自有数据。我自己服务器的访问日志里就躺着搜索引擎爬虫的全部抓取记录——今天来了几次、抓了哪些URL、返回什么状态码——这是判断收录状态的第一手资料。但第三方工具拿不到这些数据,只能靠公开接口猜。把日志和公开数据合并起来看,才能把"已收录/已抓取未收录/未被抓取"三态分清楚。
第四个痛点是成本。站点多的时候,按URL计费的检测费比服务器带宽还贵。我不如把检测逻辑固化到自己的源码里,缺什么检测项就写什么检测项。
1.2 什么样的站点最适合自建检测工具
自建检测系统不是银弹,核心是看URL规模和维护能力。根据这阵子的实践,我把适配情况整理了一张表:
| 站点类型 | 适配度 | 原因 |
|---|---|---|
| 独立站/企业站(10万URL以内) | 高度适配 | 规模可控,检测逻辑可定制,日志数据能闭环 |
| 站群/多个客户站点 | 高度适配 | 一次部署,批量调度,历史快照统一管理 |
| discuz/WordPress等源码建站 | 适配良好 | 页面模板固定,检测规则容易沉淀成配置 |
| 超大型平台站点 | 不建议 | 已经有专业团队和内部系统,自建意义不大 |
| 只做两三页的个人博客 | 不建议 | 第三方免费版检查一次就够了 |
我的建议是:如果你手里有源码建站的站点,尤其是discuz、WordPress这类CMS二次开发的,非常值得在检测源码上投入。CMS的模板机制决定了检测规则可以一次写死,后续新页面自动套用,边际成本极低。
1.3 技术选型:为什么我推荐Python + 关系型数据库打底
技术栈上,我用的是 Python + MySQL(小站点完全可以换 SQLite)。理由很直接:Python的requests/httpx处理页面抓取非常顺手,lxml解析DOM、json解析结构化数据都是一行调用的事;更重要的是检测规则本质上是"一堆if-else + 数据统计",Python写规则比Java/C++迭代快很多。
如果团队原本在PHP生态里,用PHP写也完全没问题,核心是检测逻辑而不是语言。我见过有人在discuz插件里直接集成页面检测函数,PHP实现对CMS站点反而更顺滑。无论用什么语言,我建议底层数据模型统一:URL是主键,检测时间、状态码、各检测项得分、页面hash都必须落表。没有历史数据,后续做"优化前后对比"就是无源之水。
2. 检测系统的核心模块拆解:抓取、判收录、析页面、评结构
2.1 收录检测:不是"查一下有没有"这么简单
很多人理解的收录检测就是site:域名搜一下,这在大搜索引擎里早就不准了。我做的第一版就吃了这个亏——site结果和实际索引量差了30%以上。后来我把收录检测拆成三个数据源交叉验证:
数据源一:搜索引擎资源平台回执。你提交Sitemap或手动提交URL之后,平台会返回每条URL的索引状态:已索引、未收录、抓取失败、违反政策。这是最接近真实状态的,但它只覆盖提交过的URL。我每天定时把全站URL去重后提交一次,把回执落库。
数据源二:服务器访问日志里的爬虫记录。搜索引擎蜘蛛抓取一个URL之后,通常会在几天内决定是否索引它。我按UA识别蜘蛛(每家的UA后缀都不一样),统计它抓了哪些URL、状态码是多少。如果一个URL被连续抓取多次但始终没进索引,大概率是内容或页面质量有问题——这在后面优化环节是关键线索。
数据源三:站内主动推送的发送记录。如果你的源码里有推送接口,每次推送后会拿到成功/失败回执,这些都是有效数据。
三份数据一合并,我就能把每个URL归到三类:已索引、已抓取未索引、从未抓取。检测代码如下示意:
def classify_index_status(url, index_feedback, crawl_logs): if url in index_feedback and index_feedback[url] == "SUCCESS": return "已索引" if url in crawl_logs and crawl_logs[url].get("last_status") == 200: return "已抓取未索引" return "从未抓取"这个分类看着简单,却是后续所有优化任务的起点。我踩过的一个坑是:只用一个数据源判断,导致误把"已抓取未索引"的页面当成收录成功,优化方向全跑偏了。
2.2 页面质量检测:标题、描述、关键词与结构化数据
页面质量是检测模块里检测项最多的部分,也是最容易产生误报的部分。我的做法是把检测项拆成"硬伤"和"建议"两档:硬伤必须改,建议按资源投入来。下面这张表是我现在用的核心检测规则:
| 检测项 | 判定逻辑 | 档次 |
|---|---|---|
| Title长度 | 30~60字符最佳,超出截断风险 | 硬伤/建议 |
| Title唯一性 | 全站不允许重复Title | 硬伤 |
| 核心词前置 | 核心关键词应出现在Title前30字符内 | 建议 |
| Meta Description | 50~160字符;缺失或空 | 建议 |
| H1唯一性 | 每个页面只允许一个H1,且包含核心词 | 硬伤 |
| Canonical自引用 | 每个页面必须有点向自身的Canonical | 硬伤 |
| Robots Meta | 确认关键页面没有被noindex | 硬伤 |
| 结构化数据 | JSON-LD语法校验,Article/BreadcrumbList等 | 建议 |
| 内链数量 | 少于3个内链提示"孤立页面"风险 | 建议 |
| 图片Alt | 缺失数量超过全部图片50%提示 | 建议 |
Title和Description的检测逻辑里有个细节容易被忽略:编码问题。页面是UTF-8还是GBK,直接决定字符数还是字节数——discuz老版本默认GBK,一个中文字符在部分编程环境里会被按3个字符截断。检测源码里要做编码归一化,先统一转成UTF-8再测长度。
关键词密度这块我想多说一句:不要再执着于2%~8%这种古早经验了。搜索引擎现在看的是语义相关度,不是密度。我在检测系统里保留了密度统计,但只把它当作参考维度,用来发现"堆砌嫌疑"而不是"优化不足"。密度超过15%但语义清晰,保持原样;密度低但整页围绕核心词展开,也是完全正常的状态。
2.3 抓取层面检测:状态码、重定向链与服务器响应
页面能不能被爬到,和好不好是两回事。抓取层检测主要盯四件事:
状态码异常。200/301/302/404/500是基本盘,我额外会标记两类隐藏问题:软404(返回200但页面内容提示"页面不存在")和重复状态码大量集中(说明程序有bug)。软404的检测逻辑很简单,抓取返回200的页面后,检查标题里是否包含"404""不存在""错误"等关键词,命中则判定为软404。
重定向链条。一次301没问题,301套301套301就麻烦了。搜索引擎爬虫每跳一次都要付出资源,链条超过5层很可能直接放弃。检测源码里要记录完整跳转链,我设的阈值是:超过3层标记为"待处理",超过5层标记为"硬伤"。
响应速度。我记录TTFB(首字节时间),超过3秒的页面标记为高风险。这里有个容易踩的坑:检测工具本身使用的机器和用户地域不同,网络延迟差异会污染速度数据。我的做法是在同一台服务器、同一网络环境、同一时间段内跑全站批量检测,用相对值排序,而不是用绝对值——同一个页面砸300ms和砸2s,横向一比谁快谁慢立刻清楚。
404页面是否定制。这个很多人忽略。一个返回200或空白页的"伪404",会让搜索引擎以为有大量空页面;定制过且返回真实404状态的页面,反而帮助引擎清理失效URL。检测规则里应该检查404页面是否返回正确的404头,以及页面内容里是否有站内导航。
2.4 检测数据落库与历史快照:让优化效果可对比
没有快照的检测系统只是体检单,有快照的检测系统才是病案本。我每次全站检测完,会把三个东西保存下来:
- URL维度快照:URL、状态码、标题、描述、各检测项得分、页面hash。
- 站点维度快照:总URL数、已收录数、已抓取未收录数、重定向数、404数、平均响应时长,整体健康分。
- 日志维度快照:蜘蛛抓取频次曲线、分UA抓取趋势。
有了快照,优化动作的效果就能精确到天来看。比如我改了首页Canonical之后,第3天日志显示蜘蛛重新抓取了首页,第7天资源平台显示首页重新索引,这两条时间线一对比,就能验证"Canonical修复→重抓取→重新索引"的因果链。这套复盘能力是第三方工具给不了的。
3. 从检测结果到优化动作:把"待优化项"翻译成可执行任务
3.1 给待优化项排序:优先级不是按红色数量,而是按收入影响
检测系统跑完之后,问题清单一大串,直接埋头逐个改是最低效的。我给优化项排优先级,只看三个维度:
- 是否影响收录:例如Canonical错误、Robots屏蔽、软404、大量重复内容,这类不修,其它都白搭。
- 是否影响点击率:Title和Description描述质量差,会导致即使排名上来了也没人点。
- 是否影响转化:与核心业务页面相关的问题(产品页、落地页、询盘页)永远排在最前面。
举两个实际案例。一个站全站图片Alt缺失上千条,对收录几乎没有直接影响,排在最后;网站首页的Canonical写错了,害得引擎把首页权重合并到了自己身上,这个一个小时内必须改。另一个站h1标签有三十多个页面缺失,但都是些帮助中心FAQ,我选择直接批量加上即可,不用单独走流程。优先级用一句话总结:先修让页面"进不了索引"的问题,再修让页面"排名不上去"的问题,最后修点击率层面的细节。
3.2 内容层优化:标题改写、摘要生成与内链补全
内容层优化是最消耗人力的部分,也是检测源码最能帮上忙的部分。我做了两件自动化的事。
第一件是Title批量生成建议。从一个页面的历史Title、核心关键词、页面正文首段中提取信息,拼出推荐Title格式:核心关键词放在最前,加上品牌词或地理词后缀。代码逻辑很简单:
def suggest_title(core_keyword, brand, category): candidates = [ f"{core_keyword}-{brand}", f"{core_keyword}_{category}_{brand}", f"{category}{core_keyword}品牌推荐", ] return candidates # 人工最终选择,不自动替换这里有一条红线必须划清楚:自动生成的Title只是候选,绝对不能自动替换线上页面。搜索引擎对标题的评判是综合性的,自动替换可能会有不可预料的负面效果。人工确认才能上线,这条经验来自一次失控的教训。
第二件是孤立页面检测。检测系统把所有"站内没有任何内链指向"的页面单独列表,这就是孤立页面清单。网站结构里最怕的就是这类页面——蜘蛛几乎发现不了它,即使有Sitemap也是徒劳。我处理的办法是在对应分类页的推荐位或"相关阅读"区块补上这些页面的内链,两三个就够,不需要大规模造链接。
3.3 结构层优化:URL规范化、Robots整改与Sitemap重建
结构问题往往是收录卡壳的根源,而且经常是历史遗留问题。这里讲三个最常见的整改动作。
URL规范化。同一个页面同时存在/product/123、/product/123.html、/product/123?utm_source=xxx、/product/123/index.php这些变体的时候,搜索引擎会视为重复内容。检测系统要做的,是扫描出全站URL的变体聚合,列出哪些URL参数不影响内容(纯追踪参数)哪些影响内容(如排序、筛选)。然后两个动作:不改变内容的参数在前面加rel="canonical"指回干净URL;在robots或代码层把无效变体301到主链。
Robots整改。我见过一个非常典型的坑:网站管理员为了加快收录,把JS和CSS资源全部在robots里Disallow了。引擎爬到页面,渲染时拿不到CSS/JS,页面结构判断异常,收录数量不升反降。检测源码里要专门检查robots.txt是否存在Disallow JS/CSS路径,发现立刻移除。另外,robots里应该显式指向Sitemap文件地址,格式是Sitemap: https://www.example.com/sitemap.xml,漏掉这条会降低Sitemap的发现效率。
Sitemap重建。很多站点的Sitemap是几个月没动过的静态文件,新发的内容不在里面。重建Sitemap时我放四个字段就够了:loc、lastmod、changefreq、priority。lastmod要写真实的最后修改时间,别所有页面都填当天,搜索引擎会认为你在刷时间戳。Sitemap按内容类型拆分:产品页一个、文章一个、分类页一个,每个文件URL不超过1万个。
3.4 CMS实战:以discuz列表页SEO设置为例
如果你用的是discuz这类老牌CMS,列表页的问题尤其典型——这完全值得单独写一段。discuz列表页的默认Title经常是"最新主题-版块名-站点名"这种模板,所有二级页面都一个模板,整版重复。搜索引擎看到几十个完全一样的Title,理所当然只收录最先发现的那一页。我处理流程是这样的:
第一步,列表页Title自动生成规则。在discuz的模板文件里,把标题改成"版块名-当前页数-站点名"的结构,第2页及以后自动加上"第N页"。这里要特别注意:超过第5页之后的列表页,如果内容没有明显新增,我建议直接加noindex标签,让引擎把抓取预算留给更有价值的内容页。
第二步,分页Canonical处理。discuz的分页URL是forum-x-1.html、forum-x-2.html这样递增。这里有两种做法:第一种是每页Canonical指向自身,适合"每一页有独立价值"的列表;第二种是第2页及以后Canonical指回第1页,适合"翻页只是分页"的连续列表。我的经验是:如果是分享资源帖、连载帖这种翻页有递进价值的,用第一种;如果是普通灌水列表,用第二种。千万别不写Canonical。
第三步,列表页Description。discuz默认很多列表页没有description,或直接把首帖内容截断当摘要。我建议在模板里输出版块简介作为description,没有简介的版块加一个默认文案。这个改动很小,但对点击率的影响很明显。
第四步,处理空列表页。一个没有帖子的版块,页面返回200但无内容,这就是标准的低质量页面。discuz里可以直接在检测通过后给这个页面加noindex,等有内容了再通过后台重新开放。配合检测系统,我每周跑一遍,凡是"列表无内容"的页面自动入列,效率很高。
4. 收录率上不去的真正瓶颈:收录链路的重建与监控
4.1 把收录看成一个链路而不是一个动作
我发现很多同行把收录理解成一个瞬间动作——提交了URL就等于收录了。实际上收录是一条链路,每一环都可能断掉:
URL被发现 → 内容被抓取 → 页面渲染 → 去重判定 → 索引建立 → 排序候选
检测系统应该在每个环节留下观测点。URL被发现,看日志里蜘蛛有没有访问Sitemap或爬过内链;内容被抓取,看日志里具体哪个URL被访问、状态码多少;页面渲染,看蜘蛛采样时是否成功返回完整HTML;去重判定,看标题或正文是否存在高度重合的页面;索引建立,看资源平台回执状态。
我举一个真实例子:有个站点所有页面都提交了,日志也显示蜘蛛天天来,但回执里全是"未收录"。我后来一查,站内所有内容页都是从一个模板生成的,正文部分用了同一段"产品描述"文字,只在参数处不同。搜索引擎把这些页面判定为重复内容,只保留了一两个代表页面。这就是"去重判定"环节卡死了,前三环全是通的。检测模块里必须加上正文相似度计算,我用的是简单hash + 前后100字符对比,超过80%相似直接标重。
4.2 重复与低质:导致收录负反馈的两大元凶
重复和低质是所有站点的大敌,但很多人意识不到它们会引发"负反馈"——搜索引擎开始降低整个站点的抓取频率和索引优先级。这是比单个页面不收录更严重的事。
重复内容的检测不复杂。我把全站标题跑一遍,完全相同的为一组;再把描述跑一遍,前缀相同的为一组;最后做正文hash比对,相同度超过阈值就标记。前面说过threshold我用80%,有点激进的话可以调到85%,宁可漏报也不能误伤。
低质页面则有几大特征:正文低于300字、无图片、无内链、无外链、无结构化数据、页面刷新时间超过180天。检测规则对上四条以上就标低质。处理办法有三条路:能合并内容的合并(比如多个短文章拼成一篇长文),不能合并的低价值页面加noindex,已经失效的直接404。这里有个关键动作:处理完之后,要在检测系统里看到"低质页面数量"指标逐日下降,这才是负反馈真正消化的信号。
4.3 复检闭环:从检测到优化到再检测
自建检测系统最大的价值在于能形成闭环:检测发现→优化整改→复检验证。我的节奏是这样的:每天自动跑一次轻量检测(只看状态码、robots、sitemap、日志几个维度),每周跑一次全量检测(连内容质量、结构化数据都跑)。每次优化动作上线之后,我会在检测系统里盯着三个指标:蜘蛛抓取频次、资源平台索引状态、全站收录率占比。
一个很实用的做法是设置变化阈值:如果某次改动后一周内,蜘蛛抓取频次没有上升,说明这次改动没有被引擎感知,需要检查是否有缓存或抓取障碍;如果抓取频次上升但收录率没变化,问题在页面质量;如果两者都上升了,说明进入了良性循环,可以按这个模式继续优化。千万别改完就不管了,搜索引擎对新Sitemap、新结构的理解和反馈是有延迟的(通常是1~3周),复检才能验证方向对不对。
5. 把这套检测源码真正跑起来:部署选型、频率控制与避坑
5.1 爬虫调度与请求控制:最容易被忽略的部分
检测系统本身就是一个爬虫,而"爬虫该不该被自己网站拦"是个很实际的问题。很多站点会在Nginx层按UA做限速或封禁,检测工具的UA如果没处理好,请求会被自己网站的WAF拒之门外,导致大量误报。我的做法是:给检测工具配置专属UA,形如DetectBot/1.0 (+站点域名),然后在站点白名单里放行这个UA——检测的是自己的网站,完全合理。
请求频率控制更重要。检测系统并发太大,会把源站打挂;并发太小,几万个URL要跑很久。我的经验是:单站点并发控制在5~10之间,请求间隔每URL至少200ms,随机抖动50~200ms。检测窗口选在凌晨流量低的时段。另外,每一轮检测做全站去重,避免参数差异导致同一页面被反复抓取。
这里单独提醒一句:检测工具不是SEO外包的"黑科技",它就是一个内部质量检测器。不要试图让它干任何改动线上内容、模拟用户点击之类的事情,那越界了,也没必要。
5.2 数据层性能优化:检测结果多时的慢SQL问题
全站检测跑完,一下几十万条结果metrics要落库,慢SQL立刻冒出来。搜索引擎热搜词里"慢sql优化"出现频率不低,这个坑确实常见,我在这块也踩过。最开始的表设计没有索引,SELECT * FROM url_snapshot WHERE domain='xxx' AND detected_at BETWEEN ...这种查询直接扫表,跑一次要几分钟。优化方案有几条:
- 核心字段建索引:URL的hash列必须唯一索引(避免重复快照),
detected_at普通索引,status_code普通索引。 - 批量插入用
INSERT ... ON DUPLICATE KEY UPDATE,避免逐条判断是否存在后再插入。 - 快照表按月分区,或者定期归档历史快照到独立表(比如保留最近30天热数据,更早的按归档月存冷表)。
- 检测完的数据先在内存里做完聚合统计,落库时只写聚合结果+抽样明细,而不是全量明细都写。
说实话,对大部分站点(10万URL以下),做好前三步,慢SQL基本就消失了;真正需要分区的是百万级URL的大站。
5.3 合规与边界:检测工具不是攻击工具
写这个模块的时候我必须把边界划清,这是底线问题。这套检测代码只允许运行在你自己拥有运营权限的站点上。你可以在自己的检测系统里配置任何自有域名;去扫没有授权的别人的站点、拿别人的页面数据做黑帽用途,这绝对不行,无论动机如何。
合规层面还有几个点:站点里有用户隐私数据的页面(订单页、个人中心)不要采集,告诉检测系统爬虫直接跳过这些路径;网站有登录鉴权的区域不做抓取,只检测公开页;所有检测行为严格遵守目标站点的robots.txt,如果robots声明了Crawl-delay,以robots为准。做合规处理不是应付监管,而是保护你自己,也保护搜索引擎对你的站点的正常信任关系。
5.4 上线运行之后,我踩过的三个坑
最后分享三个真实踩坑记录,希望能帮你少折腾几周。
第一个坑:把动态URL误判成无穷多页面。站点带搜索功能的,用户每次搜索都会生成/search?keyword=xxx,无休无止。检测系统头一回跑,爬出几十万个URL,站点健康分直接掉到20分。修复方案很简单:检测爬虫的URL去重模块里加参数白名单,凡是命中/search这种动态路径,只检测模板页面,不展开爬取。
第二个坑:检测脚本超时设置太短,全站误报抓取失败。默认10秒超时,结果页面上有第三方统计JS的,慢一点就超时了,系统把一堆正常页面标成"抓取失败"。后来我把超时调整为20秒,并加了三次重试,误报率立刻降了90%以上。检测数据要像生产线一样稳定,不要被偶发的慢请求污染。
第三个坑:检测完的结果没有人工复核流,误改线上配置。有一次系统报某个URL的Canonical指向错误,我直接按建议改了,结果页面又没出问题。排查后才发现是检测爬虫抓取时拿到了未登录态的缓存页面,Canonical信息本来就是旧的。现在我给系统加了"检测结果置信度"字段,凡是状态码异常或缓存特征明显的检测结果单独标记,等下一次检测复核后再进任务队列,避免瞎改。
我现在跑这套检测系统四个多月了,最大的收获不是省了那几千块年费,而是想通了一个问题:搜索引擎收录一个页面,本质上不是"提交"出来的,是"判断"出来的——它判断这个页面值不值得收进索引。检测源码是帮我观察这套判断逻辑的放大镜,真正的优化,最终还是回到内容价值和网站结构本身。如果你也想搭一套,别一上来就追求功能齐全,先从一个URL快照表、一个日志解析脚本、五个最关键的检测规则开始,跑起来之后你会比任何人都了解自己网站的底细。