← 返回蜂巢洞察

如何发现并解决网站中常见的技术性SEO问题

假设你已经建立了一个网站,你在设计上投入了大量精力,也购买了域名等等。但一个网站并不仅仅是指你在屏幕上看到的内容,实际上在幕后还有很多复杂的运作过程。你必须了解互联网的运行机制,以及搜索引擎优化(SEO)的工作原理。 速度也是其中非常重要的一个因素。如果一个网站的加载速度很慢,那么它的SEO效果就很可能不佳,因为现在大多数人都不会愿意花费太多时间等待页面加载完成。 网站的速度是一个广为人知的话题,而且其中也涉及到许多需要考虑的因素,比如“最大内容绘制时间”(LCP)、“累积布局偏移量”(CLS)以及服务器速度等等。不过这些内容我会在另一篇文章中详细讨论。 这篇文章主要探讨的是那些会阻碍搜索引擎

假设你已经建立了一个网站,你在设计上投入了大量精力,也购买了域名等等。但一个网站并不仅仅是指你在屏幕上看到的内容,实际上在幕后还有很多复杂的运作过程。你必须了解互联网的运行机制,以及搜索引擎优化(SEO)的工作原理。

速度也是其中非常重要的一个因素。如果一个网站的加载速度很慢,那么它的SEO效果就很可能不佳,因为现在大多数人都不会愿意花费太多时间等待页面加载完成。

网站的速度是一个广为人知的话题,而且其中也涉及到许多需要考虑的因素,比如“最大内容绘制时间”(LCP)、“累积布局偏移量”(CLS)以及服务器速度等等。不过这些内容我会在另一篇文章中详细讨论。

这篇文章主要探讨的是那些会阻碍搜索引擎访问和读取你网站页面的问题。

在我看来,技术性SEO要比常规的SEO更难实施。常规SEO主要关注内容和关键词,而技术性SEO通常需要开发者具备相关知识,而且可能需要对网站代码进行一些修改。如果你没有技术背景,这些修改过程可能会让你感到有些棘手。

某些技术性问题可能会在数月之内都被人们忽略,因为它们通常不会被直接看到。这些问题不属于设计方面的问题,只有通过特定的检测工具,比如Google PageSpeed Insights,才能发现它们。

在这个教程中,你将会在一个小型练习网站上找到并解决那些最常见的技术性问题。我并没有选择使用真实的网站来进行测试,以免让这些网站的主人感到不便,因此我专门建立了一个已经存在各种问题的练习网站。

目录

先决条件

你不需要是经验丰富的程序员才能跟随这些步骤进行学习。你需要准备以下工具:

  • 一个网页浏览器,比如Chrome、Firefox、Edge或Safari。在Safari中,请先进入“设置”>“高级设置”,然后开启“显示Web开发者功能”。
  • 一个终端程序:macOS系统中使用Terminal,Windows系统中使用PowerShell,Linux系统中则可以使用任意终端程序。
  • curl,这是一个用于下载网页的小程序。它预装在macOS、大多数Linux发行版中,同时也适用于Windows 10(1803版本及后续版本)和Windows 11系统。
  • Node.js,用于运行练习网站中的代码。这些代码已经使用Node.js 26.8和curl 8.7进行了测试。

在Windows系统中使用PowerShell时,请输入curl.exe而不是curl,因为在那里curl实际上是一个指向其他命令的快捷方式。同时,请将| grep -i "text"替换为| Select-String "text",并将/dev/null替换为NUL。

什么是技术性SEO?

谷歌拥有名为“爬虫”的程序,它们会持续在互联网上搜索新的网站和页面。当谷歌发现一个新的网页地址时,它会对这些页面进行抓取,并分析其中的内容(包括文本、图片和视频)。

如果谷歌认为某个页面值得被收录到索引中,它就会将该页面添加到一个庞大的网页数据库中。之后,在用户进行搜索时,谷歌会从这个索引中筛选出相关的页面作为搜索结果展示给用户。谷歌在关于搜索原理的说明中将这三个步骤称为“抓取”、“索引”和“呈现结果”。

因此,仅仅完成抓取步骤并不能保证页面会被收录到索引中,而被收录到索引中也并不一定能确保该页面会出现在搜索结果中。同样的指南还指出,即使某个网站完全遵守了谷歌的所有规定,谷歌也不能保证这三个步骤都能顺利完成。

解决技术性问题并不一定能让你的网站在谷歌搜索结果中排在第一位,但这些问题得到解决确实会增加你的网站获得更高排名的可能性,因为每一个被修复的问题都会让你的网站变得更好。

技术性SEO必须与常规的SEO策略相结合,比如关键词优化、外部链接建设、社交媒体互动等。

这些问题在真实的网站上有多常见?

以下数据是我使用自己开发的网站审计工具进行审计后得出的结果。每个网站只被计算一次,数据统计时间截至10月25日。

“抓取测试”会检查一个网站中的多个页面(这里平均检查10个页面),而“单页审计”则只会检查一个页面,通常是首页。

>
问题类型 出现频率样本数量
至少有一个页面没有设置规范标签 64.2%的网站 53个被审计的网站,时间跨度为2025年8月至2026年10月
有两个或更多页面的标题完全相同 61.8%的网站 34个被审计的网站中存在这种情况
至少有一个页面没有元描述 49.1%的网站 53个被审计的网站
至少有一个链接指向返回404错误的页面 18.9%的网站 53个被审计的网站
页面主要由JavaScript编写 17.7%的页面 277次单页审计,时间跨度为2026年5月至10月
至少有一个页面没有标题标签 13.2%的网站 53个被审计的网站
存在搜索引擎无法跟随的链接 8.3%的页面 278次单页审计
robots.txt文件存在错误,或者无法正常加载 7.9%的网站 252次单页审计,时间跨度为2026年7月至10月
页面被noindex指令或robots.txt文件禁止被索引 4.8%的页面 251次单页审计,时间跨度为2026年7月至10月

这些都是技术上的问题,但它们的重要性并不相同。缺失规范标签的问题最为严重,不过谷歌其实并不要求必须使用规范标签,因此没有这种标签的页面并不会导致搜索排名出现问题。然而,当同一内容或非常相似的内容可以通过多个URL访问时,这个问题就会变得很重要了——这一点在关于规范标签的部分会有详细说明。

重复标题也是我曾经遇到过的问题:在编写代码时,很容易忽略这类细节。正因为如此,才有了专门用于检测这些问题的工具。

让我们一起来逐一看看这些问题,确保大家都能理解它们:

  • 缺失规范标签:规范标签其实是你在HTML的〈head〉标签中添加的各种标签之一。当两个或三个页面的内容几乎相同时,规范标签可以帮助搜索引擎(比如谷歌)判断哪个URL是原始版本、主要版本,也就是你希望被收录的版本。不过,使用规范标签并不是强制性的;如果没有这个标签,谷歌也会自行选择主要版本。因此,这种标签主要适用于那些存在重复内容的页面。
  • 重复标题:很容易就会出现两个页面拥有相同的标题的情况。重复标题是不应该出现的,因为这既没有帮助,还可能让谷歌感到困惑。每个页面都应该清楚地说明自己所介绍的内容。
  • 缺失元描述:元描述非常重要,因为它不仅能帮助搜索引擎,还能辅助像ChatGPT这样的AI工具理解页面内容。元描述的作用是简要说明页面的主题和用途。如果你在谷歌上搜索某个网站,就会在链接下方看到它的元描述。
  • 指向404错误页面的链接:这意味着你设置了一个失效的链接,这个链接会引导用户访问一个根本不存在的页面。因此,这样的链接应该被修改为指向类似内容或确实存在的页面,这样才能保证链接的有效性。
  • 主要使用JavaScript构建的页面:谷歌能够执行JavaScript代码,所以仅仅因为页面使用了JavaScript,并不会导致它无法被谷歌收录。但是,只有当JavaScript代码加载并运行完成后,页面内容才会显示出来,而这个过程可能会消耗更多时间,也有可能出现错误。此外,并不是所有的搜索引擎爬虫都能执行JavaScript代码。因此,对于那些最重要的页面,我更倾向于使用〈a href="https://www.freecodecamp.org/news/server-side-rendering-in-next-js-for-improved-seo/">服务器端渲染技术。
  • 搜索引擎无法跟随的链接:这个问题并不是特别严重,其影响主要取决于链接的目标页面。不过,如果你写了一篇很好的文章,并希望它能够帮助你在谷歌上获得好的排名,但如果搜索引擎无法跟随这个链接访问该文章,那么你为这篇文章投入的所有时间和精力可能就会白费了,因为很少有人会看到这篇文章。
  • robots.txt文件中的错误:robots.txt文件的作用是帮助你向搜索引擎传达一些指令。如果这个文件中存在错误,就可能会阻止搜索引擎爬取那些你希望被收录在搜索结果中的页面。
  • 被“noindex”或robots.txt文件阻止被收录的页面:这两者其实是不同的概念。“noindex”规则是要求搜索引擎不要将某个页面纳入搜索结果,而robots.txt文件则只是阻止搜索引擎爬取该页面而已。关于这两者的区别以及它们为何重要,你将在本教程的后半部分学到更多内容。

那些属于“软404错误”、重定向链问题以及错误的规范标签并没有被记录在表格中,因为审计流程并不会检测这些问题。

如何搭建测试网站

这个测试网站是一个专为虚构的“Acme Shoes”鞋店设计的简单网站。该网站的每个页面都包含一些预设的技术性SEO问题,但你并不需要了解其中每一行代码的具体含义。

创建一个新文件夹,添加一个名为server.js的文件,然后将以下代码粘贴到其中:

// server.js:一个包含常见技术性SEO问题的简单测试网站
const http = require('node:http');

const PORT = 8080;
const BASE = 'http://localhost:' + PORT;

// 创建一个简单的HTML页面。如果某个字段被省略了,相应的标签也会被忽略。
function page({ title, description, canonical, robots, body, script }) {
  return [
    '<!doctype html>',
    '<html lang="en">',
    '<head>",
    '<meta charset="utf-8">',
    title && '<title>' + title + '</title>',
    description && '<meta name="description" content="' + description + '">',
    canonical && '<link rel="canonical" href="' + BASE + canonical + '">',
    robots && '<meta name="robots" content="' + robots + '">',
    '</head>",
    '<body>',
    body,
    script && '<script>' + script + '</script>',
    '</body>',
    '</html>',
  ]
    .filter(Boolean)
    .join('\n');
}

const routes = {
  '/': {
    html: page({
      title: 'Acme Shoes:适合所有跑者的跑鞋',
      description: '轻便的公路及越野跑鞋,支持免费退货。",
      canonical: '',
      body: [
        '<h1>Acme Shoes</h1>',
        '<a href="/products/blue-runner">>Blue Runner<./a>',
        '<span onclick="location.href=\\'/sale\'\">夏季促销活动</span>',
      ].join('\n'),
    }),
  },
  // 问题:标题模糊且没有元描述
  '/products/blue-runner': {
    html: page({
      title: 'Acme Shoes',
      canonical: '/products/blue-runner',
      body: '<h1>Blue Runner</h1>',
    }),
  },
  // 问题:页面中缺少产品信息,但响应状态仍为“200 OK”(属于软404错误)
  '/products/red-runner': {
    html: page({
      title: 'Acme Shoes',
      body: '<h1>很抱歉,该商品无法找到。 /sale-2025 -> /sale
  '/old-sale': { redirect: '/sale-2025' },
  '/sale-2025': { redirect: '/sale' },
  '/sale': {
    html: page({
      title: '夏季促销:跑鞋最高优惠40% | Acme Shoes',
      description: "在8月31日之前,购买上一季的跑鞋可享受最高40%的折扣。",
      canonical: '/sale',
      body: '<h1>夏季促销活动</h1>',
    }),
  },
  // 问题:页面中设置了“noindex”头信息,但用户根本看不到
  '/about': {
    headers: { 'X-Robots-Tag': 'noindex' },
    html: page({
      title: '关于Acme Shoes',
      description: "一个由两个人组成的工作室是如何发展成一家跑鞋品牌的。",
      canonical: '/about',
      body: '<h1>关于我们</h1>',
    }),
  },
  // 问题:使用的规范标签指向的是首页
  '/blog/choosing-trail-shoes': {
    html: page({
      title: '如何选择越野跑鞋 | Acme Shoes',
      description: "抓地力、重量和舒适度:挑选越野跑鞋时需要注意的因素。",
      canonical: '',
      body: '<h1>如何选择越野跑鞋</h1>',
    }),
  },
  // 问题:只有在JavaScript代码执行完成后,内容才会显示出来
  '/catalog': {
    html: page({
      title: '所有跑鞋产品 | Acme Shoes',
      description: "浏览Acme品牌的所有跑鞋系列。",
      canonical: '/catalog',
      body: '<div id="app">>正在加载中…</div>',
      script:
        "fetch('/api/products').then((r) => r.json()).then((products) => {
          "document.getElementById('app').innerHTML = products.map((p) => '<h2>&' + p + '</h2>&'.join('');"
        });
      },
    }),
  },
  '/api/products': {
    type: 'application/json',
    html: JSON.stringify(['Blue Runner', 'Trail Grip 2', 'City Glide'],
  },
  // 问题:"Disallow: /blog"这条规则会阻止所有以/blog开头的路径被访问
  '/robots.txt': {
    type: 'text/plain',
    html: 'User-agent: *\nDisallow: /blog\n',
  },
};

http
  .createServer((req, res) => {
    const path = new URL(req.url, BASE).pathname;
    const route = routes[path];

    if (!route) {
      res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
      return res.end(page({ title: '页面未找到', body: '<h1>页面未找到</h1>' }));
    }
    if (route.redirect) {
      res.writeHead(301, { Location: routeredirect });
      return res.end();
    }
    res.writeHead(200, {
      'Content-Type': (route.type || 'text/html') + '; charset=utf-8',
      ...route.headers,
    });
    res.end(route.html);
  })
  .listen(PORT, () => console.log('测试网站已启动,地址为 ' + BASE));
routes 中的每个键都代表一个页面地址。那些以 “Problem:” 开头的注释说明了各个页面存在哪些问题。

请从同一个文件夹中启动服务器:

node server.js

你应该会看到如下输出:

练习网站正在运行,地址为 http://localhost:8080

让服务器保持运行状态,然后打开另一个终端来执行下面的命令。当你修改了 server.js 文件后,请使用 Ctrl+C 停止服务器,然后再重新启动它。

如何检查页面的 HTTP 状态码

我记得刚开始构建网站的时候,我会尝试制作各种小功能。作为一名全栈开发者,我总是喜欢不断进行各种实验。

有一次我在服务器端遇到了问题,通过 “网络” 标签页发现系统返回了 500 错误代码;还有一次,我故意删除了一个页面,想看看是否会收到 404 错误或其他异常信息。如果你经常对自己的网站进行各种测试,那么从这些结果中你一定能学到很多东西。

搜索引擎首先会读取 HTTP 状态码。这些状态码其实是服务器与客户端(比如你的浏览器)之间进行通信的方式。状态码被分为五个范围:1xx、2xx、3xx、4xx 和 5xx。其中,5xx 类型的状态码表示服务器端出现了问题,而 4xx 类型的状态码则表示客户端存在问题。

404 是最常见的错误代码,它表示网站中不存在该页面。你会经常遇到 404 错误,而解决这个问题的方法通常就是及时维护你的网站并检查链接是否正确。

在本教程中会遇到的一些常见的 HTTP 状态码包括:

  • 200 OK:页面已经成功加载。
  • 301 Moved Permanently:该页面已移动到其他地址。
  • 404 Not Found:该页面不存在。

根据谷歌的相关文档,如果一个 URL 返回的是 4xx 状态码,那么谷歌不会对该页面进行索引。

要想查看练习网站首页的 HTTP 状态码,可以使用 -I 选项来仅显示响应头信息,同时使用 -s 选项来隐藏 curl 的进度条:

curl -sI http://localhost:8080/
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

现在,试着访问一个不在 routes 中列出的地址,看看正确的 404 错误响应是什么样的:

curl -sI http://localhost:8080/products/does-not-exist
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

在浏览器中,打开开发者工具(按 F12 键,或在 Mac 上按 Cmd+Option+I),然后进入 “网络” 标签页,重新加载页面。此时,“状态” 列会显示相应的 HTTP 状态码。

什么是“软404错误”?

测试一下商店中已不再出售的商品:

curl -sI http://localhost:8080/products/red-runner
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

在浏览器中,会看到这样的提示:“抱歉,该商品无法找到。”

“软404错误”本质上就是“页面未找到”,但服务器仍然会返回200状态码。这种情况会让谷歌感到困惑,因为地址依然存在,但页面内容已经过时了。

为了解决这个问题,应该让这些不存在的页面真正返回404状态码,这也是谷歌所推荐的。在测试环境中,可以将'/products/red-runner'这条链接从routes配置文件中删除,这样服务器就会返回404状态码。

失效的链接也会导致同样的问题。在我们的测试数据中,53个被爬取的网站中有18.9%的网站至少包含一个会返回404状态码的链接。

因此,请不要留下那些指向不存在内容的链接。应该将它们更新为指向类似内容或确实存在的内容。

如果某个页面的位置发生了变化,就需要在旧地址和新地址之间设置301重定向规则。只有当页面真的已经消失时,才应该使用404状态码。

如何查找并修复重定向链

重定向的本质就是将一个URL链接指向另一个URL链接。例如,当你将域名从example-x.com更改为example-y.com时,就需要设置重定向规则,这样所有输入example-x.com的访问者都会被自动重定向到example-y.com。

正确使用重定向规则是非常有用的。301状态码表示页面已经永久性迁移;而302状态码则表示迁移是暂时的。谷歌在重定向规则说明中详细解释了如何处理这些不同的情况,而且它的爬虫会跟踪最多10次重定向操作。

但是,当一个旧地址(比如你之前使用过的域名)首先重定向到一个新地址,而这个新地址又继续进行其他重定向时,就会形成所谓的“重定向链”。少量的重定向并不会造成太大问题,但如果有五次、六次甚至七次重定向,那就真的会带来麻烦了。

curl -sIL http://localhost:8080/old-sale
HTTP/1.1 301 Permanent Move
Location: /sale-2025
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

HTTP/1.1 301 Permanent Move
Location: /sale
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

下面的第一个命令会显示整个重定向链的每一个步骤,而第二个命令则能提供简短的总结。

curl -sIL -L http://localhost:8080/old-sale
HTTP/1.1 301 Permanent Move
Location: /sale-2025
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

HTTP/1.1 301 Permanent Move
Location: /sale
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Date: Sun, 25 Oct 2026 17:42:53 GMT
Connection: keep-alive
Keep-Alive: timeout=5
/old-sale 会指向 /sale-2025,而 /sale-2025 又会指向 /sale。以下是一个简短的示例:
curl -sL -o /dev/null -w "%{num_redirects} 重定向操作,最终指向 %{url_effective}\n" http://localhost:8080/old-sale
输出结果: 2 重定向操作,最终指向 http://localhost:8080/sale -o /dev/null 这个选项告诉 curl 不要将页面的 HTML 内容显示在终端中,因此只会打印出总结信息。-w 用于指定总结信息的格式。 要解决这个问题,只需将旧地址直接指向目标页面即可: '/old-sale': { redirect: '/sale' }, 重新启动服务器后再次运行测试,此时输出结果应为 “1 重定向操作,最终指向 http://localhost:8080/sale”。

如何确保 robots.txt 不会阻止重要页面被索引

robots.txt 文件用于告诉谷歌等搜索引擎哪些内容可以被访问、哪些路径不能被爬取。 让我们看一下示例网站中的 robots.txt 文件: curl -s http://localhost:8080/robots.txt 文件内容: User-agent: * Disallow: /blog “Disallow: /blog” 这条规则非常危险,因为它会阻止爬虫访问所有以 “/blog” 开头的路径。而通常情况下,你的文章才是对网站宣传效果最好的内容。 谷歌的 robots.txt 文档 中也给出了类似的例子:“Disallow: /fish” 这条规则会同时阻止 “/fish.html” 和 “/fishheads” 等页面被访问。 为了解决这个问题,需要确保规则只针对你真正想要禁止的内容进行设置。例如,如果只想阻止某个草稿文件夹被访问,就可以这样写: User-agent: * Disallow: /blog-drafts/ 在示例网站中,需要修改 “/robots.txt” 文件中的 “html” 部分: html: 'User-agent: *\nDisallow: /blog-drafts/\n', 需要注意的是,robots.txt 文件主要控制爬虫的访问行为,并不直接影响页面的索引过程。谷歌明确表示,robots.txt 并不是用来阻止页面被收录到搜索结果中的工具。如果想达到这个目的,应该使用 noindex 标签。 即使某个 URL 被 robots.txt 文件禁止了,只要还有其他页面链接到它,它仍然有可能出现在搜索结果中——只不过这些结果可能不会显示该页面的描述信息。因为谷歌并不会去读取被禁止页面的内容。

如何发现意外设置的 “noindex” 规则

“noindex” 标签用于告诉谷歌不要将某个特定页面收录到索引中。但如果这个规则被错误地应用到了那些你需要让其被索引的页面上,就会造成问题——比如产品页面或首页。 然而,在一些不需要被排名的页面上,或者那些对网站整体内容贡献不大的页面上,使用 “noindex” 标签反而是有益的。例如登录页面、注册页面等。noindex这一指令只有在搜索引擎能够访问该页面并读取到这条规则时才会生效。如果robots.txt文件禁止了某个URL的被爬取,那么Google就不会看到noindex这个指令,该页面仍然可能会出现在搜索结果中。因此,如果你希望某个页面不被Google收录,就应该使用noindex,但同时要确保该页面仍可被搜索引擎访问。

在本次检测的数据中,457个被审核的页面中有11个(占比2.4%)包含了noindex这个robots元标签。有两种方法可以设置这个标签,你需要检查这两种方法是否都已被正确应用。

如何检查robots元标签

第一种方法是在页面的标签中添加相应代码:

<meta name="robots" content="noindex">

你可以通过以下命令在浏览器中查看该页面是否包含这个元标签:

curl -s http://localhost:8080/about | grep -i noindex
在“关于我们”页面上,这条指令不会显示任何结果。你也可以右键点击该页面,选择“查看页面源代码”,然后在其中搜索noindex。

修改这个元标签非常简单,只需将其删除即可,这样搜索引擎就能再次对该页面进行索引了。

你可以在页面的代码或模板中查找这个元标签,也可以在内容管理系统或SEO插件的设置中查看它。在WordPress中,选择“阻止搜索引擎对站点进行索引”这一选项,就可以在所有页面上添加noindex元标签。

如何检查X-Robots-Tag头部信息

第二种方法是通过HTTP头部信息来设置。你可以查看“关于我们”页面的头部信息:

curl -sI http://localhost:8080/about
查询结果会显示如下内容:

HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 X-Robots-Tag: noindex Date: Sun, 25 Oct 2026 17:42:59 GMT Connection: keep-alive Keep-Alive: timeout=5 这个元标签只会出现在响应头部信息中,而不会在“查看页面源代码”时显示出来。在本次检测的数据中,12个被禁止被搜索引擎访问的页面中有5个的HTML代码中并没有noindex元标签;其中2个页面使用了X-Robots-Tag头部信息来禁止被爬取,而另外3个页面则是通过robots.txt文件被阻止被访问的。

在实际操作中,如果你想要修改某个网站的设置,可以直接删除'/about'路径下的headers配置项。而对于真实的网站来说,你需要检查服务器配置、托管服务提供商设置的头部信息,以及任何相关的SEO插件。

如何正确使用规范标签

如果你有多个页面内容大致相同,但并没有足够的区别来区分它们,那么你就需要指定一个主页面。规范标签可以帮助搜索引擎确定哪个页面是主页面。

同一个页面也可能存在于多个地址上:

https://example.com/blog/choosing-trail-shoes
https://example.com/blog/choosing-trail-shoes?utm_source=newsletter
https://www.example.com/blog/choosing-trail-shoes
这三个地址实际上指向的是同一篇文章。其中第一个地址是主页面,也就是你希望Google在搜索结果中显示的页面。因此,这三个地址都应该使用相同的规范标签来指明这个主页面。

<link rel="canonical" href="https://example.com/blog/choosing-trail-shoes">

当谷歌看到?utm_source=newsletter版本中存在这个标签时,它会认为该页面是第一个地址的副本。而主页面上也同样带有这个标签,且这个标签指向的是自身。这种被称为“自引用规范标签”的机制,其作用就是表明“我是主版本”。

谷歌将这种标签视为一种强有力的信号,而非某种指令

不过,你完全可以选择不使用规范标签。谷歌表示,指定规范标签并不是必须的:如果没有设置这种标签,谷歌也会自行选择它认为最适合展示给用户的版本。只有当相同或非常相似的内容可以通过多个URL访问时,设置规范标签才显得有意义——就像上面提到的那三个地址一样。

因此,缺少规范标签本身并不算是一个缺陷。在经过审核的457个页面中,有27.1%的页面并没有设置规范标签。真正重要的是,这些页面是否存在需要设置规范标签的重复内容,比如那些带有跟踪参数的版本。

你可以查看示例网站中关于“徒步鞋”的那篇文章,来验证这一点:

curl -s http://localhost:8080/blog/choosing-trail-shoes | grep -i canonical
<link rel="canonical" href="http://localhost:8080/">

这篇文章说明它的主版本是首页,因此谷歌可能会显示首页而不是这篇文章,或者忽略这个规范标签。

由于这篇文章并不是其他内容的副本,所以它本身就是主版本。要解决这个问题,只需将这篇文章的规范标签指向它自己即可:

canonical: '/blog/choosing-trail-shoes',

如何修复缺失或重复的标题和元描述

一个好的标题或元描述应该长度适中、不会过于冗长,并且能简洁地说明页面的内容。它可以说是页面的精髓,相当于页面的介绍文字。

以Blue Runner产品的页面为例来看:

curl -s http://localhost:8080/products/blue-runner | grep -i -E "<title>|name=\"description\""
<>title>Acme Shoes<>/title>

这个标题并没有说明页面的内容,而且也没有元描述。在PowerShell中,可以使用| Select-String '<title>|name="description"'来检查这类问题。

谷歌关于标题和摘要的指导原则要求,每页都应该有独特且具有描述性的标题和元描述。

在示例网站中,要将'/products/blue-runner'这条记录中的title字段替换为合适的内容,从而解决这个问题:

标题:Blue Runner公路跑鞋 | Acme Shoes,
描述:这款公路跑鞋采用轻质材料制成,鞋底具有缓冲功能,且支持免费退货。

请查看示例网站的首页:

curl -s http://localhost:8080/
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>>Acme Shoes:适合所有跑者的跑鞋
<link rel="canonical" href="http://localhost:8080/">
</head>
<body>
<h1>Acme Shoes
<a href="/products/blue-runner">>Blue Runner
<span onclick="location.href('/sale'">>夏季促销活动
</body>>
</html>

这个页面上的其他内容都没有问题:标题、描述、规范标签以及指向“Blue Runner”产品的链接,这些都是合法的元素,其中也包含了href属性。唯一的问题就是那个“夏季促销活动”的标签。

标签本质上是一种没有语义意义的HTML代码,它本身并不表示任何具体的链接信息。而真正的链接是具有明确含义的:搜索引擎能够识别出它是链接,屏幕阅读器也能理解它的作用。

哪些链接需要被搜索引擎抓取呢?基本上就是你希望让搜索引擎看到的所有内容,比如你销售的产品、发布的文章、开设的课程等等。

谷歌的链接指南指出,只有那些含有href属性的元素,才能被搜索引擎可靠地抓取。

要解决示例网站中的这个问题,只需将那个标签替换成以下代码即可:

'夏季促销活动'

如何判断你的内容是否需要JavaScript才能显示

在采用客户端渲染机制的情况下,JavaScript代码必须先被加载完毕,之后其他内容才会被呈现出来。

JavaScript通常用于生成产品列表、价格信息、评论内容以及菜单等。如果没有JavaScript,客户端渲染的页面往往只会显示“正在加载”之类的提示信息,或者是一个空白的界面。

谷歌确实会解析JavaScript代码,但这个过程发生在后续阶段。具体来说,是在页面渲染队列中等待一段时间之后才进行解析。如果某个脚本执行失败或被阻止,那么渲染后的页面就可能缺少一些内容。

正因为如此,服务器端渲染仍然是一个很好的选择,对于那些至关重要的内容来说,我更倾向于使用服务器端渲染技术。谷歌的JavaScript指南也表达了同样的观点:服务器端渲染能够让网站对用户和搜索引擎来说都运行得更快,而且并不是所有的爬虫程序都能执行JavaScript代码。

在所检测的277个页面中,有17.7%的页面主要是使用JavaScript构建的。这并不意味着谷歌无法对这些页面进行索引,只是说明这些页面的主要内容依赖于JavaScript的正常运行才能显示出来。 在服务器端渲染的情况下,HTML内容会直接发送到浏览器中,只有之后才会执行JavaScript代码来进行渲染。 谷歌能够对这两种方式构建的页面进行索引。它的爬虫会使用最新版本的Chrome来运行JavaScript代码,因此服务器端渲染并不是被收录进谷歌索引的必要条件。 接下来的测试会检查在没有JavaScript运行的情况下,这些页面的重要内容是否仍然可以正常显示。虽然这个测试无法反映谷歌实际看到的内容(因为谷歌会在其自己的环境中运行JavaScript),但它能够显示出在任何JavaScript代码执行之前,所有爬虫都能获取到的信息。 在您的浏览器中打开`http://localhost:8080/catalog`,您会看到三个产品信息。现在使用不支持JavaScript运行的curl工具来下载这个页面的内容: ```bash curl -s http://localhost:8080/catalog | grep -i "trail grip" ``` 这条命令不会输出任何结果,因为服务器发送的HTML代码中并不包含产品名称。在``标签内部,服务器只发送了以下内容: ```html
Loading...
``` 如果不使用curl工具,可以在浏览器中选择“查看页面源代码”。在这个界面中,您会看到“Loading...”以及相关的JavaScript代码,但产品名称仍然不会显示,因为浏览器会在JavaScript代码执行之后才添加这些内容。 在您自己的网站上,可以在源代码中查找该页面中的重要信息。 如果想要了解谷歌是如何渲染这个页面的,可以使用谷歌提供的工具来对实时页面进行测试。在您的网站中,可以通过Search Console中的“URL检查”工具来进行实时测试(先选择“测试实时URL”,然后再选择“查看测试后的页面”),这样就能看到谷歌实际渲染出的HTML代码以及对应的截图。 对于任何公开的网页,Rich Results Test工具也能显示这些网页的渲染结果。谷歌建议同时使用这两种工具来查找与JavaScript相关的问题。不过这两种工具都无法访问`localhost`地址,因此请在您自己的网站上进行测试。 如果您希望产品名称从一开始就出现在HTML代码中,那么就需要在服务器端进行渲染处理。在示例网站中,可以将产品列表添加到`routes`代码之前: ```javascript const products = ['Blue Runner', 'Trail Grip 2', 'City Glide']; ``` 然后把页面中的``和`