You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 21:09:51