起点

92 篇文章,site:cyk.pink 一条结果都没有。

不是排名差,是搜索引擎不知道有这么一个站。查了一下,sitemap、robots、feed 三个地址全是 404,站长平台一个都没提交过。三年里我做完 hexo deploy 就关浏览器。

先看已经有什么

免得重复劳动:

项目 结果
http → https 301
404 页面 真 404
canonical / og / article meta 有
gzip 开
sitemap / robots / feed 全 404
ld+json 无
站点描述 「我是CYK」

前三行是之前折腾 nginx 时顺手做好的,不用再碰。

sitemap 和 feed

npm i hexo-generator-sitemap hexo-generator-feed
sitemap:
path: sitemap.xml
tags: true
categories: true

feed:
type: atom
path: atom.xml
limit: 20

百度专用的 hexo-generator-baidu-sitemap 没装。那个包停在 Hexo 4 时代,装上直接跑不起来,而百度现在也读标准 sitemap。

生成完 225 条 URL。

robots.txt

User-agent: *
Allow: /

Sitemap: https://cyk.pink/sitemap.xml
Sitemap: https://cyk.pink/atom.xml

放在 source/ 根目录,构建时原样复制到站点根。

主题不输出 keywords

在 _config.yml 里配了 keywords,重新构建,页面里搜不到 <meta name="keywords">。翻主题 layout 才确认,Butterfly 压根没写这一行,配了等于没配。

Google 不看 keywords,百度和其他爬虫还读。既然要补,就从已经渲染好的 HTML 里把文章标签抠出来拼:

hexo.extend.filter.register('after_render:html', function (str) {
if (/<meta name="keywords"/.test(str)) return str
const tags = []
const re = /<meta property="article:tag" content="([^"]*)"/g
let m
while ((m = re.exec(str)) !== null) tags.push(m[1])
const kw = tags.length ? tags.join(',') : hexo.config.keywords
return kw ? str.replace('</head>', `<meta name="keywords" content="${kw}">\n</head>`) : str
})

放 scripts/ 目录,hexo 启动时会自动加载。

结构化数据

主题里也没有 ld+json。没有它 Google 不给富摘要。

同一个 filter 接着写,一次输出四个类型:全站 WebSite + Person,文章页再加 BlogPosting 和 BreadcrumbList,用 @graph 串起来。

数据不用问 hexo 内部对象,从渲染好的 HTML 里反解更省事:

const url = pick(html, /<link rel="canonical" href="([^"]+)"/)
const isArticle = /<meta property="og:type" content="article"/.test(html)

两个地方要处理。

JSON.stringify 之后把 < 换成 \u003c。不换的话,文章正文里只要出现一次 </script>,整段脚本就提前闭合,后面全部错位。

整个 filter 包在 try/catch 里。SEO 脚本出问题最多是没加标签,不该让整个站构建失败。

285 个页面,284 个带上了,缺口是 404 页——它没有 canonical,被跳过了。

顺手清一条死链

主题自带一个 404 generator,会生成 /404.html,sitemap 插件把它当普通页面收了进去。但 nginx 里写着 location = /404.html { internal; },外部访问必然 404。

一条不多,但没必要留着。

hexo.extend.filter.register('after_generate', clean)
hexo.extend.filter.register('after_exit', clean)

两个时机都挂,是因为它会和 sitemap 插件抢写入顺序。只挂 after_generate 的时候,加完文章重新生成,那个 /404.html 又被写回去了一次。

结果

sitemap 217 条,全量校验 0 死链,284/285 页有结构化数据。

真正的难点不在这几个配置,在于要先把「我以为的」和「实际缺的」分开——sitemap 和 ld+json 是真缺,其他都是瞎操心。