☰
URL推送与质量预审:站点收录链路排查和优化实操
2026/10/28 11:15:20 网站建设 项目流程

站点上线两个月,内容更新了几百篇,搜索结果里翻来覆去只躺着首页和两个栏目页,这种场景我这两年帮人排查过不下二十次。问题极少出在“搜索引擎不喜欢你”这类玄学上,绝大多数时候是链路中间某一环断了:要么页面压根没被发现,要么被发现后抓取失败,要么抓下来了但内容被判成不值得单独建索引。围绕URL 推送和质量预审这两件事,我把这几年踩过的坑、验证过的流程整理成一套能照着走的做法,从提交通道选型、推送脚本落地,到推送前的自检清单和收录异常排查,都会给到具体的参数、代码和判断标准。这套东西对刚接手的运维、独立负责内容站的运营、以及兼着做技术 SEO 的后端都适用,不需要多深的算法背景,能看懂 HTTP 状态码、会复制粘贴脚本、愿意花半小时看日志就够了。

1. 收录链路的真实结构:为什么单靠“提交”解决不了问题

1.1 一条 URL 走到索引要过几道关

很多人对收录的理解停留在“提交了就等于收录了”,这是个典型的认知错位。把一条新页面从上线到能在搜索结果里被搜到,中间至少隔着五道关卡,任何一道卡住,后面的动作都是白做。

第一道是发现,搜索引擎得先知道这个 URL 存在。发现途径有四条:站内链接爬行、外部链接、站点地图、主动推送。第二道是调度,知道归知道,什么时候来抓是它说了算,这里涉及站点权重、历史抓取成功率、服务器响应速度。第三道是抓取,真的发请求过来了,你的服务器得在合理时间内返回 200,返回 403、404、5xx 或者超时,这次抓取就废了。第四道是解析与渲染,尤其是现在大量站点靠前端框架渲染,首屏内容如果必须执行一堆 JS 才出来,解析成本会显著上升。第五道是索引判定,抓回来的正文要过质量关:是不是采集拼凑、是不是和站内其他页面高度重复、是不是空壳列表页、有没有实质信息增量。

我把这五道关画成一句大白话:推送只是把简历递到了桌上,录不录用还得看简历本身。所以那些“我天天推送怎么还是不收录”的疑问,八成卡在第三道和第五道,而不是第一道。搞清楚这一点,后面的动作才有针对性——推送负责加速第一道,预审负责保住第五道。

1.2 三种提交通道的定位与取舍

资源平台一般会给到三种提交入口,各家的命名不一样,但本质就这三类:主动推送接口、站点地图、手动单条提交。它们的定位差异很大,混着用会浪费配额。

通道时效性配额特征适合的页面失败反馈
主动推送接口分钟到小时级按站点表现动态分配,新站偏少新发布的原创内容、时效性强的页面有明确返回码,可重试
站点地图小时到天级无严格条数配额,但有文件规格限制存量页面全量覆盖、栏目页、历史归档只能看抓取与索引结果反推
手动单条提交分钟级每日条数极少重点页面补救、临时活动页提交即受理,结果需回看

我的实际用法是三条腿分工:站点地图做全量兜底,保证任何一个可访问页面至少有一条被发现路径;主动推送只喂新发布且过了预审的页面,绝不拿它去推存量;手动提交留作应急,比如某篇稿子当天要上首页推荐,推一次就够了。这个分工的关键在于——推送配额是稀缺资源,一旦拿去推低质页面,站点整体信任度会被拉低,后续配额只会更少,形成负循环。

1.3 把质量预审前移,是配额有限时的最优解

配额有限这件事短期内改变不了,那能优化的就只剩“推什么”。我把预审放在推送之前,逻辑很简单:推送是不可撤销的动作,页面一旦被推过去并被判定为低质,这个负面信号会挂在站点维度上,影响的是所有页面。而预审是零成本的,多花五分钟看一遍,比推十个垃圾页面划算得多。

预审不需要多复杂的工具,一张清单加一个浏览器就够了。我一般的顺序是:先看这个页面有没有独立存在的价值(能不能回答一个具体问题、有没有独家信息),再看技术层面能不能被正常抓取(状态码、首屏内容、移动端表现),最后看元信息有没有硬伤(标题重复、canonical 指向错误、结构化数据和正文对不上)。三步走完,能砍掉大半不该推的 URL。下面几节会把每一步拆开讲透。

2. 推送之前的底层准备:先把“能被抓、值得抓”做实

2.1 抓取通道的三项硬检查

推送之前必须先确认抓取通道是通的,否则推过去也是白推。这三项检查我每次接手新站都会跑一遍,十分钟内能出结果。

第一项,robots 文件。最常见的翻车是测试环境遗留的Disallow: /被同步到了生产环境,整站一封,抓取量直接归零。检查方法很土但有效:直接浏览器访问https://www.example.com/robots.txt,看返回是不是 200,内容里有没有误伤。特别注意别把 CSS、JS 目录或者图片目录一起封了,现在渲染依赖这些静态资源,封了等于自己把首屏搞残。另外 robots 文件本身别做 302 跳转,某些抓取端对跳转后的 robots 处理不一致,容易出玄学问题。

第二项,状态码。随便抽二十个准备推送的 URL,用 curl 看返回头。要求是干净的 200,不能是 200 但内容是“页面不存在”的软 404,也不能是 301 链式跳转好几次才到目标页。

curl -sS -o /dev/null -w "%{http_code} %{redirect_url} %{time_total}\n" \ -A "Mozilla/5.0 (compatible; SiteAudit/1.0)" \ https://www.example.com/article/1001

输出里第二个字段如果有内容,说明存在跳转,链式跳转超过一跳就该改成直连。第三个字段是总耗时,超过 3 秒的页面建议单独排查,服务端慢会直接拉低抓取频次。

第三项,首屏可渲染。关掉浏览器缓存,禁用 JS 看一眼,如果正文一个字都没有,那就要评估渲染成本了。我的经验是:内容型页面尽量做服务端渲染或者静态化,交互型模块再交给前端,别让正文依赖三层异步请求才拼出来。

注意:检查时用的 User-Agent 要和真实抓取端接近,某些站点做了 UA 白名单或者 CDN 做了人机识别,用默认 curl 的 UA 请求会拿到 403,误判成抓取失败。

2.2 URL 规范化:同一份内容只留一个门牌号

重复 URL 是收录效率的隐形杀手。同一篇文章如果有五种访问形态,抓取端会当成五个页面去抓、去判重,最后要么互相稀释权重,要么只留一个其余全进“已抓取未编入索引”。下面这张表是我在站点审计里最常命中的几种重复形态。

重复形态示例处理方式
协议与主机名不一致http/https、带 www 与不带 www301 统一到唯一形态
结尾斜杠差异/article/1001与/article/1001/服务端 301 或框架层统一
大小写混用/Article/1001与/article/1001路由层强制小写
无意义查询参数?from=list&spm=abccanonical 指回干净 URL,或 robots 屏蔽
分页与筛选?page=2、?tag=x&sort=new分页保留并自指 canonical,筛选组合屏蔽
打印页、AMP 页/print/1001canonical 指向正文页

处理原则只有一条:每个内容实体对应唯一一个规范 URL,其余形态要么 301 过去,要么 canonical 指过去,要么直接不让抓。canonical 是建议不是命令,能 301 的优先 301,因为 301 是硬信号,canonical 有可能被忽略。

这里有个容易忽略的点:分页页面的 canonical 千万别指回第一页。很多人图省事把?page=2的 canonical 全指向列表首页,结果第二页往后的内容永远进不了索引。正确做法是分页自指,同时保证分页里的详情链接是真实可点的<a href>,别用 JS 点击事件。

2.3 站点地图的分片、更新与 lastmod 纪律

站点地图是唯一一个不消耗推送配额、又能覆盖全站的通道,值得认真做。规格上有两条硬约束:单个文件不超过 50000 条 URL,未压缩体积不超过 50MB。超了就得分片,用索引文件串起来。

<?xml version="1.0" encoding="UTF-8"?> <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <sitemap> <loc>https://www.example.com/sitemap-article-1.xml</loc> <lastmod>2025-03-18</lastmod> </sitemap> <sitemap> <loc>https://www.example.com/sitemap-article-2.xml</loc> <lastmod>2025-03-18</lastmod> </sitemap> </sitemapindex>

lastmod这一项我要单独说,因为踩过坑。只写真实的内容变更时间,不要在每次生成时无脑刷成当前时间。全站 lastmod 天天变化,抓取端会判定这个字段不可信,之后你真正更新了页面它也不当回事。我一般的做法是:文章表里存一个content_updated_at字段,只有正文实质性修改才更新,改个错别字、调个样式不算。

分片策略上,我倾向按内容类型分(文章、商品、专题各一份),再按时间切子片。好处是新增内容只需要重新生成最新的那个子片,不用全量重写;排查问题时也能快速定位是哪一类内容出了问题。

提示:站点地图里只放返回 200 的规范 URL。曾经见过一份 sitemap 里混进了几万条 404 和重定向地址,结果整份文件的抓取优先级被压到很低,好页面也跟着遭殃。

3. URL 推送实操:配额、脚本与节奏控制

3.1 鉴权、配额与推送前的三项自检

推送接口的鉴权通常是站点维度绑定的:在平台后台验证站点归属(DNS 记录、文件校验或者 meta 标签三选一),拿到一个 token,之后所有请求都带上site和token两个参数。token 泄露的风险很实在——别人可以拿你的配额去推垃圾 URL,所以别把它硬编码进前端代码或者公开仓库,走环境变量。

配额这块要有清醒认识:每日额度是动态的,跟站点的历史推送质量、抓取成功率、内容更新频率都相关。新站初期额度少是正常的,别一上来就想着推全站。我在后台一般会看三个数:今日剩余额度、近七天的推送成功率、以及推送后被抓取的比例。第三个指标最能说明问题,如果推了一千条只有几十条被抓,那问题不在配额,在页面本身。

正式推之前的三项自检,我做成了一张小便签:

  • URL 必须是规范形态,和 canonical 完全一致,不带任何统计参数
  • URL 必须当前可访问且返回 200,推送前十分钟内验证过
  • URL不能重复推,同一地址当天推两次纯属浪费,第二次大概率返回重复提示

第三项很多团队会忽略,因为定时任务重跑、人工补推、多个人同时操作,很容易重复。我在推送脚本里加了一张本地去重表,按url + 日期做唯一键,简单但管用。

3.2 一份可直接改的批量推送脚本

下面这份脚本是我一直在用的模板,改掉常量和接口地址就能跑。设计上有三个考虑:分批提交避免单次请求过大、失败分类而不是无脑重试、结果全部落盘方便事后复盘。

import os import time import json import random import hashlib import requests from datetime import date PUSH_ENDPOINT = os.environ["PUSH_ENDPOINT"] # 以平台文档给出的地址为准 SITE = os.environ["SITE"] # 例如 https://www.example.com TOKEN = os.environ["PUSH_TOKEN"] BATCH_SIZE = 50 QPS_INTERVAL = 0.5 # 每次请求间隔,别打满 RESULT_FILE = f"push_result_{date.today()}.jsonl" session = requests.Session() session.headers.update({"Content-Type": "text/plain; charset=utf-8"}) def push_batch(urls, retry=2): payload = "\n".join(urls) last_err = None for attempt in range(retry + 1): try: resp = session.post( PUSH_ENDPOINT, params={"site": SITE, "token": TOKEN}, data=payload.encode("utf-8"), timeout=15, ) if resp.status_code == 200: return {"ok": True, "body": resp.json()} if resp.status_code in (401, 403): return {"ok": False, "fatal": "auth", "code": resp.status_code} if resp.status_code == 429: time.sleep(2 ** attempt + random.random()) continue last_err = f"http_{resp.status_code}" except requests.RequestException as exc: last_err = type(exc).__name__ time.sleep(2 ** attempt + random.random()) return {"ok": False, "fatal": None, "err": last_err} def run(url_list): seen = set() for i in range(0, len(url_list), BATCH_SIZE): batch = [] for u in url_list[i:i + BATCH_SIZE]: key = hashlib.md5(u.encode()).hexdigest() if key in seen: continue seen.add(key) batch.append(u) if not batch: continue result = push_batch(batch) with open(RESULT_FILE, "a", encoding="utf-8") as f: f.write(json.dumps( {"ts": time.time(), "size": len(batch), "result": result, "urls": batch}, ensure_ascii=False) + "\n") if result.get("fatal") == "auth": raise SystemExit("鉴权失败,检查 token 与站点绑定关系") time.sleep(QPS_INTERVAL)

几个细节值得说明。BATCH_SIZE设 50 是个经验值,太小请求次数多、太大单次失败代价高,50 上下比较稳。QPS_INTERVAL别设成 0,接口再宽松也经不住并发打满,被限流之后恢复起来很麻烦。429单独处理成退避重试,401/403直接终止,因为这类错误重试一百次也没用。

结果落成 jsonl 而不是直接打印,是为了后面能统计。我一般第二天早上跑一个统计脚本,看成功多少、失败多少、失败集中在哪些返回码上,比翻日志高效。

3.3 推送节奏设计与失败重试的退避策略

节奏这件事比脚本本身更重要。我见过最典型的错误做法是:内容站积压了几万条存量页面,某天想起来要收录,写个循环一口气全推了。后果是当天配额瞬间耗尽,而且因为大量页面同时被推、同时被抓,服务器直接扛不住,抓取大面积超时,反而把站点的抓取评分拉低。

我的节奏方案是这样的:新发内容即时推,发布成功后三十秒内推一次,这是最黄金的时间窗;存量内容按比例慢慢补,每天拿配额的 20% 左右去补历史页面,优先补那些有自然搜索需求、有实质内容的,列表页和标签页基本不推;大促或专题上线前预留额度,提前三天停止补存量,把额度攒下来给重点页面。

失败重试要分类。我把返回码分成三档:

  • 可重试:网络超时、5xx、429 限流。用指数退避,间隔 1s、2s、4s,最多三轮。
  • 不可重试:401、403 鉴权类,直接停下报警。
  • 部分成功:返回体里逐条给出状态的情况,把失败的那几条挑出来单独处理,别整批重推。

还有一点,推送不等于要收录。有些页面推了但一直不收录,别反复推,推第三次的时候抓取端大概率已经在降权处理这个 URL 了。正确做法是回到第 4 节,重新过一遍预审。

4. 质量预审:推送之前先自己当一次审核

4.1 内容层预审:把“薄”和“同质”提前剔掉

内容预审这一步,很多人以为是在数段落字数,其实完全不是。判定标准从来不是“够不够长”,而是“有没有信息增量”。一篇八百字但全是常识复述的文章,价值远不如一篇三百字但给出了具体参数和踩坑记录的文章。

我判断“薄页面”的几个信号:全文没有一处具体数字、没有一张自己拍的图或自己画的表、所有观点都能在其他十个站点找到一模一样的表述、标题里堆了三个以上形容词但正文没展开。命中两条以上,这个页面就先别推。

“同质”是另一个大头。典型场景是电商站的筛选组合页——品牌+品类+价格区间能组合出上万个 URL,每个页面的正文只有商品列表,文案一模一样。这类页面要么做参数化屏蔽(只让抓主筛选维度),要么老老实实给每个组合写差异化的说明文案。我见过一个站靠给三百个筛选页各写两百字真实使用建议,把收录率从个位数拉到了七成以上,投入产出比相当高。

还有一种情况是聚合页和详情页抢位置。列表页把详情页的全文都输出了,详情页反而没内容可给。处理方式是列表页只输出摘要加链接,把完整内容留给详情页,各自的定位要清晰。

心得:预审的时候我会问自己一句——“如果我是搜索的人,看到这个页面会失望吗”。这个主观判断比任何工具打分都准。失望的页面,推上去也是浪费。

4.2 技术层预审:首屏、状态码、移动端与死链

技术层预审是可以用工具批量做的,但人工抽检不能省。四项重点。

首屏渲染。用浏览器开发者工具的网络面板,限制成慢速网络再刷新,看正文什么时候出现。如果正文要等三四个接口串行返回才渲染,抓取端很可能只看到一个骨架屏。改造方向是把正文数据内联进 HTML,或者做静态化预渲染。

状态码与软 404。软 404 指的是返回 200 但内容是“抱歉,内容已删除”这类空状态页。这种页面一旦被大量抓取,会严重拖累整站的抓取预算。检查方式是搜一下站点里的空状态文案,看命中页面返回的什么状态码,该给 404 的别给 200。

移动端适配。现在抓取端基本以移动端 UA 为主,移动端体验差会直接影响收录。重点看三处:首屏有没有全屏弹窗挡内容、字体大小是否需要缩放才能读、正文区域的宽度是不是超出视口。这几个问题在模板层面改一次就能全站生效,比逐页调效率高得多。

死链。死链分两种,站内链接指向 404 的,和 sitemap 里混进 404 的。前者靠定期跑爬虫扫,后者在生成 sitemap 时做一次状态码过滤就能拦住。处理死链的正确姿势是 301 到最相关的新页面,实在没有相关页面的才返回 410,别一律跳首页——全站死链都跳首页,会被判定成软 404 的变种。

4.3 结构化数据与元信息的六种常见错法

结构化数据这块,错法高度集中。我整理了六种在审计里反复出现的:

错法具体表现后果
标记与正文不符标记了评分 4.9,正文根本没有评分标记被忽略,严重时整站标记降权
时间字段造假每次生成都把发布时间刷成当天时效性判断失真
面包屑断裂最后一级指向当前页但用了 302层级关系解析不出来
必填字段缺失文章类缺作者、缺主图富摘要不展示
重复标记同一页面同时存在 JSON-LD 和微数据两套解析冲突,取其一
多语言标记打架hreflang 和 canonical 指向不同语言版本语言版本互相覆盖

元信息这边,最要命的是标题重复。批量生成的页面如果标题是“产品中心-某某公司”这种模板,几百个页面标题几乎一样,收录端会认为是同一类页面。改造成本其实很低:把页面里最有区分度的信息(型号、地区、具体问题)提到标题前半段就行。

描述标签不用太纠结长度,但别让它自动截取正文前 80 个字——截出来的内容经常是“当前位置:首页 > 产品 >”这种导航文字。要么手写,要么用正文第一段的有效句子。

5. 收录结果回看与异常排查实录

5.1 必须盯住的四个数据面

推送做完不等于工作结束,回看数据才是闭环。我固定看四个面,按重要性排序。

提交量与成功率。这是自己脚本产出的数据,反映推送动作本身健不健康。成功率长期低于 90%,先查 token 和 URL 合法性,别急着怪平台。

抓取频次。资源平台一般会给站点维度的抓取统计。这个数字突然掉一半,八成是服务器扛不住或者大面积返回了错误状态码,这时候推什么都没用,先救服务端。

索引量。索引量增长滞后于抓取量是正常的,但如果抓取量涨了、索引量纹丝不动,说明卡在质量判定这一关,要回去看内容本身。

展现与点击。收录了但零展现,可能是关键词竞争太激烈或者标题没吸引力;有展现没点击,问题在标题和描述。这两个指标和收录是两个层面的事,别混在一起看。

5.2 用访问日志定位抓取问题

平台给的数据是聚合的,要定位到具体页面还得看自己的访问日志。下面这段脚本是我常用的,按 UA 过滤出抓取请求,统计状态码分布和抓取最多的路径。

import re from collections import Counter LINE = re.compile( r'(?P<ip>\S+) \S+ \S+ \[(?P<time>[^\]]+)\] ' r'"(?P<method>[A-Z]+) (?P<path>\S+)[^"]*" ' r'(?P<status>\d{3}) \S+ "[^"]*" "(?P<ua>[^"]*)"' ) def analyze(log_path, bot_kw="spider"): status_cnt = Counter() path_cnt = Counter() with open(log_path, encoding="utf-8", errors="ignore") as f: for line in f: m = LINE.match(line) if not m: continue if bot_kw not in m.group("ua").lower(): continue status_cnt[m.group("status")] += 1 path_cnt[m.group("path")] += 1 return status_cnt, path_cnt.most_common(30) status, top_paths = analyze("/var/log/nginx/access.log") print("状态码分布:", status.most_common()) for p, c in top_paths: print(c, p)

跑完重点看两件事。一是 5xx 占比,超过 1% 就该查服务端了,抓取端遇到大量 5xx 会主动降频。二是抓取最多的路径里有没有不该被抓的——比如筛选参数页、搜索结果页、后台接口,这些占了大量抓取预算,真正的内容页反而轮不上。发现这种情况,用 robots 或者页面上的 nofollow 把预算收回来。

5.3 常见问题速查表

下面这张表是我这几年攒下来的,遇到问题时先照着过一遍,能省不少时间。

现象最可能的原因排查动作
推送成功但长期不收录内容同质或信息量不足抽三篇对比竞品,看有没有独有信息
抓取频次骤降服务端 5xx 增多或响应变慢查日志状态码分布与 P95 响应时间
收录后又消失页面内容大幅改动或变成空状态检查是否误删内容、是否返回软 404
只收录首页和栏目页详情页链接不是真实<a>标签查看渲染后 DOM 里有没有 href
收录量远大于实际页面数URL 参数组合产生大量重复排查筛选参数、分页、排序组合
新站推送全部失败token 未绑定或站点验证过期后台重新做一次归属验证
移动端收录差、PC 端正常移动端首屏被弹窗遮挡或需横向滚动用移动 UA 实际访问抽检
sitemap 提交后无抓取文件超规格或混入大量非 200 URL检查条数、体积、状态码

排查有个通用原则:从最近一次变更往回倒。站点出问题的时间点往往和某次上线、某次模板改版、某次服务器迁移高度重合。先把时间线对齐,能省掉一大半瞎猜。

注意:不要为了“催收录”去反复提交同一个 URL 或者短时间内大幅改动页面标题。这两件事在抓取端看来都是不稳定信号,效果适得其反。

6. 把收录做成流水线:日常维护与长期动作

6.1 上线前十分钟的强制 Checklist

收录问题的根治办法是把它变成发布流程的一部分,而不是出了事再救火。我现在的做法是给内容上线加一道十分钟的强制检查,过不了就不允许发布。这张清单贴在团队文档里,新人照着做就行。

  • 标题是否包含页面独有信息,和站内其他页面不重复
  • 正文是否有至少一处别处找不到的具体信息(数据、案例、操作步骤)
  • 页面返回是否干净的 200,有没有链式跳转
  • 移动端首屏是否被弹窗或浮层遮挡
  • canonical 是否指向自身,且与推送地址完全一致
  • 结构化数据的字段是否和正文一致,尤其是评分、价格、时间
  • 站内是否有至少两个真实<a>链接指向这个页面
  • 页面是否已进入 sitemap,lastmod 是否为本次真实更新时间

这八条全部通过,才允许进入推送队列。看起来繁琐,但跑顺了之后单页耗时不到十分钟,而且能挡掉八成后续的收录问题。清单里我最看重的是第二条和第七条——有独有信息保证质量,有两个站内入口保证被发现,这两条做到,收录基本不会太差。

6.2 月度巡检与掉收录的优先级判断

日常维护之外,我每个月会做一次站点级巡检,重点看四个数:索引量环比变化、抓取频次环比变化、死链数量、以及抓取预算的分配比例(内容页 vs 参数页)。这四个数里任何一个出现 20% 以上的异常波动,就值得单独拉出来查。

掉收录是最容易让人慌的场景,但处理要有优先级。我的判断顺序是:先确认页面本身还在不在(是不是被误删、是不是 404),再确认内容有没有被大改(改标题、改正文主体都算),然后确认是不是站内出现了更强的同质页面(新旧两篇讲同一件事,被合并了),最后才考虑外部因素。前三种情况占了我遇到案例的九成以上,而且都能自己修。

真正需要长期投入的其实是内容结构本身。站点里如果有大量“为了填充而存在”的页面——比如每个城市一个落地页但文案完全相同、每个型号一个详情页但参数从供应商那直接复制——这些页面会持续消耗抓取预算,拉低整体质量评分。我的建议是定期做一次“页面价值盘点”,把三个月零展现、零点击、零站内点击的页面挑出来,要么补内容,要么合并,要么直接下线并 410。下线垃圾页面这个动作,短期内索引量会掉,但中长期抓取预算会回流到真正有价值的页面上,这笔账算得过来。

这套流程跑下来,我经手的几个内容站收录率基本能稳定在七成到八成五之间,剩下的那一两成往往是内容本身确实不够硬。收录这件事没有一劳永逸的开关,它更像持续维护一条管道——管道通畅了,内容才有机会流到该去的地方。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询