如何用TypeScript按类别程序化审核页面SEO评分
无头CMS页面上线前自动SEO审核方案
需求概述
- 返回0–100分的综合评分,按元标签、内容、结构、性能分类展示子评分
- 问题按错误(error)、警告(warning)、**信息(info)**分级,便于优先修复
- 基于Node.js服务器端运行,不依赖任何外部API
- 评分低于阈值时可阻断CI/CD部署
现有手动方案的痛点
之前手动检查标题、元描述长度等逻辑,存在维护困难、扩展性差的问题,且无评分体系和结构化输出:
// 手动检查——逻辑不一致且难以维护 const titleLength = title.length; if (titleLength < 50 || titleLength > 60) { console.warn('标题长度不符合要求'); } const descLength = metaDescription.length; if (descLength < 120 || descLength > 158) { console.warn('元描述长度不符合要求'); } // 无评分机制、无结构化输出、无法批量汇总全站问题
期望的实现效果
单页面审核
// 单页面审核 const result = auditPage({ url: 'https://example.com/blog/react-seo', title: 'React SEO指南——2026年最佳实践', metaDescription: '学习如何为搜索引擎优化React应用...', content: '<h1>React SEO指南</h1><p>...</p>', headings: ['h1:React SEO指南', 'h2:SEO的重要性'], images: [{ src: '/hero.webp', alt: 'React SEO示意图' }], focusKeyphrase: 'react seo', wordCount: 1850, }); console.log(result.score); // 84 console.log(result.categories); // { // meta: { score: 90, passed: 9, warnings: 1, errors: 0 }, // content: { score: 82, passed: 7, warnings: 2, errors: 0 }, // structure: { score: 78, ... }, // performance: { score: 85, ... } // } // 仅筛选错误和警告 const issues = result.rules.filter(r => r.severity === 'error' || r.severity === 'warning');
全站审核与CI/CD阻断
const report = auditSite({ pages: allPages }); if (report.score < 75) { process.exit(1); // 阻断部署 }
解决方案实现思路
1. 定义可扩展的SEO规则集
按分类定义规则,每个规则包含检查逻辑、权重、严重级别,方便后续扩展:
const SEORules = { meta: [ { id: 'title-length', name: '标题长度合规', severity: 'warning', weight: 10, check: (page) => page.title.length >= 50 && page.title.length <= 60 }, { id: 'meta-desc-contains-keyphrase', name: '元描述包含核心关键词', severity: 'warning', weight: 10, check: (page) => page.metaDescription.toLowerCase().includes(page.focusKeyphrase.toLowerCase()) } ], content: [ { id: 'keyphrase-density', name: '关键词密度合理', severity: 'warning', weight: 15, check: (page) => { const matchCount = page.content.match(new RegExp(page.focusKeyphrase, 'gi'))?.length || 0; const density = (matchCount / page.wordCount) * 100; return density >= 0.5 && density <= 2; } }, { id: 'image-alt-contains-keyphrase', name: '图片alt文本包含关键词', severity: 'info', weight: 5, check: (page) => page.images.some(img => img.alt.toLowerCase().includes(page.focusKeyphrase.toLowerCase())) } ], structure: [ { id: 'single-h1', name: '页面仅含一个H1标签', severity: 'error', weight: 20, check: (page) => page.headings.filter(h => h.startsWith('h1:')).length === 1 }, { id: 'heading-hierarchy', name: '标题层级无越级', severity: 'warning', weight: 15, check: (page) => { const levels = page.headings.map(h => parseInt(h.split(':')[0].slice(1))); for (let i = 1; i < levels.length; i++) { if (levels[i] > levels[i-1] + 1) return false; } return true; } } ], performance: [ { id: 'image-webp-format', name: '图片使用WebP格式', severity: 'warning', weight: 10, check: (page) => page.images.every(img => img.src.endsWith('.webp')) }, { id: 'url-slug-clean', name: 'URL路径简洁含关键词', severity: 'info', weight: 5, check: (page) => page.url.split('/').pop().includes(page.focusKeyphrase.replace(' ', '-')) } ] };
2. 实现单页面审核函数
遍历规则集,计算分类得分和问题详情:
function auditPage(page) { const categories = {}; const allRules = []; // 遍历每个分类规则计算得分 for (const [category, rules] of Object.entries(SEORules)) { let passed = 0; let warnings = 0; let errors = 0; const totalWeight = rules.reduce((sum, rule) => sum + rule.weight, 0); let scoredWeight = 0; const categoryRules = rules.map(rule => { const passedCheck = rule.check(page); if (passedCheck) { passed++; scoredWeight += rule.weight; } else { rule.severity === 'error' ? errors++ : warnings++; } return { ...rule, passed: passedCheck }; }); allRules.push(...categoryRules); categories[category] = { score: Math.round((scoredWeight / totalWeight) * 100) || 0, passed, warnings, errors }; } // 计算综合得分:按分类权重加权(可根据需求调整) const categoryWeights = { meta: 0.25, content: 0.3, structure: 0.25, performance: 0.2 }; const totalScore = Object.entries(categories).reduce((sum, [cat, data]) => { return sum + (data.score * categoryWeights[cat]); }, 0); return { score: Math.round(totalScore), categories, rules: allRules }; }
3. 实现全站审核函数
汇总所有页面的得分和问题,生成全站报告:
function auditSite({ pages }) { const pageResults = pages.map(page => auditPage(page)); const totalPages = pageResults.length; const averageScore = Math.round(pageResults.reduce((sum, res) => sum + res.score, 0) / totalPages); // 汇总全站错误、警告总数 const totalErrors = pageResults.reduce((sum, res) => { return sum + Object.values(res.categories).reduce((catSum, cat) => catSum + cat.errors, 0); }, 0); const totalWarnings = pageResults.reduce((sum, res) => { return sum + Object.values(res.categories).reduce((catSum, cat) => catSum + cat.warnings, 0); }, 0); return { score: averageScore, totalPages, totalErrors, totalWarnings, pageResults }; }
4. CI/CD集成
在CI/CD脚本中调用全站审核,根据得分判断是否阻断部署:
// 从无头CMS获取待上线页面数据 const allPages = await fetchPagesFromHeadlessCMS(); const report = auditSite({ pages: allPages }); console.log(`全站SEO综合评分: ${report.score}`); console.log(`总计错误: ${report.totalErrors}, 总计警告: ${report.totalWarnings}`); if (report.score < 75) { console.error('SEO评分低于阈值,阻断部署'); process.exit(1); } else { console.log('SEO审核通过,继续部署'); }
内容的提问来源于stack exchange,提问作者Al Amin
相关产品推荐
相关产品推荐

