Skip to content

内容分析

内容分析仪表板为您的网站内容性能提供全面的洞察,帮助您了解内容趋势、优化用户参与度,并为内容策略制定数据驱动的决策。

概览

内容分析系统自动扫描所有内容文件并生成详细的分析报告,包括:

  • 内容性能: 阅读时间、字数统计和参与度指标
  • 内容分布: 分类、标签和内容类型分析
  • 增长趋势: 随时间变化的内容创建模式
  • SEO 洞察: 关键词使用和优化机会
  • 内容健康度: 缺失的元数据、损坏的链接和优化建议
graph TD
    A[内容文件] --> B[分析引擎]
    B --> C[数据处理]
    C --> D[指标生成]
    D --> E[仪表板显示]

    subgraph "分析组件"
        F[内容扫描器]
        G[元数据提取器]
        H[性能分析器]
        I[趋势计算器]
    end

    B --> F
    F --> G
    G --> H
    H --> I
    I --> D

设置和配置

1. 自动生成

内容分析在构建过程中自动运行:

# 生成分析数据
npm run generate-analysis

# 包含分析的构建
npm run build  # 包含分析生成

2. 手动生成

独立生成分析数据:

# 直接运行分析脚本
node scripts/generate-analysis-data.js

# 详细输出
DEBUG=analysis node scripts/generate-analysis-data.js

3. 配置选项

在 Hugo 配置中配置分析设置:

# config/_default/params.toml
[content_analysis]
enabled = true
include_drafts = false
min_word_count = 100
exclude_patterns = [
  "content/*/archive/**",
  "content/*/deprecated/**"
]

# 分析仪表板设置
[content_analysis.dashboard]
enabled = true
public_access = false
update_frequency = "daily"

仪表板功能

1. 内容概览

关键指标显示:

  • 总页面数: 已发布内容的完整计数
  • 内容类型: 博客、图书、播客的分布
  • 平均阅读时间: 全站阅读时间统计
  • 内容新鲜度: 最近更新与较旧内容的比率

视觉组件:

<!-- Dashboard overview cards -->
<div class="analysis-overview">
  <div class="metric-card">
    <h3>Total Pages</h3>
    <span class="metric-value">{{ .TotalPages }}</span>
    <span class="metric-change">+{{ .GrowthRate }}% this month</span>
  </div>

  <div class="metric-card">
    <h3>Average Reading Time</h3>
    <span class="metric-value">{{ .AvgReadingTime }} min</span>
    <span class="metric-trend">{{ .ReadingTimeTrend }}</span>
  </div>
</div>

2. 内容分布分析

分类性能:

{
  "categories": {
    "技术": {
      "count": 156,
      "percentage": 45.2,
      "avgReadingTime": 8.5,
      "totalWords": 125000
    },
    "云原生": {
      "count": 89,
      "percentage": 25.8,
      "avgReadingTime": 12.3,
      "totalWords": 98000
    }
  }
}

标签云分析:

  • 最受欢迎的标签
  • 标签使用频率
  • 标签关联分析
  • 随时间变化的趋势标签

3. 内容性能指标

阅读时间分析:

const readingTimeAnalysis = {
  distribution: {
    "0-3 min": 45,    // Quick reads
    "3-7 min": 128,   // Standard articles
    "7-15 min": 89,   // In-depth articles
    "15+ min": 23     // Long-form content
  },
  averageByType: {
    "blog": 6.8,
    "book": 15.2,
    "podcast": 25.5
  },
  trends: {
    "increasing": ["technical tutorials", "case studies"],
    "decreasing": ["news updates", "quick tips"]
  }
};

字数统计:

  • 平均每篇文章字数
  • 字数分布
  • 内容深度分析
  • 最佳长度建议

4. 增长趋势分析

内容创作模式:

graph LR
    A[2023] --> B[2024]
    B --> C[2025]

    subgraph "Content Growth"
        D[Blog Posts: 45 → 89 → 156]
        E[Books: 3 → 5 → 8]
        F[Podcasts: 0 → 12 → 25]
    end

季节性趋势:

  • 峰值发布月份
  • 内容类型季节性
  • 参与度模式分析
  • 发布频率优化

5. SEO 和优化洞察

SEO 健康检查:

{
  "seo_analysis": {
    "missing_descriptions": 12,
    "short_titles": 8,
    "missing_images": 15,
    "duplicate_titles": 2,
    "optimization_score": 87.5
  },
  "recommendations": [
    "Add meta descriptions to 12 pages",
    "Optimize 8 titles for better SEO",
    "Add featured images to 15 posts"
  ]
}

内容差距分析:

  • 未充分代表的主题
  • 关键词机会
  • 内容系列建议
  • 交叉链接机会

数据收集过程

1. 内容扫描

分析引擎扫描所有内容文件:

// Content scanning process
const scanContent = async () => {
  const contentFiles = await glob('content/**/*.md');
  const pages = [];

  for (const file of contentFiles) {
    const content = fs.readFileSync(file, 'utf8');
    const { data: frontMatter, content: body } = matter(content);

    const analysis = {
      path: file,
      title: frontMatter.title,
      date: frontMatter.date,
      categories: frontMatter.categories || [],
      tags: frontMatter.tags || [],
      wordCount: countWords(body),
      readingTime: calculateReadingTime(body),
      images: extractImages(body),
      links: extractLinks(body),
      headings: extractHeadings(body)
    };

    pages.push(analysis);
  }

  return pages;
};

2. 指标计算

阅读时间计算:

const calculateReadingTime = (content) => {
  const wordsPerMinute = 200; // Average reading speed
  const words = countWords(content);
  const readingTime = Math.ceil(words / wordsPerMinute);

  return {
    words,
    minutes: readingTime,
    display: readingTime === 1 ? '1 minute' : `${readingTime} minutes`
  };
};

内容质量评分:

const calculateQualityScore = (page) => {
  let score = 100;

  // Deduct points for missing elements
  if (!page.description) score -= 10;
  if (!page.image) score -= 5;
  if (page.wordCount < 300) score -= 15;
  if (page.tags.length === 0) score -= 5;
  if (page.categories.length === 0) score -= 5;

  // Bonus points for good practices
  if (page.wordCount > 1000) score += 5;
  if (page.images.length > 2) score += 3;
  if (page.headings.length > 3) score += 2;

  return Math.max(0, Math.min(100, score));
};

3. 数据存储

分析数据以结构化 JSON 格式存储:

{
  "generated_at": "2025-01-16T10:00:00Z",
  "total_pages": 345,
  "summary": {
    "content_types": {
      "blog": 234,
      "book": 89,
      "podcast": 22
    },
    "total_words": 456789,
    "average_reading_time": 7.8,
    "content_health_score": 87.5
  },
  "trends": {
    "monthly_growth": [
      {"month": "2024-12", "posts": 15},
      {"month": "2025-01", "posts": 18}
    ],
    "popular_categories": [
      {"name": "技术", "count": 156, "growth": 12.5},
      {"name": "云原生", "count": 89, "growth": 8.3}
    ]
  },
  "pages": [
    {
      "path": "content/zh/blog/my-post.md",
      "title": "My Blog Post",
      "url": "/blog/my-post/",
      "date": "2025-01-15",
      "word_count": 1250,
      "reading_time": 6,
      "quality_score": 92,
      "categories": ["技术"],
      "tags": ["hugo", "web"],
      "seo_score": 85
    }
  ]
}

仪表板实现

1. 前端组件

仪表板布局:

<!-- layouts/analysis/dashboard.html -->
<div class="analysis-dashboard">
  <header class="dashboard-header">
    <h1>Content Analysis Dashboard</h1>
    <div class="last-updated">
      Last updated: {{ .Site.Data.content_analysis.generated_at | dateFormat "January 2, 2006" }}
    </div>
  </header>

  <div class="dashboard-grid">
    {{ partial "analysis/overview-cards.html" . }}
    {{ partial "analysis/content-distribution.html" . }}
    {{ partial "analysis/growth-trends.html" . }}
    {{ partial "analysis/seo-insights.html" . }}
  </div>
</div>

交互式图表:

// Chart.js implementation for trends
const createGrowthChart = (data) => {
  const ctx = document.getElementById('growthChart').getContext('2d');

  new Chart(ctx, {
    type: 'line',
    data: {
      labels: data.months,
      datasets: [{
        label: 'Posts Published',
        data: data.counts,
        borderColor: '#007bff',
        backgroundColor: 'rgba(0, 123, 255, 0.1)',
        tension: 0.4
      }]
    },
    options: {
      responsive: true,
      plugins: {
        title: {
          display: true,
          text: 'Content Growth Over Time'
        }
      },
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  });
};

2. 数据可视化

分类分布饼图:

const createCategoryChart = (categories) => {
  const ctx = document.getElementById('categoryChart').getContext('2d');

  new Chart(ctx, {
    type: 'doughnut',
    data: {
      labels: categories.map(c => c.name),
      datasets: [{
        data: categories.map(c => c.count),
        backgroundColor: [
          '#007bff', '#28a745', '#ffc107',
          '#dc3545', '#6f42c1', '#fd7e14'
        ]
      }]
    },
    options: {
      responsive: true,
      plugins: {
        legend: {
          position: 'bottom'
        }
      }
    }
  });
};

阅读时间分布:

const createReadingTimeChart = (distribution) => {
  const ctx = document.getElementById('readingTimeChart').getContext('2d');

  new Chart(ctx, {
    type: 'bar',
    data: {
      labels: Object.keys(distribution),
      datasets: [{
        label: 'Number of Posts',
        data: Object.values(distribution),
        backgroundColor: 'rgba(0, 123, 255, 0.8)'
      }]
    },
    options: {
      responsive: true,
      plugins: {
        title: {
          display: true,
          text: 'Reading Time Distribution'
        }
      }
    }
  });
};

高级分析

1. 内容性能评分

参与度预测模型:

const calculateEngagementScore = (page) => {
  const factors = {
    readingTime: getReadingTimeScore(page.readingTime),
    wordCount: getWordCountScore(page.wordCount),
    imageCount: getImageScore(page.images.length),
    headingStructure: getHeadingScore(page.headings),
    seoOptimization: getSEOScore(page),
    freshness: getFreshnessScore(page.date)
  };

  const weights = {
    readingTime: 0.2,
    wordCount: 0.15,
    imageCount: 0.1,
    headingStructure: 0.15,
    seoOptimization: 0.25,
    freshness: 0.15
  };

  return Object.keys(factors).reduce((score, factor) => {
    return score + (factors[factor] * weights[factor]);
  }, 0);
};

2. 内容推荐

自动建议:

const generateRecommendations = (analysisData) => {
  const recommendations = [];

  // Content gap analysis
  const underrepresentedTopics = findContentGaps(analysisData);
  if (underrepresentedTopics.length > 0) {
    recommendations.push({
      type: 'content_gap',
      priority: 'high',
      message: `Consider creating content about: ${underrepresentedTopics.join(', ')}`,
      action: 'Create new posts in underrepresented categories'
    });
  }

  // SEO optimization
  const seoIssues = findSEOIssues(analysisData);
  if (seoIssues.length > 0) {
    recommendations.push({
      type: 'seo_optimization',
      priority: 'medium',
      message: `${seoIssues.length} pages need SEO improvements`,
      action: 'Add missing meta descriptions and optimize titles'
    });
  }

  // Content freshness
  const staleContent = findStaleContent(analysisData);
  if (staleContent.length > 0) {
    recommendations.push({
      type: 'content_freshness',
      priority: 'low',
      message: `${staleContent.length} posts haven't been updated in over a year`,
      action: 'Review and update older content'
    });
  }

  return recommendations;
};

3. 趋势分析

内容速度追踪:

const analyzeContentVelocity = (pages) => {
  const monthlyData = groupPagesByMonth(pages);
  const velocity = [];

  for (let i = 1; i < monthlyData.length; i++) {
    const current = monthlyData[i];
    const previous = monthlyData[i - 1];

    velocity.push({
      month: current.month,
      posts: current.count,
      change: current.count - previous.count,
      changePercent: ((current.count - previous.count) / previous.count) * 100
    });
  }

  return velocity;
};

与 Hugo 集成

1. 构建集成

分析在 Hugo 构建过程中自动运行:

// scripts/generate-analysis-data.js
const generateAnalysis = async () => {
  console.log('🔍 Starting content analysis...');

  // Scan all content
  const pages = await scanContent();
  console.log(`📄 Analyzed ${pages.length} pages`);

  // Generate analytics
  const analytics = generateAnalytics(pages);
  console.log(`📊 Generated ${Object.keys(analytics).length} metric categories`);

  // Save data
  await saveAnalysisData(analytics);
  console.log('✅ Analysis data saved');

  // Generate dashboard
  await generateDashboard(analytics);
  console.log('📈 Dashboard generated');
};

2. 模板集成

在模板中显示分析:

<!-- layouts/partials/content-stats.html -->
{{ with .Site.Data.content_analysis }}
<div class="content-stats">
  <div class="stat">
    <span class="stat-number">{{ .total_pages }}</span>
    <span class="stat-label">Total Posts</span>
  </div>

  <div class="stat">
    <span class="stat-number">{{ .summary.total_words | lang.FormatNumber 0 }}</span>
    <span class="stat-label">Words Written</span>
  </div>

  <div class="stat">
    <span class="stat-number">{{ .summary.average_reading_time }}min</span>
    <span class="stat-label">Avg Reading Time</span>
  </div>
</div>
{{ end }}

3. 短代码集成

分析短代码:

<!-- layouts/shortcodes/content-analysis.html -->
{{ $type := .Get "type" | default "overview" }}
{{ $data := .Site.Data.content_analysis }}

{{ if eq $type "overview" }}
  {{ partial "analysis/overview.html" $data }}
{{ else if eq $type "categories" }}
  {{ partial "analysis/categories.html" $data }}
{{ else if eq $type "trends" }}
  {{ partial "analysis/trends.html" $data }}
{{ end }}

内容中使用:

{{< content-analysis type="overview" >}}

{{< content-analysis type="categories" >}}

{{< content-analysis type="trends" >}}

性能优化

1. 高效数据处理

增量分析:

const incrementalAnalysis = async () => {
  const lastRun = getLastAnalysisTime();
  const changedFiles = await getChangedFiles(lastRun);

  if (changedFiles.length === 0) {
    console.log('No changes detected, skipping analysis');
    return;
  }

  console.log(`Processing ${changedFiles.length} changed files`);

  // Load existing data
  const existingData = loadExistingAnalysis();

  // Update only changed content
  for (const file of changedFiles) {
    const analysis = await analyzeFile(file);
    existingData.pages[file] = analysis;
  }

  // Recalculate aggregates
  existingData.summary = calculateSummary(existingData.pages);

  // Save updated data
  await saveAnalysisData(existingData);
};

2. 缓存策略

分析结果缓存:

const cacheAnalysis = {
  get: (key) => {
    const cacheFile = `cache/analysis-${key}.json`;
    if (fs.existsSync(cacheFile)) {
      const cached = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
      if (Date.now() - cached.timestamp < 3600000) { // 1 hour
        return cached.data;
      }
    }
    return null;
  },

  set: (key, data) => {
    const cacheFile = `cache/analysis-${key}.json`;
    fs.mkdirSync('cache', { recursive: true });
    fs.writeFileSync(cacheFile, JSON.stringify({
      timestamp: Date.now(),
      data
    }));
  }
};

故障排除

常见问题

1. 分析未运行

问题: 内容分析未生成数据

解决方案:

# 检查脚本是否存在
ls -la scripts/generate-analysis-data.js

# 手动运行带调试输出
DEBUG=analysis node scripts/generate-analysis-data.js

# 检查构建日志中的错误
npm run build 2>&1 | grep -i error

2. 仪表板未显示

问题: 分析仪表板未显示数据

解决方案:

# 检查数据文件是否存在
ls -la data/content_analysis.json

# 验证数据格式
cat data/content_analysis.json | jq .

# 检查 Hugo 数据加载
hugo config | grep -i data

3. 性能问题

问题: 分析运行时间过长

解决方案:

# 启用增量分析
export ANALYSIS_INCREMENTAL=true

# 排除大目录
export ANALYSIS_EXCLUDE="content/archive/**,content/deprecated/**"

# 使用并行处理
export ANALYSIS_PARALLEL=true

下一步

设置内容分析后:

相关主题


需要帮助吗?请查看我们的 故障排除指南 或创建 GitHub 问题。