2025-07-04

Google Blogger API で技術記事投稿を自動化してみた

Google Blogger API で技術記事投稿を自動化してみた

技術ブログの執筆と投稿は、継続的な情報発信において重要な活動である。しかし、記事作成から投稿までの手作業は時間がかかり、効率化の余地がある。

本記事では、Markdown で記事を作成し、Google Blogger API を通じて自動投稿するスクリプトの作成方法を詳しく解説する。OAuth2 認証と環境変数管理に焦点を当てた実践的な実装例を紹介する。

システム要件

前提条件

  • Node.js 16 以上
  • Google アカウント
  • Blogger ブログ

目標とする機能

  • Markdown による記事作成
  • OAuth2 による安全な認証
  • 環境変数による設定管理
  • Google Blogger への自動投稿

アーキテクチャ設計

ディレクトリ構成

├── articles/
│   ├── drafts/          # 作成中の記事
│   ├── review/          # レビュー中の記事
│   ├── published/       # 投稿済みの記事
│   └── templates/       # 記事テンプレート
├── scripts/
│   ├── auth.js          # OAuth2 認証
│   ├── new-article.js   # 記事作成
│   ├── build.js         # HTML ビルド
│   ├── publish-draft.js # Blogger 投稿
│   └── update-article.js # 記事更新
└── blogger-config.json  # API 設定ファイル

技術スタック

  • 言語: JavaScript (Node.js)
  • 認証: Google OAuth2
  • ビルド: Markdown-it + MathJax + Prism.js
  • 設定管理: 環境変数 + JSON

Google Cloud Console の設定

1. プロジェクトの作成と API 有効化

# Google Cloud Console での手順:
# 1. 新しいプロジェクトを作成
# 2. Blogger API を有効化
# 3. OAuth 2.0 認証情報を作成(デスクトップアプリケーション)

2. OAuth2 認証情報の取得

重要な設定項目:

  • アプリケーションの種類: デスクトップアプリケーション
  • リダイレクトURI: urn:ietf:wg:oauth:2.0:oob
  • スコープ: https://www.googleapis.com/auth/blogger

認証システムの実装

OAuth2 認証スクリプト

// scripts/auth.js の主要部分
const { google } = require('googleapis');

async function authenticateUser(config) {
    const { clientId, clientSecret, redirectUri } = config.blogger;
    
    const oAuth2Client = new google.auth.OAuth2(
        clientId,
        clientSecret,
        redirectUri
    );
    
    // 認証URLを生成
    const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: [
            'https://www.googleapis.com/auth/blogger',
            'https://www.googleapis.com/auth/blogger.readonly'
        ]
    });
    
    console.log('認証URL:', authUrl);
    
    // 認証コードを取得(ユーザー入力)
    const authCode = await getUserInput();
    
    // トークンを取得・保存
    const { tokens } = await oAuth2Client.getToken(authCode);
    await fs.writeJson('blogger-token.json', tokens);
    
    return oAuth2Client;
}

環境変数管理

// blogger-config.json
{
  "blogger": {
    "blogId": "${BLOGGER_BLOG_ID}",
    "clientId": "${BLOGGER_CLIENT_ID}",
    "clientSecret": "${BLOGGER_CLIENT_SECRET}",
    "redirectUri": "urn:ietf:wg:oauth:2.0:oob"
  }
}
// 環境変数展開機能
function expandEnvironmentVariables(obj) {
    if (typeof obj === 'string') {
        return obj.replace(/\$\{([^}]+)\}/g, (match, envVar) => {
            return process.env[envVar] || match;
        });
    }
    // 再帰的に処理...
}

記事管理システム

記事作成スクリプト

// scripts/new-article.js の核心部分
function generateFileName(title, date) {
    const dateStr = moment(date).format('YYYYMMDD');
    const titleSlug = title
        .toLowerCase()
        .replace(/[^a-z0-9ひらがなカタカナ漢字]/g, '_')
        .replace(/_+/g, '_')
        .replace(/^_|_$/g, '');
    
    return `${dateStr}_${titleSlug}.md`;
}

function generateArticleContent(options) {
    return `---
title: "${options.title}"
date: "${options.date}"
tags: [${options.tags.map(tag => `"${tag}"`).join(', ')}]
description: "${options.description}"
---

# ${options.title}

## 概要

${options.description}

## 内容

### セクション1

内容を書く
`;
}

ビルドシステム

// scripts/build.js - Markdown から HTML への変換
const MarkdownIt = require('markdown-it');
const markdownItKatex = require('markdown-it-katex');
const Prism = require('prismjs');

const md = new MarkdownIt({
    html: true,
    breaks: true,
    linkify: true,
    highlight: function (str, lang) {
        if (lang && Prism.languages[lang]) {
            return Prism.highlight(str, Prism.languages[lang], lang);
        }
        return '';
    }
});

md.use(markdownItKatex); // 数式対応

Blogger API 連携

記事投稿機能

// scripts/publish-draft.js の主要部分
async function publishToBlogger(auth, blogId, title, content, labels = []) {
    const blogger = google.blogger({ version: 'v3', auth });
    
    const post = {
        kind: 'blogger#post',
        title: title,
        content: content,
        labels: labels
    };
    
    const response = await blogger.posts.insert({
        blogId: blogId,
        resource: post,
        isDraft: true  // 安全のため下書きとして投稿
    });
    
    return response.data;
}

エラーハンドリング

// 認証エラーの詳細処理
catch (error) {
    if (error.message.includes('access_denied')) {
        console.log('OAuth 同意画面でテストユーザーを追加してください');
    } else if (error.message.includes('invalid_client')) {
        console.log('クライアントIDとシークレットを確認してください');
    }
}

セキュリティ考慮事項

機密情報の管理

# .gitignore に追加すべき項目
blogger-token.json
*.local.json
.env
.env.local

環境変数の設定

# 本番環境での設定例
export BLOGGER_CLIENT_ID="your-client-id"
export BLOGGER_CLIENT_SECRET="your-client-secret"
export BLOGGER_BLOG_ID="your-blog-id"

使用方法

基本的な使い方

# 1. 認証設定(初回のみ)
node scripts/auth.js

# 2. 記事をMarkdownで作成(手動)
# articles/drafts/your-article.md

# 3. HTML にビルド
node scripts/build.js your-article.md

# 4. Blogger に下書きとして投稿
node scripts/publish-draft.js your-article.md

# 5. 既存記事の更新
node scripts/update-article.js your-article.md

便利なコマンド

# 記事一覧の表示
node scripts/publish-draft.js --list

# ヘルプ表示
node scripts/publish-draft.js --help

トラブルシューティング

OAuth 認証エラー

問題: "アクセスをブロック: 認証エラーである"
解決: Google Cloud Console でテストユーザーを追加

性能と拡張性

最適化のポイント

  1. キャッシュ活用: 認証トークンの適切な管理
  2. 並列処理: 複数記事の一括処理対応
  3. エラー回復: リトライ機能の実装
  4. ログ管理: 詳細なログ出力

今後の拡張案

  • 画像の自動アップロード機能
  • SEO メタデータの自動生成
  • SNS への自動投稿連携
  • 記事のスケジュール投稿機能

まとめ

本記事では、Google Blogger API を活用した技術記事の自動投稿方法を解説した。

実現できたこと

  • 効率的な記事管理: Markdown による記事作成
  • 安全な認証: OAuth2 による API 連携
  • シンプルな構成: 複雑な依存関係のない軽量システム
  • 自動投稿: Google Blogger への直接投稿

学んだポイント

  1. OAuth2 認証の実装: Google API との安全な連携方法
  2. 環境変数管理: セキュリティを考慮した設定管理
  3. Node.js スクリプト: 実用的な CLI ツールの作成
  4. システム設計: 複雑性を排除したシンプルなアーキテクチャ

このスクリプトにより、技術記事の執筆から投稿までの作業を大幅に効率化できた。Google Blogger API は思った以上に使いやすく、個人ブログの自動化には最適である。

参考文献


執筆について: この記事は Claude Code (claude.ai/code) との協働により執筆され、実際に構築した自動投稿スクリプトを使用して Blogger に投稿されている。

0 件のコメント:

コメントを投稿

ラビット・チャレンジ - Stage 3. 深層学習 前編 (Day 1)

提出したレポートです。 絶対書きすぎですが、行間を埋めたくなるので仕方ない。 Rabbit Challenge - Stage 3. 深層学習 前編 (Day 1) 0. 深層学習とは何か この講義(Day1)の内容では、ニューラルネットワークを用いた学習方法として、順...