ブログ・SNS・データ収集を自動化する、実践的なパイプラインの作り方

ブログを定期更新したい、SNSに毎日投稿したい、競合サイトの価格を追いたい。そう思いながら、結局は手作業で続けている人は多いです。

「自動化」という言葉はよく聞くが、何から始めればいいかわからない。あるいは、ツールを触ってはみたが途中で止まってしまった。そういった相談を受けることがあります。

この記事では、ブログ更新・SNS投稿・データ収集の3つをまとめて「どう自動化するか」を、実際に動く構成で解説します。コンセプトの話ではなく、手を動かして動作確認できる内容です。

結論

自動化パイプラインは「データ収集 → 処理・生成 → 配信」の3層で考えると整理しやすい。ブログ・SNS・データ収集のどれから始めても、この構造は変わらない。ツールはPython + GitHub Actions + 各サービスAPIの組み合わせが、2026年5月時点で最もコスト効率よく動く。

自動化パイプラインの全体像:3層で考える

「自動化したい」という要望を分解すると、ほぼ必ずこの3段階に収まります。

  1. 収集層:外部のデータや情報を取ってくる
  2. 処理・生成層:取得したデータを整形・変換・文章化する
  3. 配信層:WordPress、X (Twitter)、Slack などの宛先に送る

ブログ自動投稿も、SNS自動配信も、価格追跡も、この3層のどこかを担っているだけです。「全部を一気に自動化しよう」とすると壊れたときの切り分けが難しくなるため、1層ずつ確認しながら積み上げる方が実用的です。

処理・生成層に生成AIを挟むかどうかは任意です。単純なデータ収集と転送なら不要ですが、要約や文体変換が必要ならAnthropic Claude APIOpenAI APIを組み込む形になります。

収集層 RSS / スクレイピング 処理・生成層 Python / AI API 配信層 WP / X / Slack 自動化パイプラインの3層構造 (概念図)
収集 → 処理・生成 → 配信の3層。各層を独立させると障害切り分けが容易になる

検証環境と前提:何を使って動かしたか

今回の検証は以下の環境で行いました。

項目 内容
実行環境 Python 3.12 / GitHub Actions (ubuntu-latest)
ブログ配信先 WordPress 6.5 (REST API v2)
SNS配信先 X (Twitter) API v2 / Basic プラン
データ収集 feedparser 6.0.11 (RSS解析) + requests 2.31
検証時期 2026年5月

GitHubリポジトリをプライベートで作成し、GitHub Actionsのスケジュールトリガー(schedule: cron)で動かします。シークレットはすべてGitHub Secretsに格納します。APIキーをコードに直書きするのは、プライベートリポジトリでも避けます。

注意

X (Twitter) APIは2023年2月以降に料金体系が大きく変わりました。2026年5月時点でポスト投稿が可能なのはBasicプラン以上(月100ドル)です。無料プランではv2の書き込みエンドポイントが使えません。利用前に公式ドキュメントでプランを確認してください。

ディレクトリ構成はシンプルに保ちます。

my-auto-pipeline/
├── .github/
│   └── workflows/
│       └── daily.yml        # GitHub Actions 定義
├── collectors/
│   ├── rss_collector.py     # RSS収集
│   └── price_scraper.py     # 価格データ収集
├── processors/
│   └── summarizer.py        # テキスト処理・AI要約
├── distributors/
│   ├── wp_poster.py         # WordPress 投稿
│   └── x_poster.py          # X 投稿
├── requirements.txt
└── README.md

手順:収集・処理・配信を順番に実装する

  1. Step 1: RSS収集スクリプトを作る

    feedparserでRSSフィードを取得し、最新N件のタイトル・URL・要約を辞書リストで返す関数にします。エラー時はNoneではなく空リストを返すと、後続処理がシンプルになります。

  2. Step 2: テキスト処理(必要なら AI 要約)を挟む

    記事の要約が必要な場合はClaude APIのMessages APIに渡します。不要なら、feedparserが返すsummaryフィールドをそのまま使います。AI処理はコストが発生するため、呼び出し前に「本当に必要か」を確認します。

  3. Step 3: WordPress REST APIで下書き投稿する

    WordPressのREST APIエンドポイント(`/wp-json/wp/v2/posts`)にPOSTリクエストを送ります。statusを`draft`にしておくと、人間が確認してから公開できます。最初は`publish`にせず`draft`で動作確認するのが安全です。

  4. Step 4: X APIでポストを送る

    tweepy 4.x(v2対応)のClient.create_tweetを使います。文字数は280文字(日本語は半角換算で140文字相当)の制限があるため、投稿前にtextを切り詰める処理を入れておきます。

  5. Step 5: GitHub Actionsで定時実行する

    daily.ymlにcronを設定し、日次で自動実行します。APIキー類はGitHub Secretsから`${{ secrets.WP_PASSWORD }}`の形で環境変数として渡します。

各スクリプトの骨格を示します。実際に動作確認済みのコードです(2026年5月)。

rss_collector.py(主要部分)

import feedparser
from typing import List, Dict

def fetch_latest(feed_url: str, limit: int = 5) -> List[Dict]:
    feed = feedparser.parse(feed_url)
    results = []
    for entry in feed.entries[:limit]:
        results.append({
            "title": entry.get("title", ""),
            "link": entry.get("link", ""),
            "summary": entry.get("summary", ""),
        })
    return results

wp_poster.py(主要部分)

import requests
import os

def post_draft(title: str, content: str) -> dict:
    wp_url = os.environ["WP_URL"]  # 例: https://example.com
    user = os.environ["WP_USER"]
    password = os.environ["WP_APP_PASSWORD"]  # WordPress アプリパスワード

    endpoint = f"{wp_url}/wp-json/wp/v2/posts"
    payload = {"title": title, "content": content, "status": "draft"}

    resp = requests.post(endpoint, json=payload, auth=(user, password), timeout=15)
    resp.raise_for_status()
    return resp.json()

WordPress側の認証は「アプリケーションパスワード」機能(WordPress 5.6以降で標準搭載)を使います。通常のログインパスワードは使いません。

GitHub Actions(daily.yml)

name: daily-pipeline

on:
  schedule:
    - cron: '0 21 * * *'  # 毎日 JST 06:00 (UTC 21:00)
  workflow_dispatch:       # 手動実行も可能にしておく

jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: pip install -r requirements.txt
      - name: Run pipeline
        env:
          WP_URL: ${{ secrets.WP_URL }}
          WP_USER: ${{ secrets.WP_USER }}
          WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
          X_BEARER_TOKEN: ${{ secrets.X_BEARER_TOKEN }}
          X_API_KEY: ${{ secrets.X_API_KEY }}
          X_API_SECRET: ${{ secrets.X_API_SECRET }}
          X_ACCESS_TOKEN: ${{ secrets.X_ACCESS_TOKEN }}
          X_ACCESS_SECRET: ${{ secrets.X_ACCESS_SECRET }}
        run: python main.py

workflow_dispatchを入れておくと、手動で任意のタイミングで実行できます。デバッグ時に必ず使うため、最初から入れておくことを勧めます。

結果と考察:動かして見えてきたこと

この記事のポイント

  • パイプラインは「収集・処理・配信」の3層で分離すると、障害時の切り分けが容易になる
  • WordPress投稿は最初 draft ステータスで動かし、確認フローを挟むのが実用上安全
  • GitHub ActionsはGitHub Free プランで月2,000分まで無料(2026年5月時点)。日次1回の実行なら月30分程度で収まる
  • X APIはプランによって書き込み権限が異なるため、実装前にプラン確認が必須

実際に1週間動かした結果、障害が出たのは以下の2点でした。

1. RSSフィードのエンコーディング問題

一部のRSSフィードがISO-8859-1で配信されていて、feedparserがUnicode変換に失敗するケースがありました。feedparserは通常この変換を自動処理しますが、フィード側のContent-Typeが不正確な場合はentry.title.encode('latin-1').decode('utf-8')のような変換が必要になることがあります。

2. GitHub ActionsのUTCとJST換算ミス

cronはUTC基準のため、JST(UTC+9)との換算を間違えると意図した時刻に動きません。「JST 6時に動かしたい→UTC 21時(前日)」という点は毎回確認が必要です。

コスト面では、GitHub ActionsはGitHub Freeプランで月2,000分が無料GitHub公式: Billing for GitHub Actions)。この構成の場合、1回の実行で約1〜2分かかるため、月30〜60分の消費で十分余裕があります。

生成AI要約をClaude claude-3-haiku-20240307で行った場合、1記事あたりのトークン消費は入力500〜800トークン・出力200〜300トークン程度(概算)。2026年5月時点の料金(Anthropic公式)を当てはめると、1記事0.01〜0.03セント未満の水準で、コスト面では実質無視できます。ただしAPI呼び出しのレイテンシが1〜3秒追加されるため、タイムアウト設定は余裕をもたせます。

価格スクレイピングについては、対象サイトの利用規約を必ず確認する必要があります。明示的に禁止されているサイトへのスクレイピングは行わないのが原則です。Robots.txtの確認も必須です。


※本記事は2026-05-25時点の情報に基づきます。AI モデルや API の仕様・料金は変更されることがあります。最新は公式ドキュメントをご確認ください。

AI / tech の選択は要件や環境によって最適解が変わります。本記事は参考情報で、最終的な技術判断はご自身の検証に基づいてください。


【disclosure】affiliate link を含む。

まとめ

  • パイプラインを「収集 → 処理・生成 → 配信」の3層に分けると、どこで何が起きているかが見えやすくなり、修正コストが下がる
  • WordPress投稿はdraftステータスから始める、GitHub ActionsのcronはUTC基準、この2点は最初に確認しておくと無駄なデバッグを減らせる
  • X API の書き込みはBasicプラン(月100ドル)以上が必要。コストに見合うか先に判断する

今回の構成で月の運用コストはほぼゼロ(AI要約なし)〜数十円(AI要約あり)の範囲に収まっています。次は収集対象をRSSだけでなく、特定ページの更新検知(差分比較)に拡張してみたいところです。

Photo by Goran Ivos on Unsplash