【連載02】Python×AIでブログ半自動化!APIでWordPressへ下書き投稿するプロトタイプ開発術

PC

こんにちは、てつです!

今回は、前回から始まったブログ半自動化プロジェクトの続きをやっていこうと思います!

まだ前回の記事を見ていない方はぜひこちらも見て頂けると幸いです<(_ _)>

【連載01】ブログ半自動化プロジェクト始動!GitHub連携と挫折しないための全体設計
こんにちは、てつです!今回からは、ブログの半自動化の構築過程を記録していこうと思います!ブログの半自動化といっても、前回までに立ち上げたブログサーバーが外部に公開していないものになるので、ブログの完全自動で不労所得を謳うような記事ではないこ…

前回の次回予告にて、「プロトタイプの作成」をやるといってましたね。そこからやっていきます!

では、まずなぜプロトタイプを作るのか?という説明から行かせてもらいます!

まず、ビジネスやシステム開発の現場ではこのプロトタイプを MVP(Minimum Viable Product:実用最小限の製品) と呼びます。

このプロトタイプの作成意図としては、全体のボトルネックや必要なデータ項目を明確することです。

最小の労力で「コアとなる価値」の部分を検証し、学習(フィードバック)を得ることができる。それがプロトタイプ作成の意義です!

この「コア」となる部分は、今回のプロジェクトでいうと、「データが入り、AIが書き、WordPressに届く」です。

「プロトタイプ」を先に作るべき4つのロジック
  1. 価値の早期検証: AIが生成する記事の品質やバリデーションの難易度を早めに知ることで、設計ミスを防げます。
  2. モチベーションの維持: 実際にブログに記事が投稿される「成果」を早く目にすることで、開発の継続意欲が高まります。
  3. 必要な項目の逆算: AIに投げる際に「実は発行元メディアの名前も必要だった」など、後から気づく項目をDB設計に反映しやすくなります。
  4. リスクの早期発見: WordPress APIとの連携やAIのAPIコストなど、実装上の課題を早めに特定できます。

今回は以下のようなステップでプロトタイプを作成していこうと思います。

  • ステップ1:固定データでの試行
    • RSS取得は後回しにし、1件分のニュース情報を変数に直接書き込んでテストします。
  • ステップ2:AIへのパス
    • そのデータをプロンプトに埋め込み、AI APIから返答を受け取ります。
  • ステップ3:WordPressへの「下書き」投稿
    • 受け取ったテキストをそのままWordPressのREST APIで投稿します。

DB(データベース)の設計やプロンプトなどの作り込みはあと回しです!まず「核」を作ります!

固定データでの試行

ここでは、以下の3つをやっていきます。要は、自動化システムの「心臓部」にダミーの血液を流して動作確認をする作業です。

テスト用ファイルの作成: 他のファイルと混ざらないよう、プロトタイプ専用のPythonファイルを用意します。

ニュースデータの定義: AIに渡すための「材料」となる情報を、変数(データの入れ物)に格納します。

データの出力確認: プログラムを実行し、正しくデータが読み込まれているか画面上で確認します。

まずプロジェクトディレクトリに移動してください。

そこでプロトタイプ専用のディレクトリを作り、そこにテストファイルを作っていきます。

#プロトタイプ専用のディレクトリを作成します。
mkdir prototypes

touch prototype_core.py

正直個人でしか開発をしたことがないので様式美のようなものはわかりませんが、私は作業ディレクトリのルートは散らかさないようにしてます。

実験で作成した一時的なファイルとかゴミデータは、ディレクトリごと に「.gitignore」 に指定して管理しやすくなるってメリットもあります。

こういったルールを作っておかないとすぐ散らかしちゃうので作っておくことをお勧めします。笑

脱線しちゃいましたね。作れましたか?

作れたらファイルにコードを書いていきましょう。ここの部分は各々異なると思うので実際に作りたいシステムのコードを書いてみましょう。AIにコードを書いてもらうのもいいと思います。

ただ、理解しながら書いていくことが大切です。全文をコピペして次にいくのではなく、読んでみて、写経してみるのもいい練習になると思います。

ていうか僕はそうして練習してます。このブログがその一環でもありますしね笑

どうですか?できましたか?

僕が使ったサンプルコードは以下です。正しく動作したので次に進みます。

sample_news = {
"title": "最新のAI搭載ガジェットが発表、作業効率が200%向上か",
"url": "https://example.com/news/123",
"summary": "米テック企業が新しいスマートデバイスを発表。AIがユーザーの行動を予測し、PC作業を自動化する機能を搭載しています。",
}

print(f" [テスト用タイトル] : {sample_news['title']}")
print(f" [テスト用URL] : {sample_news['url']}")

AIへのパス

AI(生成AI API)に丸投げするのではなく、こちらで「枠組み」を指定してあげる必要があります。

なのでここでは、「枠組み」を作ります。

以下のステップで処理します。

1.役割(ペルソナ)の定義: AIに「プロのガジェットブロガー」という役割を与えます。

2.命令文(指示)の作成: 「ニュースを要約し、読者のメリットを付け加えて、WordPress用のHTML形式で出力せよ」といった具体的な指示を定義します。

3.テンプレート(型)の用意: 固定データを流し込むための「雛形」を作ります。

4.結合: 指示文とニュースデータを合流させ、AIへ送る「最終的な依頼文(プロンプト)」を完成させます。

では実装に移っていきます。先ほどのファイルにプロンプト追加します。

参考にはならないと思いますが、念のため貼っておきます。

※ここでは最小構成で動かすために.py内にプロンプトをいれますが、本番では実行ファイルと分離させます。

sample_news = {
"title": "最新のAI搭載ガジェットが発表、作業効率が200%向上か",
"url": "https://example.com/news/123",
"summary": "米テック企業が新しいスマートデバイスを発表。AIがユーザーの行動を予測し、PC作業を自動化する機能を搭載しています。",
}

print(f" [テスト用タイトル] : {sample_news['title']}")
print(f" [テスト用URL] : {sample_news['url']}")

prompt_template = f"""
あなたはプロのガジェットブロガーです。
以下のニュースを元に、読者がワクワクするようなブログ記事を日本語で作成してください。

【ニュース内容】
タイトル: {sample_news['title']}
URL: {sample_news['url']}
概要: {sample_news['summary']}

【出力ルール】
・読者のメリット(ベネフィット)を強調すること。
・WordPressにそのまま貼れるHTML形式(h2, pタグなど)で出力すること。
・1000文字程度のボリュームで作成すること。
"""

print("\n---生成されたプロンプト---")
print(prompt_template)

実際に読み込まれていることを確認したら、このステップの中核であるAI APIへのリクエストを送信する段階に移っていきます。

まずはAPIキーの取得が必要なので事前に終えてから作業しましょう。

最初は無料枠のあるGeminiAPIかOpenAI APIでいいかなと思います。下記リンクからアクセスしてログインして取得してみましょう。

Sign in – Google Accounts
https://platform.openai.com/api-keys

ただこれからの手順で無料枠によるエラーが出ることがあるかもしれません。ていうか僕はめっちゃ出ました笑

なので、最初は無料枠で試して駄目なら、有料版のAPIの取得してみてください。

下記コマンドを実行し、管理ツールの導入、実行方法の変更、ライブラリのインストールをします。

# 1. パッケージリストを更新します
sudo apt update

# 2. pip をインストールします(途中で y/n を聞かれたら y を入力)
sudo apt install -y python3-pip

# 3. システムのアップデートとモジュールのインストール
sudo apt install -y python3.13-venv

# 4.「venv」という名前の仮想環境フォルダを作成します。
python3 -m venv venv

# 5. 作成した仮想環境を有効化します。
source venv/bin/activate

# 6. Geminiかopenai のライブラリをインストールします(python3 -m をつけるのが確実です)
python3 -m pip install -U openai
python3 -m pip install -U google-genai

途中で仮想環境ファルダの作成手順があると思います。なぜ必要なのか?

現代の Linux(Ubuntu や Debian の最新版など)は、システムの重要なプログラムを壊さないように、勝手に Python ライブラリを追加できないようになっているからです。

また途中の#3は、Debian/Ubuntu系のOS特有の仕様で、Python本体とは別に「仮想環境(venv)を作成するためのモジュール」を個別にインストールする必要があるので挟んでます。

こういった自分の開発環境に依存するエラーはよく出てくると思います。

辛抱強く耐えましょう。慣れてきます。

僕もここでエラーが出たので備忘録として残しておきます笑

ライブラリのインストールまで終わりましたか?

終わったらGemini APIへ送信し、ブログ記事としての回答を受け取るロジックを実装していきます。

下記コマンドを実行し、環境変数を管理するファイルを作りましょう。

# 仮想環境内で実行してください
pip install python-dotenv

.env ファイルに書いた設定値を Python プログラム内で変数として扱えるようにするツールを導入します。

これにより他人に絶対見せてはいけないAPIキーなどの情報分離して管理できるようになります。

では、.envファイルを作成し、APIキーを入れておきましょう。

Bash
touch .env

nano .env

#.env
GEMINI_API_KEY=(実際のキー)
OPEN_API_KEY=(実際のキー)

.envファイルはプロジェクトのルートディレクトリに配置しておいたほうがいいです。

また、「=」 の前後にスペースを入れないのがルールになります。気を付けましょう。

ここまでできたら.gitignoreを絶対に更新するようにお願いします。

最低限ここら辺のものは追加しておくと安心です。

# --- 秘匿情報 (Security) ---
# 1行解説: APIキーなどが含まれる設定ファイルを Git の管理外にします。
.env

# --- 仮想環境 (Environment) ---
# 1行解説: ローカルで作成した仮想環境フォルダそのものは Git に含めません。
venv/
.venv/
env/

# --- Python 実行生成物 (Python Artifacts) ---
# 1行解説: Python がプログラムを高速実行するために作るキャッシュファイルを無視します。
__pycache__/
*.py[cod]
*$py.class

# --- データ・ログ (Data & Logs) ---
# 1行解説: 実行時のログや、以前作成した db フォルダ内の生データを管理外にします。
*.log
db/

# --- エディタ・OS関連 (Editor & OS) ---
# 1行解説: VS Code の設定や OS が勝手に作る隠しファイルを無視します。
.vscode/
.DS_Store
Thumbs.db

特に .envvenv/ は、一度でも Git(特に GitHub 等の公開の場)に上げてしまうと、履歴を消すのが非常に面倒です。

今この瞬間に設定を終えるのが、最もコストの低いセキュリティ対策になります。

環境変数の設定と.gitignoreの記述が終わったら実際にコードを書き実行していきましょう。

今回僕はOpenAIを使っているのでそのサンプルコードを添付します。ご参考までに。

sample_news = {
"title": "最新のAI搭載ガジェットが発表、作業効率が200%向上か",
"url": "https://example.com/news/123",
"summary": "米テック企業が新しいスマートデバイスを発表。AIがユーザーの行動を予測し、PC作業を自動化する機能を搭載しています。",
}

prompt_template = f"""
あなたはプロのガジェットブロガーです。
以下のニュースを元に、読者がワクワクするようなブログ記事を日本語で作成してください。

【ニュース内容】
タイトル: {sample_news['title']}
URL: {sample_news['url']}
概要: {sample_news['summary']}

【出力ルール】
・読者のメリット(ベネフィット)を強調すること。
・WordPressにそのまま貼れるHTML形式(h2, pタグなど)で出力すること。
・1000文字程度のボリュームで作成すること。
"""

import os
import openai
from google import genai
from pathlib import Path
from dotenv import load_dotenv

env_path = Path(__file__).resolve().parent.parent / ".env"

load_dotenv(dotenv_path=env_path)

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")

def generate_article(prompt, provider="openai"):
client = openai.OpenAI(api_key=OPENAI_API_KEY)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": prompt}
],
)
return response.choices[0].message.content


print("=== 記事を生成中 ===")
result = generate_article(prompt_template)

print(result)

保存出来たら下記コマンドを実行し、出力結果を確認しましょう。

 python3 prototype_core.py 

以下の画像が私の実行結果となります。

プロトタイプなので、記事の品質等は度外視するとやりたいことは出来てるって感じですね。

ここまで出来たら、ニュースデータの読み込み → プロンプトの構築 → AI APIとの通信 → 記事生成というシステムの核部分は完成したことになります。

最後にwordpressにこの記事を流していきましょう。

WordPressへの「下書き」投稿

やっとここまで来ました。

WordPressに記事を出力していきましょう。

WordPress 下書き投稿のロジック

  1. 認証準備: WordPress 管理画面で「アプリケーションパスワード」を発行し、外部からの操作を許可します。
  2. 接続情報の定義: 投稿先の URL(エンドポイント)と、ユーザー名、パスワードをプログラムに組み込みます。
  3. データの構造化: AI が生成した HTML 本文とタイトルを、WordPress が受け取れる JSON 形式に整えます。
  4. リクエスト送信: Python の requests ライブラリを使い、WordPress サーバーへ「下書き(draft)として保存せよ」という命令を送ります。

まず事前準備として、アプリケーションパスワードを取得しましょう。

手順: WordPress管理画面 > ユーザー > プロフィール の最下部付近にある「新しいアプリケーションパスワード名」に「API-Tool」などと入力して発行します。

注意: 表示される 「xxxx xxxx xxxx xxxx」 という文字列をコピーして、.env ファイルに保存してください。これは通常のログインパスワードとは別物です。

しかし、管理者(Administrator)権限は何でもできてしまうため、万が一プログラムのミスや設定ファイルの流出が起きた際のリスクが大きすぎます。

なので今回は投稿の権限だけ持ったユーザーを作ってからこの作業をします。

設定のステップ(手順)

  1. 新規ユーザー作成: WordPress 管理画面の ユーザー > 新規追加 から、名前を ai-bot などにして作成します。
  2. 権限の設定: 権限グループを 「投稿者」 に設定します。
  3. アプリパスワード発行: 作成した新ユーザーでログインし直し、そのユーザーのプロフィール画面から「アプリケーションパスワード」を発行してください。

ここで私は少し問題が発生しました笑

レンタルサーバーや外部に公開しているブログであれば、「https://」という通信になっていると思います。ただ僕のブログは外部公開をしない前提で「http://」という通信になっています。

WordPress はデフォルトで「セキュリティのために暗号化(HTTPS)されていない通信ではパスワードを発行させない」というガードを固めています。

このまではアプリケーションパスワードの発行ができません。

なので、非公開の「開発用サイト」であることを WordPress に教えてあげなければなりません。

解決のためのロジック(処理の手順)

  1. セキュリティ制限の解除: 本来は安全のために HTTPS が必須ですが、開発環境用の「許可フラグ」を立てます。
  2. コードの追記: WordPress の wp-config.php またはテーマの functions.php にコードを追加します。
  3. 反映確認: プロフィール画面をリロードし、入力欄が出現することを確認します。

今回は、WordPress の設定ファイルである wp-config.php を編集する方法を採用します。

まず、wp-config.php ファイルを探しますか。findコマンドで対象ファイルを探しましょう。

# システム全体から wp-config.php という名前のファイルを検索し、場所を表示します。
sudo find / -name "wp-config.php" 2>/dev/null

この出力結果が対象ファイルがあるパスです。

見つかった対象ファイルを編集しましょう。下記コマンドを実行してください。

# 現在のファイルを .bak という名前で複製し、いつでも切り戻せるようにします。
sudo cp /<さっきのコマンドで見つかったパス>/wp-config.php /さっきのコマンドで見つかったパス>/wp-config.php.bak
# 管理者権限で設定ファイルを開きます。
sudo nano /mnt/sdcard/tech-shortcut-lab/html/wp-config.php
// サイトの環境タイプを 'local' に設定し、HTTP環境でもパスワード発行を許可します。
define( 'WP_ENVIRONMENT_TYPE', 'local' );

ここまでできました?できたらパスワードの発行までやりましょう。

編集後手順

保存と終了::

  • Ctrl + O を押して Enter で保存。
  • Ctrl + Xnano エディタを終了します。

ブラウザで確認::WordPress管理画面の 「ユーザー > プロフィール」 を再度読み込み(リロード)してください。

パスワードの発行::「新しいアプリケーションパスワード名」に python-bot などの名前を入れ、発行ボタンを押してください。

発行できましたか?

できたら .envファイルを編集しましょう。念のためひな形的なのを置いておきますね。

# 1行解説: WordPressのAPI接続先URLです。
WP_URL=
# 先ほど作成した「投稿者」権限を持つユーザーのIDです。
WP_USER=
# 1行解説: 発行された16文字のパスワードを半角スペース込みで貼り付けます。
WP_PASS=

ファイルの更新はできましたか?

テストに移りましょう。API経由で投稿ができるかテストコードを下記に記載するので動かしてみましょう。

あらかじめ僕がつまった環境変数の参照エラーのハンドリングがしやすいようにテストコードの中にデバックログが表示されるようにしているので、ハンドリングの際に活用してください。

import os
import requests
from requests.auth import HTTPBasicAuth
from pathlib import Path
from dotenv import load_dotenv

env_path = Path(__file__).resolve().parent.parent / ".env"
load_status = load_dotenv(dotenv_path=env_path)

# 読み込みが成功したか(ファイルが存在したか)を画面に表示します
print(f"DEBUG: .envファイルを見つけましたか?: {env_path.exists()}")

# 環境変数がうまく読み込めているか確認するため
print(f"DEBUG: 現在実行中のファイルの場所: {__file__}")
print(f"DEBUG: 探している .env の絶対パス: {env_path}")
print(f"DEBUG: ファイルは実際に存在するか?: {env_path.exists()}")

# load_dotenvの結果も表示
load_status = load_dotenv(dotenv_path=env_path)
print(f"DEBUG: load_dotenv の読み込み成否: {load_status}")

WP_URL = os.getenv("WP_URL")
WP_USER = os.getenv("WP_USER")
WP_PASS = os.getenv("WP_PASS")

# .env から正しく値を拾えているか、実行時にターミナルへ表示させます
print(f"DEBUG - URL: {WP_URL}")
print(f"DEBUG - USER: {WP_USER}")

def testpost():
payload = {
"title": "Pythonからの自動投稿テスト",
"content": "これはAPI経由で自動投稿されたテスト記事です。",
"status": "draft"
}

response = requests.post(
WP_URL,
auth=HTTPBasicAuth(WP_USER, WP_PASS),
json=payload
)

if response.status_code == 201:
print(f"投稿成功! URL:{response.json().get('link')}")
print(response.json())
else:
print(f"失敗: {response.status_code} - {response.text}")
print(response.text)

if __name__ == "__main__":
testpost()

ファイルを実行して、以下のようになったので成功です。

私は一発では成功できませんでした笑

ただデバック用のコードがあると格段に原因の解明がしやすいという気づきがあったので、得られたものは多かったですね。

何はともあれ、これでAPI経由で投稿できることがわかりました。

とうとうここにきて、AIが生成した記事を投稿の下書きにおく段階まで来ました。

実際にコードを書き、実行してみましょう。さっき作ったコードたちも使います。

役割ごとにファイルを分離します。

下記のコードは、「AI に記事を書かせ、その結果を WP に送る」という一連の流れを指示するファイルです。後述する2つのファイルを呼びして、この作業を完結させます。

#proto_main.py
import os
from pathlib import Path
from dotenv import load_dotenv
from prototype_core import generate_article, prompt_template
from wp_handler import post_to_wordpress

env_path = Path(__file__).resolve().parent.parent / ".env"
load_dotenv(dotenv_path=env_path)

def run_automation():
title, content = generate_article(prompt_template).split('\n', 1)

success,response = post_to_wordpress(
os.getenv("WP_URL")
os.getenv("WP_USER")
os.getenv("WP_PASS")
title,
content
)

if success:
print("記事の投稿に成功しました。")

else:
print(f"記事の投稿に失敗しました。{response}")

if
__name__ == "__main__":
run_automation()

下記のファイルは、先ほど成功した WordPress への投稿機能だけを持つファイルです。

#wp_handler.py
import requests
from requests.auth import HTTPBasicAuth

#司令塔(main)から届く5つの情報を受け取って、WordPressに投稿する関数を定義します
def post_to_wordpress(wp_url, wp_user, wp_pass, title, content):
"""
WordPress REST APIを使用して記事を下書き投稿する
"""
payload = {
"title": title,
"content": content,
"status": "draft"
}
#指定されたURLへ、認証情報と記事データを一緒に送信します
response = requests.post(
WP_URL,
auth=HTTPBasicAuth(WP_USER, WP_PASS),
json=payload
)

#成功(201)したかどうかと、エラーが起きた際の内容を司令塔に報告します
if response.status_code == 201:
print(f"投稿成功! URL:{response.json().get('link')}")
print(response.json())
else:
print(f"失敗: {response.status_code} - {response.text}")
print(response.text)

#このファイルを直接実行した時だけ動くテストエリアです(import時は動きません)
if __name__ == "__main__":
print("このファイルはモジュールとして呼び出されることを想定しています。")

下記のファイルは、AI に記事を書かせる機能(プロンプト送信など)に特化したファイルです。

sample_news = {
"title": "最新のAI搭載ガジェットが発表、作業効率が200%向上か",
"url": "https://example.com/news/123",
"summary": "米テック企業が新しいスマートデバイスを発表。AIがユーザーの行動を予測し、PC作業を自動化する機能を搭載しています。",
}

prompt_template = f"""
あなたはプロのガジェットブロガーです。
以下のニュースを元に、読者がワクワクするようなブログ記事を日本語で作成してください。

【ニュース内容】
タイトル: {sample_news['title']}
URL: {sample_news['url']}
概要: {sample_news['summary']}

【出力ルール】
・読者のメリット(ベネフィット)を強調すること。
・WordPressにそのまま貼れるHTML形式(h2, pタグなど)で出力すること。
・1000文字程度のボリュームで作成すること。
"""

import os
import openai
from google import genai
from pathlib import Path
from dotenv import load_dotenv

env_path = Path(__file__).resolve().parent.parent / ".env"

load_dotenv(dotenv_path=env_path)

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")

def generate_article(prompt, provider="openai"):
client = openai.OpenAI(api_key=OPENAI_API_KEY)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": prompt}
],
)
return response.choices[0].message.content


if __name__ == "__main__":
result = generate_article(prompt_template)
print(result)

ここまで出来たら「proto_main.py」ファイルを実行します。

僕のテスト投稿は以下の画像のようになりました。ひとまず、やりたいことは成功しました!

お疲れさまでした、これにてプロトタイプの作成は完了しました。

今回は、ブログ半自動化プロジェクトの核心部である「プロトタイプの作成」を駆け抜けてきました!

エラーにぶつかったり、環境構築で足止めを食らったりと大変な部分もありましたが、無事にAIが生成した記事がWordPressに届いた瞬間は、何度経験しても嬉しいものですね。笑

今回の振り返り

  • MVP(最小限の製品)の重要性:いきなり完璧を目指さず、まずは「核」を作る。
  • セキュリティの基礎:.env や .gitignore を使って、APIキーなどの秘匿情報を守る。
  • デバッグのコツ:ログを出力することで、どこで止まっているのか「原因の切り分け」をする。
  • モジュール化:役割ごとにファイルを分けることで、管理しやすいコードを目指す。

プロトタイプが完成したことで、全体の流れが「見える化」されました。ここまで来れば、あとは各パーツをブラッシュアップしていくだけです!

次回の連載では、「自動でニュースを取得するRSSリーダーの実装」について解説していこうと思います。いよいよ「手動」の部分を削ぎ落としていく作業に入りますよ!

「自分も自動化ツールを作ってみたい!」「副業に活かしたい!」という方は、ぜひ今のうちに今回のステップまでを復習しておいてくださいね。

それでは、次回の記事もお楽しみに!最後まで読んでいただきありがとうございました!

コメント

タイトルとURLをコピーしました