← 返回

本站 SEO 优化介绍

复制为 Markdown

大概是在今年的 5 月份左右,我将自己的博客网站全部换成了自己写的 vue + spring 技术栈,替代原先的 Pada Wiki 等开源的博客站点。辛辛苦苦做样式,参考很多博客网站的 UI 交互,甚至还加上了很多 AI 功能,并且将自己原先在其他博客上的很多高访问量的文章都搬了过来。满心期待地希望大家访问一下我自己的亲手做的博客网站,但是显示很骨感,网站上线将近半个月,后台监控显示外部流量打开的数字是 0 。

意识到别人想要访问我的网站,首先是要能在搜索引擎(Google、Bing 等)上能够搜索看见我的文章。这一部分就涉及到 SEO 改造的内容,是我之前没接触过的。

SEO(Search Engine Optimization,搜索引擎优化),指通过优化网站内容、结构和技术,提升其在搜索引擎自然排名中的可见度,从而吸引更多精准流量。核心包括关键词研究、优质内容创作、页面优化及外链建设,旨在符合搜索算法与用户需求。

本文章记录了我当前这个站点 SEO 改造的全流程。

搜索引擎的工作原理

image.png

  1. 发现链接。 搜索引擎有一只"爬虫"(Google 的叫 Googlebot,Bing 的叫 Bingbot),它天天在网上逛,靠三种方式发现新页面:读你的 sitemap.xml、从别的网站点过来的外链、以及你网站内部的 <a> 标签链接。
  2. 抓取页面。 爬虫发现链接后,会像一个普通浏览器一样发 HTTP 请求,把 HTML 源码下载下来。
  3. 渲染解析。 这一步是 SPA 的命门。Google 的爬虫理论上能执行 JavaScript,但它不会每个页面都执行(太贵了),而且执行时机不确定,可能几天后才来跑你的 JS。Bing 的能力更弱一些。
  4. 建立索引。 搜索引擎从抓到的内容里提取标题、描述、正文、图片等信息,存进自己的索引库。
  5. 排名展示。 用户搜索时,从索引库里按相关性和质量排序,展示结果。

下面可以根据搜索引擎的工作原理来逐一优化我们的网站接口。

补齐搜索引擎爬虫需要的必要文件(sitemap.xml 、robots.txt)

通过上面的原理介绍,要想让搜索引擎的爬虫能看见我的网站,首先是得有一个 sitemap.xml 文件在网站根目录下可以直接访问。比如本站的 sitemap.xml 链接:https://blogs.hlt.cab/sitemap.xml ,显示的内容大概如下:

image.png

sitemap.xml 文件中需要记录网站所有的超链接以及可以跳转的多语言链接等,由于本站是博客网站,所以需要记录所有博客文章对应的链接。

除了 sitemap.xml 文件以外,网站根目录下面应该还有一个 robots.txt 文件,告诉搜索引擎本站的 sitemap 在哪里,以及本站的内容哪些可以爬,哪些不能爬(君子协定)。本站的 robots.txt 链接 https://blogs.hlt.cab/robots.txt 访问大概是这个内容。

image.png

技术角度,因为是博客网站的缘故,sitemap.xml 需要是动态的,不可能说每次发布一篇新的文章,sitemap.xml 也得跟着改一遍。

希望它是动态的,所以最好还是由前端做成一个接口,每次请求都从后端文章列表里面实时生成 sitemap:

typescript
// nuxt.config.ts
sitemap: {
  siteUrl: 'https://blogs.hlt.cab',
  sources: ['/api/__sitemap__/urls'],   // 指向下面这个服务端接口
  exclude: ['/login', '/chat', '/admin', '/admin/**']
}
typescript
// src/server/api/__sitemap__/urls.ts
// 每次爬虫请求 sitemap.xml 时,实时从后端拉最新文章列表生成
const res = await $fetch('/post/list', {
  baseURL: getApiBase(),
  query: { page: 1, size: 1000, status: 1 }  // status=1 只取已发布
})

const postUrls = list.map((item) => ({
  loc: getPostPath(item),
  changefreq: 'weekly',
  priority: 0.8,
  lastmod: item.updateTime || item.createTime
}))

这样发布新文章之后,数据库里面有更新,sitemap 就可以跟着更新,不必每次都改。

对应地,robots.txt 文件也改成由服务端输出(根据后端拦截器原则来):

typescirpt
// src/server/routes/robots.txt.ts
export default defineEventHandler((event) => {
  const text = [
    'User-agent: *',
    'Allow: /post/',
    'Disallow: /api/',
    'Disallow: /admin/',
    'Disallow: /login/',
    'Disallow: /chat/',
    `Sitemap: ${getSiteUrl()}/sitemap.xml`
  ].join('
')

  setHeader(event, 'Content-Type', 'text/plain; charset=UTF-8')
  return text
})

确保 /sitemap.xml/robots.txt 两个路由在公网上可以访问之后,还需要去对应搜索引擎的控制台注册一下我们的 sitemap 。

这里的路由地址不是固定的,也可以换成别的,在搜索引擎控制台上注册的时候对应地配置即可。

对应的控制台需要先验证域名归属权限,一半是在域名解析上新增一个解析就可以,这里不再赘述。

以 GÇS 为例,验证完域名归属,在对应的域名下面配置 sitemap

image.png

等待几个工作日,基本上就可以在 Google 上凭借关键词搜索到自己的网站了。

一个简单的验证方法是直接在 Google/Bing 的输入框里面输入 site:xx.com ,表示搜索你自己域名下面的内容。

image.png

到这一步,能搜到自己网站上的内容,基本上就说明 sitemap 等配置成功了。

重构网站的渲染模式

这一步算是我自己踩的一个坑,也是对应上面搜索引擎原理的第 2 步和第 3 步。

最开始我们写网站前端的时候都习惯 CSR ,将前端大部分的渲染工作都交给客户端/前端去渲染。但是这样做对搜索引擎非常不友好,因为搜索引擎在爬取站点的时候希望能直接拿到网站的 meta 数据等 html 信息,CSR 的话,对应的页面样式是先渲染,然后再去请求后端的文件信息。这会导致搜索引擎爬虫在爬取的时候拿到的网页数据都是空的。严重的话会造成搜索引擎直接不收录我们的网站。

所以,将网站的页面,尤其是文章详情列表的页面,重构成 SSR (服务端渲染)是很有必要的。服务器收到请求时,先在服务端把数据填进 HTML 再返回,爬虫拿到的第一口 HTML 就是完整的。

typescript
useSeoMeta({
  title: () => pageTitle.value,
  description: () => pageDescription.value,
  ogTitle: () => pageTitle.value,
  ogDescription: () => pageDescription.value,
  ogType: () => post.value ? 'article' : 'website',
  ogUrl: () => canonicalUrl.value,
  ogImage: () => post.value?.coverImage || undefined,
  twitterCard: () => post.value?.coverImage ? 'summary_large_image' : 'summary',
  // 文章不存在时返回 noindex,正常时允许收录
  robots: () => notFound.value ? 'noindex, nofollow' : 'index, follow'
})

useHead(() => ({
  link: [{ rel: 'canonical', href: canonicalUrl.value }],
  script: articleJsonLd.value ? [{
    type: 'application/ld+json',
    textContent: JSON.stringify(articleJsonLd.value)
  }] : []
}))

上文提到的 sitemap.xmlrobots.txt 俩文件动态生成,也可以算成这一部分的工作。内容和渲染有服务端一起处理,确保爬虫一次就能拿到全部的数据。

网站的渲染有问题的话,其实搜索引擎的控制台会提示我们的。比如在 Google 的 GCS 上 “安全处理和人工处置措施” 部分会提示网站在安全和收录方面存在的问题,Bing 的 webmaster 上在域名首页会用横幅展示网站收录的优化建议。对照其逐一更改,对网站的收录性能会有不小的帮助。

补充一些 SEO 重构的细节

1、可以给文章的页面路由加上一个 slug,方便搜索引擎理解。

原先的文章页面路由比较简单,比如第 1 篇文章,那路由就是 post/1,加一个 slug 的意思是可以在后面再拼接一个能大致表示文章标题的字符串,比如我当前站点的一篇文章地址:https://blogs.hlt.cab/post/23/ji-lu-yi-xia-wo-zai-kai-fa-a-g-e-n-t-shi-cai-dao-de-keng ,后面的 /ji-lu-yi-xia-wo-zai-kai-fa-a-g-e-n-t-shi-cai-dao-de-ken 就是把文章标题转换成 slug 拼接的结果。在后端,有一些框架可以专门做这些事情。

2、加上 /feed.xml 路由。

feed.xml 是一份标准 RSS 2.0 XML。

RSS 对 SEO 是间接帮助:订阅工具和内容聚合平台会通过 RSS 发现你的新文章,多一个被发现的渠道,也可能带来外链。实现就是一个服务端路由,把文章列表拼成 XML 返回。

本站的 feed.xml 链接 https://blogs.hlt.cab/feed.xml 大概长这样:

image.png

3、slug 不一致时 301 永久重定向。

slug 虽说有便于搜索引擎理解,但是有时候过长或者内容复杂容易被阶段或者是二次编码什么的,不能单纯地因为 slug 文案不对就拒绝用户访问文章。

所以可以在 slug 不一致时将用户页面重定向到当前的文章页面(slug 前面一般还是会加一个文章 id 的参数)。

typescript
if (post.value?.slug && route.params.slug !== post.value.slug) {
  await navigateTo(postLink(post.value), {
    redirectCode: 301,   // 永久重定向,把权重转移到规范地址
    replace: true
  })
}

4、sitemap 上的数据,尤其是时间数据,尽量用真实的。

sitemap.xml 文件中的时间参数比如 Last Updated 这种会影响搜索引擎爬取的频率,更新越频繁的站点搜索引擎爬取也会越频繁。所以有的人会考虑把这个参数永久设置为当前的时间。

这样不好,长期这样下去会影响 sitemap 上的参数在搜索引擎那边的可信度,对后续新增的页面会有影响,严重的话甚至会降权、降低排序。


大致是这么些,最后附上我的网站 SEO 改造的步骤图,希望对读者有帮助。

image.png

最热文章