見出し画像

【無料公開中】WordPressのAI自動投稿ツール(ロリポップ編)

近日中にUdemyで詳細な手順を公開予定です。このページでアナウンスいたしますのでお楽しみに。

  • 成果物



0.はじめに

✨自動投稿ブログとは何?

自動投稿ブログは、コンピュータプログラムを使って、ブログに記事を自動で書き込むシステムです。普通のブログは人が記事を書いて投稿しますが、自動投稿ブログでは、プログラムがインターネットから情報を集めてきて、それをもとに勝手に記事を作ってくれるんです。このおかげで、ブログを更新するために自分で毎回記事を書かなくても済むようになります。

🌟自動投稿ブログを使うメリット

  • 時間節約: 毎日ブログを書くのは大変ですよね。自動投稿なら、時間を節約して、他の大事なことに集中できます。

  • いつも新しい情報: プログラムが自動で情報を集めてきてくれるので、ブログの内容がいつも最新の状態を保てます。

  • 更新忘れなし: 「今日はブログを更新するのを忘れた!」なんてことがなくなります。自動で定期的に更新してくれるので、安心です。

🎈lolipopホスティングサービスとは

lolipopは、ウェブサイトをインターネット上で公開するための「スペース」を提供するサービスです。初心者でも簡単に使えるように設計されていて、手頃な値段で利用できるのが特徴です。管理画面がわかりやすく、サポートも充実しているので、ウェブサイト運営が初めての方にもおすすめです。

📊他のサービスとの違い

lolipopは特に初心者向けに作られていますが、大きなウェブサイトや複雑な設定が必要な場合には、他のホスティングサービスの方が適している場合もあります。それぞれのサービスには得意分野があるので、自分のニーズに合ったサービスを選びましょう。

🔄自動投稿スクリプトの汎用性

自動投稿スクリプトは、特定のホスティングサービスに限定されずに使えます。これは、Pythonのような一般的なプログラミング言語で書かれているからです。つまり、どんなホスティングサービスでも、このスクリプトを使ってブログを自動で更新することができるんです。


1. 前提条件

1. プログラミングの基本知識

  • Pythonに関する基礎知識: スクリプトはPythonで書かれているため、基本的なPythonの知識(変数、ループ、関数など)が必要です。

  • コードの読解と修正能力: スクリプトのカスタマイズやトラブルシューティングのために、コードを読んで理解し、必要に応じて修正できる能力が求められます。

2. レンタルサーバーの利用経験

  • サーバー管理の基本: レンタルサーバーの基本的な管理方法(ファイルのアップロード、ディレクトリ構造の理解など)に慣れていることが望ましいです。

  • SSHアクセスの経験: サーバーにSSHでアクセスし、コマンドラインで操作する経験があると有利です。

3. APIの利用経験

  • APIキーの取得と管理: OpenAIやWordPressなどのAPIキーを安全に取得し、管理する知識が必要です。

  • APIドキュメントの理解: APIの仕様や制限を理解するために、ドキュメントを読み解く能力が求められます。



2.ロリポップのアカウント作成と設定

2.1 lolipopでアカウントを作る: ステップバイステップ

  1. ウェブサイトへアクセス: lolipopの公式ウェブサイトにアクセスします。

  2. 新規登録をクリック: トップページにある「新規登録」ボタンをクリックして、登録プロセスを開始します。

  3. 情報の入力: 名前、メールアドレス、パスワードなど、必要な情報を入力します。

  4. メールでの確認: 登録したメールアドレスに確認メールが送られてきますので、メール内のリンクをクリックしてアカウントを有効化します。

2.2 ホスティングプランを選ぶ

  1. プランの種類: lolipopでは、個人ブログ用の「ライトプラン」から、ビジネス用の「スタンダードプラン」や「プレミアムプラン」まで、さまざまなプランが用意されています。

  2. プランの価格: ライトプランは月額100円から始まりますが、より高性能なプランは異なる料金設定があります。

2.3 SSHアクセスの設定と利用条件

  1. SSHとは: SSH(Secure Shell)は、サーバーに安全にアクセスし、管理作業を行うための方法です。

  2. 利用条件: SSHアクセスは、スタンダードプラン以上のユーザーのみ利用可能です。これにより、セキュリティを高めながらサーバー管理を行うことができます。

  3. SSHの設定方法: lolipopの管理画面からSSHアクセスを簡単に設定できます。

2.4 WordPressの簡単インストール

  1. WordPressの利点: WordPressは、ブログやウェブサイトを簡単に作成・管理できるシステムです。

  2. 簡単インストール: lolipopでは、数クリックでWordPressをインストールし、設定することができます。この機能により、初心者でも簡単にブログやウェブサイトを立ち上げることが可能です。

  3. インストールプロセス: lolipopの管理画面からWordPressをインストールする際に、まずテーマを選択できます。これにより、インストールがよりカスタマイズされた形で行われます。

  4. デフォルトテーマ「cocoon」の使用: 今回は、デフォルトで「cocoon」というテーマを使用します。このテーマは、見やすく使いやすいデザインを提供し、無料で利用できます。

2.5 WordPress管理画面へのアクセス

  1. ログイン情報: インストール完了後、WordPressの管理画面にログインするための情報が表示されます。

  2. 管理画面へのアクセス: 提供されたURLから管理画面にログインして、サイトを管理します。

2.6 基本設定

  1. 最低限の設定: lolipopからWordPressをインストールすると、最低限の設定がデフォルトで完了しています。これにより、初心者でもすぐにサイトを運用開始できます。

  2. 追加設定の選択: より詳細な設定を行いたい場合は、「設定」メニューからパーマリンクなどの追加設定を行うことができます。これは必須ではなく、必要に応じて行ってください。

2.7 テーマとプラグインの活用

  1. テーマのカスタマイズ: 「外観」→「テーマ」で、サイトのデザインをカスタマイズすることができます。既定の「cocoon」以外にも多くのテーマが利用可能です。

  2. プラグインの追加: 「プラグイン」→「新規追加」で、サイトの機能を拡張するプラグインを追加できます。セキュリティ、SEO、パフォーマンス向上などの目的に応じて選択してください。

2.8 独自ドメインの取得

ドメインの取得方法: lolipopのドメインサービスページから簡単にドメインを検索し、購入することができます。これは必須ではありません。



3. SSHアクセスの設定とAPIの利用

3.1 SSHアクセスの重要性

  • SSHの役割: SSH(Secure Shell)は、サーバーへの安全なリモートアクセスを可能にする技術です。これにより、サーバー上で直接ファイルを編集したり、コマンドを実行したりできます。

  • APIとの関連: SSHアクセスを有効化することで、サーバー上でAPIを使った自動投稿スクリプトを実行することが可能になります。つまり、SSHなしではAPIを活用した自動化は実現できません。

3.2 APIの基本

  • APIの概要: API(Application Programming Interface)は、異なるソフトウェア間で情報を交換するための仕組みです。Web上のデータやサービスにプログラムからアクセスする際に使用されます。

  • 自動投稿スクリプトとAPI: 自動投稿スクリプトは、APIを介して外部のデータを取得し、それを元にブログ記事を生成します。

3.3 lolipopでのSSHアクセス設定

  • プラン要件: lolipopでは、スタンダードプラン以上でSSHアクセスが利用可能です。

  • 設定手順:

    1. lolipopの管理画面にログイン。

    2. 「サーバー設定」メニューからSSHアクセスを「有効にする」を選択し保存。

3.4 SSHキーの使用

  • SSHキーによるセキュリティ強化: SSHキーは、サーバーへの安全なアクセスを提供するためのツールです。キーの生成とサーバーへの登録を行うことで、パスワードなしでのログインが可能になります。

3.5 SSHとAPIを使ったサーバー管理

  • サーバーのリモート操作: SSHを通じてサーバーにアクセスし、APIを使用する自動投稿スクリプトなどを実行します。

  • データの取得と自動化: APIを利用して外部の情報を取得し、これを自動投稿スクリプトで処理することが可能です。

3.6 初心者向けのアドバイス

  • SSHとAPIの基礎学習: SSHアクセスとAPIの利用には、基本的なコマンドライン操作とプログラミングの理解が必要です。これらの技術を学ぶことで、サーバー管理と自動化の世界が開けます



4. ローカルの環境構築

4.1 Visual Studio Codeの導入

  • VS Codeとは: Visual Studio Code(VS Code)は初心者にも扱いやすいテキストエディタで、コードの編集に最適です。

  • VS Codeのインストール:

    1. VS Code公式ウェブサイトにアクセスします。

    2. 「Download」ボタンをクリックしてインストーラーをダウンロードし、指示に従ってインストールします。

4.2 VS Code内でのターミナルの利用

  • ターミナルの基本: VS Codeには組み込みのターミナルがあり、コードの実行やその他のコマンドを簡単に実行できます。

  • ターミナルの開き方:

    1. VS Codeを開きます。

    2. メニューバーの「表示」をクリックし、「ターミナル」を選択します。

    3. ターミナルが画面下部に表示されます。

  • カレントディレクトリについて: VS Codeでターミナルを開くと、デフォルトで現在開いているプロジェクトのディレクトリがカレントディレクトリとして設定されています。これにより、そのディレクトリ内で直接コマンドを実行できます。

4.3 Pythonのインストール

  • Pythonのダウンロードとインストール:

    1. Python公式ウェブサイトにアクセスし、「Download Python」ボタンをクリックしてインストーラーをダウンロードします。

    2. ダウンロードしたインストーラーを実行し、画面の指示に従ってPythonをインストールします。この時、「Add Python to PATH」のオプションを選択することを確認してください。

4.4 Pythonスクリプトの開発

  • 新しいPythonファイルの作成:

    1. VS Codeで新しいファイルを作成するには、左上の「ファイル」メニューから「新規ファイル」を選びます。

    2. ファイルの種類を「Python」に設定し、ファイル名を付けて保存します(例:main_script.py)。

  • スクリプトの基本的な書き方:

    • Pythonファイルを開き、自動投稿機能に必要なコードを記述します。例えば、ウェブサイトからデータを取得するコードや、取得したデータを整形するコードなどです。

    • コードの書き方が不明な場合は、Pythonに関するチュートリアルやドキュメントを参照してください。

4.5 プロジェクトの保存と管理

  • プロジェクトの保存: 作成したPythonファイルは、適切な場所に保存し、プロジェクトとして管理します。ファイルを保存するには、「ファイル」メニューから「名前を付けて保存」を選択します。

  • プロジェクトの整理: さまざまなファイルやディレクトリをプロジェクト内で適切に整理し、管理しやすくします。



5-1 Pythonスクリプト

  1. このスクリプトは、最新のテクノロジーニュースを自動的に取得し、それに関連する記事を生成して、これらをWordPressサイトに投稿する自動化ツールです。記事の生成にはOpenAIのChatGPTが、画像の生成にはDALL-Eが使用されています。また、ニュースの内容はNewsAPIから取得され、適切なカテゴリやタグはAIによって決定されます。これにより、定期的に新しいコンテンツをウェブサイトに追加するプロセスが自動化されます。

  2. なお、デフォルトで2つの記事を生成するように設定しています。

  3. あなたの好みに応じて色々とカスタマイズしてください。

# main_script.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
このスクリプトはWordPressに自動的にテクノロジーニュースの記事を投稿するためのものです。
主な機能は、NewsAPIから最新のニュースを取得し、それを元に記事を生成して、
WordPressに投稿することです。
"""

import requests
from requests.auth import HTTPBasicAuth
import time
import openai
import json
import logging
import shutil 
import os
import traceback

# =====以下の変数は適宜設定してください================================================================
# WordPress APIの基本URL
base_url = "サイトのURL"

# 投稿を作成するためのエンドポイント
posts_url = f"{base_url}/wp-json/wp/v2/posts"

# メディアをアップロードするためのエンドポイント
media_url = f"{base_url}/wp-json/wp/v2/media"

# WordPress API 認証情報
username = "ここに実際のユーザー名を入力"
password = "ここに実際のパスワードを入力"#例[cCKz NnMj hLDU bz3D UMtJ QWQ2]のような形式

# ログの設定
logging.basicConfig(filename='auto_press.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')

# OpenAI ChatCompletionのAPIキー
openai.api_key = 'ここにOpenAIのAPIキーを入力'

# =================================================================================================================================



# WordPressに画像をアップロードする関数
def upload_image(image_path):
    """
    WordPressサイトに指定された画像をアップロードする関数。
    アップロードに成功すると、画像のメディアIDを返します。
    アップロードに失敗した場合は、Noneを返します。

    :param image_path: アップロードする画像のローカルパス
    :return: アップロードされた画像のWordPressメディアID
    """
    try:
        logging.info(f"Uploading image to WordPress: {image_path}")
        files = {'file': (image_path, open(image_path, 'rb'), 'image/png')}
        response = requests.post(media_url, files=files, auth=HTTPBasicAuth(username, password))
        # print("Response Status Code:", response.status_code)
        # print("Response Body:", response.text)

        open(image_path, 'rb').close()  # ファイルストリームを閉じる

        if response.status_code == 201:
            image_id = response.json().get("id")  # 画像のIDを取得
            return image_id
        else:
            logging.error(f"Image upload failed: {response.status_code}, {response.text}")
            raise Exception(f"Image upload failed: {response.status_code}, {response.text}")
    except Exception as e:
        logging.error(f"Exception in upload_image: {e}\n{traceback.format_exc()}")
        return None

# カテゴリーの設定・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・

# WordPressからすべてのカテゴリを取得する関数
def get_wordpress_categories():
    """
    WordPressサイトからすべてのカテゴリを取得する関数。
    成功するとカテゴリのリストを返し、失敗すると空のリストを返します。

    :return: カテゴリのリスト
    """
    categories_url = f"{base_url}/wp-json/wp/v2/categories"
    response = requests.get(categories_url, auth=HTTPBasicAuth(username, password))
    if response.status_code == 200:
        return response.json()
    else:
        logging.error(f"Failed to fetch categories: {response.text}")
        return []

# カテゴリを作成する関数
def create_category(category_name):
    """
    新しいカテゴリをWordPressサイトに作成する関数。
    作成に成功すると、カテゴリのIDを返します。
    作成に失敗した場合はNoneを返します。

    :param category_name: 作成するカテゴリの名前
    :return: 作成されたカテゴリのID
    """
    category_data = {
        "name": category_name
    }
    response = requests.post(f"{base_url}/wp-json/wp/v2/categories", json=category_data, auth=HTTPBasicAuth(username, password))
    if response.status_code in [200, 201]:
        return response.json().get('id')
    else:
        logging.error(f"Failed to create category: {response.status_code}, {response.text}")
        return None

# AIによるカテゴリ決定の関数を更新
def determine_category_with_ai(title, content):
    """
    AI(OpenAI)を使用して、与えられた記事の内容に基づいて最適なカテゴリを決定する関数。
    AIの提案が適切であればそのカテゴリIDを返し、不明瞭な場合はデフォルトカテゴリを作成してそのIDを返します。

    :param title: 記事のタイトル
    :param content: 記事の内容
    :return: 決定されたカテゴリのID
    """
    categories = get_wordpress_categories()

    try:
        prompt = f"次の記事の最も適切かつ簡潔な単語のみで日本語カテゴリーを決定してください:\nタイトル: {title}\n内容: {content}\n利用可能なカテゴリー: {', '.join([cat['name'] for cat in categories])}"
        response = openai.ChatCompletion.create(
            model="gpt-4-1106-preview",
            messages=[
                {"role": "system", "content": "あなたは内容を理解しカテゴライズすることができるAIアシスタントです。"},
                {"role": "user", "content": f"{prompt}:余計な文章は出力せず、単語のみで出力すること"}

            ],
            temperature=0.5,
            max_tokens=60,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        print("カテゴリー:",response)
        suggested_category_name = response.choices[0].message.content.strip()
        if suggested_category_name and suggested_category_name.lower() != "none":
            # 既存のカテゴリの中から適切なIDを見つけるか、新しいカテゴリを作成
            for category in categories:
                if category['name'].lower() == suggested_category_name.lower():
                    return category['id']
            else:
                return create_category(suggested_category_name)

        # AIの提案が不明瞭な場合、デフォルトカテゴリー「雑記」を使用
        return create_category("雑記")

    except Exception as e:
        logging.error(f"Failed to determine category with AI: {e}")
        return create_category("エラー")


# タグの設定・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
def get_wordpress_tags():
    """
    WordPressサイトからすべてのタグを取得する関数。
    成功するとタグのリストを返し、失敗すると空のリストを返します。

    :return: タグのリスト
    """
    tags_url = f"{base_url}/wp-json/wp/v2/tags"
    response = requests.get(tags_url, auth=HTTPBasicAuth(username, password))
    if response.status_code == 200:
        return response.json()
    else:
        logging.error(f"Failed to fetch tags: {response.text}")
        return []

def determine_tags_with_ai(title, content, tags):
    """
    AI(OpenAI)を使用して、与えられた記事の内容に基づいて最適なタグを決定する関数。
    AIの提案に基づいてタグのリストを作成し、それを返します。

    :param title: 記事のタイトル
    :param content: 記事の内容
    :param tags: 利用可能なタグのリスト
    :return: 決定されたタグのIDのリスト
    """
    try:
        prompt = f"次の記事の最も適切なタグを必ず日本語で4つ決定してください:\nタイトル: {title}\n内容: {content}\n利用可能なタグ: {', '.join([tag['name'] for tag in tags])}"

        response = openai.ChatCompletion.create(
            model="gpt-4-1106-preview",
            messages=[
                {"role": "system", "content": "あなたは内容を理解しタグ付けすることができるAIアシスタントです。"},
                {"role": "user", "content": prompt}
            ],
            temperature=0.2,
            max_tokens=60,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        print("タグ:" ,response)

        # AIの応答からタグを分離
        suggested_tags = response.choices[0].message.content.strip().split('\n')
        tag_ids = []

        for suggested_tag in suggested_tags:
            # 数字とピリオドを取り除く
            tag_name = suggested_tag.split('. ', 1)[-1].strip()
            for tag in tags:
                if tag['name'].lower() == tag_name.lower():
                    tag_ids.append(tag['id'])
                    break
            else:
                # 新しいタグを作成し、そのIDをリストに追加
                new_tag_id = create_tag(tag_name)
                if new_tag_id:
                    tag_ids.append(new_tag_id)

        return tag_ids
    except Exception as e:
        logging.error(f"Failed to determine tags with AI: {e}")
        return []


def create_tag(tag_name):
    """
    新しいタグをWordPressサイトに作成する関数。
    作成に成功すると、タグのIDを返します。
    作成に失敗した場合はNoneを返します。

    :param tag_name: 作成するタグの名前
    :return: 作成されたタグのID
    """
    tag_data = {
        "name": tag_name
    }
    response = requests.post(f"{base_url}/wp-json/wp/v2/tags", json=tag_data, auth=HTTPBasicAuth(username, password))
    if response.status_code in [200, 201]:
        return response.json().get('id')
    else:
        logging.error(f"Failed to create tag: {response.status_code}, {response.text}")
        return None

# 投稿を作成する関数・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
    
# NewsAPIから最新のテクノロジーニュースを取得
def fetch_technology_news():
    """
    NewsAPIを使用して最新のテクノロジーニュースを取得する関数。
    成功するとニュースのリストを返し、失敗すると空のリストを返します。

    :return: ニュースのリスト
    """
    print("Fetch technology news")
    logging.info("Fetching the latest technology news")
    api_key = "実際のAPIキーを入力"
    url = f"https://newsapi.org/v2/top-headlines?category=technology&apiKey={api_key}"
    response = requests.get(url)
    print("Response", response)
    
    if response.status_code == 200:
        articles = response.json().get('articles', [])
        filtered_articles = []

        # 最初の2つの記事だけを処理
        for article in articles[:2]:
            title = article['title']
            description = article.get('description', '')
            print("translate呼び出し前")
            translated_title = translate_to_japanese_with_openai(title)
            filtered_articles.append((translated_title, description))
            print("translate呼び出し後")

        return filtered_articles
    else:
        print("Fetch technology news失敗")
        logging.error(f"Failed to fetch news: {response.text}")
        return []

def translate_to_japanese_with_openai(text):
    """
    OpenAIを使用して与えられたテキストを日本語に翻訳する関数。
    翻訳に成功すると翻訳されたテキストを返し、失敗すると元のテキストを返します。

    :param text: 翻訳するテキスト
    :return: 翻訳されたテキスト
    """
    print("translate_to_japanese_with_openaiスタート")
    try:
        response = openai.ChatCompletion.create(
            model="gpt-4-1106-preview",
            messages=[
                {"role": "system", "content": "あなたは多言語に対応できる翻訳者です"},
                {"role": "user", "content": f"Translate the following text to Japanese:\n{text}"}
            ],
            temperature=0.2,
            max_tokens=100,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )

        translated_text = response.choices[0].message.content
        print("translated_text", translated_text)
        return translated_text.strip()
    except Exception as e:
        print("翻訳失敗!!")
        logging.error(f"Failed to translate text: {e}")
        print("!!!!!!!!!!!!", text)
        return text  # 翻訳に失敗した場合は元のテキストを返す



# OpenAI ChatGPTを使って記事を生成
def generate_article(title, description):
    """
    OpenAIのChatGPTを使用して、与えられたタイトルと説明から記事を生成する関数。
    記事の生成に成功すると生成された記事のテキストを返し、失敗するとNoneを返します。

    :param title: 記事のタイトル
    :param description: 記事の説明
    :return: 生成された記事のテキスト
    """
    try:
        print("Generating article-----start")
        logging.info("Generating article using OpenAI ChatGPT")
        combined_prompt = f"Title: {title}\nDescription: {description}\n\nWrite an article about this news:"
        print("responseの直前")
        response = openai.ChatCompletion.create(
            model="gpt-4-1106-preview",
            messages=[
                {"role": "system", "content": "あなたは優秀な日本語webライターです"},
                {"role": "user", "content": f"原文:{combined_prompt}"},
                {"role": "user", "content": """指示文:
                    ---

                    **絶対に守ること**: 「文頭と、文末には「```」を使用しないこと(絶対厳命)」
                 
                    **指示用プロンプト**
                 

                    1. **主題の特定と明確化**:「提供された原文の主題を特定し、その主題に関連する内容に焦点を当てて要約してください。主題とその重要な要素を明確にすることが重要です。**ただし、内容は深く掘り下げ、読みやすく長い文章にするよう心がけること**」

                    2. **読者層の考慮**:「様々な読者層を意識し、内容を調整してください。記事がターゲットとする読者(例:初心者、中級者、専門家など)に合わせて言い回しや内容の深さを調整します。」

                    3. **要約と言い換え**:「原文を要約し、複雑な表現や専門用語を簡潔でわかりやすい言葉に言い換えてください。内容の本質を失わないよう注意してください。」

                    4. **個人情報の扱い**:「原文中の個人情報は、サンプルのように変更して、プライバシーを保護するようにしてください。」

                    5. **最終的な形式**:「あなたの出力は最終的にHTML形式でなければなりません。**指示者に対して余計な補足は無用**」

                    6. **プログラミングコードの扱い**:「プログラミングのコードを含む場合は、マークダウン形式で記述してください。例えば:」

                    ```bash
                    # コードのタイトル
                    コード
                    # 別のコードのタイトル
                    コード2
                    ```

                    7. **見出しと構成の適用**:「記事を論理的かつ明瞭に構成し、適切な見出しを用いてセクションごとに整理してください。HTMLでの見出しは `<h1>`, `<h2>`, `<h3>` タグを適切に使用します。」

                    8. **信頼性の確保**:「情報の正確性と信頼性を確保し、可能な限りソースを明記してください。情報の出所が不明な場合は、その旨を読者に伝えるか、確認を行ってください。」

                    9. **視覚的要素の利用**:「関連する画像やグラフィックを使用して、テキストを補完し、視覚的に魅力的にしてください。」

                    10. **読者とのインタラクション**:「読者に質問を投げかけたり、コメントを求めたりするなどして、読者との対話を促進してください。」

                    11. **締めくくりと次のステップの提供**:「結論を明確にし、読者に対して次に取るべきステップ(例:関連記事へのリンク、購読の促進など)を示してください。」

                    12. **本文の長さ**:「文字数を必ず3000字程度にすること。原文のコンテンツでは情報が不足する場合は適宜補足追加していくもの。」

                    13. **HTMLフォーマットへの変換**:
                        - 「記事をHTML形式に変換し、適切なタグを使用して構造化してください。」
                        - **段落の構成**:「各段落は `<p>` タグで囲んでください。」
                        - **リンクの挿入**:「関連する外部サイトや他のブログ記事へのリンクは `<a href="URL">リンクテキスト</a>` 形式で挿入してください。」
                        - **画像の埋め込み**:「画像は `<img src="画像のURL" alt="画像の説明">` の形式で記事に挿入し、全ての画像には適切なaltテキストを付けてください。」
                        - **リストの使用**:「箇条書きは `<ul>` タグ、番号付きリストは `<ol>` タグを使用し、各項目は `<li>` タグで囲んでください。」
                        - **体裁**: 「文頭と、文末には「```」を使用しないこと(絶対厳命)」
                    ---

                    """}
                    ],
            temperature=0.2,
            max_tokens=2000,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        print("Generating article-----end")
        return response.choices[0].message.content
    except Exception as e:
        logging.error(f"Exception in generate_article: {e}\n{traceback.format_exc()}")
        ("AIによる記事生成失敗")
        return None

# OpenAI DALL-Eを使って画像を生成
def generate_image(title, description):
    """
    OpenAIのDALL-Eを使用して、与えられたタイトルと説明から関連する画像を生成する関数。
    画像の生成に成功すると生成された画像のURLを返し、失敗するとNoneを返します。

    :param title: 記事のタイトル
    :param description: 記事の説明
    :return: 生成された画像のURL
    """
    try:
        print("Generating image")
        logging.info("Generating image using OpenAI DALL-E")
        combined_prompt = f"Title: {title}\nDescription: {description}\n\nCreate an image based on this news:(Create a graphical illustration in a modern and engaging style, suitable for a wide range of audiences including beginners and intermediate users. The design should be clear, visually appealing, and easy to understand. Each element of the illustration should be distinct and visually distinctive, with a focus on modern aesthetics and engaging visuals. The style should be consistent and can be applied to various content themes)"
        
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {openai.api_key}"
        }
        api_data = {
            "model": "dall-e-3",
            "prompt": combined_prompt,
            "n": 1,
            "size": "1024x1024"
        }
        response = requests.post(
            'https://api.openai.com/v1/images/generations',
            headers=headers,
            data=json.dumps(api_data)
        )
        response.raise_for_status()
        image_data = response.json()
        if response.status_code != 200:
            logging.error(f"Failed to generate image: {response.status_code}, {response.text}")
            return None
        return image_data['data'][0]['url']
    except Exception as e:
        logging.error(f"Exception in generate_image: {e}\n{traceback.format_exc()}")
        return None
    
def download_image(image_url):
    """
    与えられたURLから画像をダウンロードし、ローカルに保存する関数。
    ダウンロードに成功すると保存された画像のファイルパスを返し、失敗するとNoneを返します。

    :param image_url: ダウンロードする画像のURL
    :return: ダウンロードされた画像のファイルパス
    """
    print("download_image")
    response = requests.get(image_url, stream=True)
    if response.status_code == 200:
        # 現在のタイムスタンプをファイル名に追加
        timestamp = int(time.time())
        file_path = f"downloaded_image_{timestamp}.png"
        with open(file_path, 'wb') as out_file:
            shutil.copyfileobj(response.raw, out_file)
        return file_path
    else:
        logging.error(f"Failed to download image: {response.status_code}, {response.text}")
        return None

# 定期的にテクノロジーニュースを取得してWordPressに投稿する関数
def scheduled_news_fetch():
    """
    定期的にテクノロジーニュースを取得し、WordPressに記事を投稿する関数。
    NewsAPIを使用して最新のニュースを取得し、それに基づいて記事を生成、
    さらに関連する画像も生成して、これらをWordPressに投稿します。

    """
    print("scheduled_news_fetch")

    logging.info("Scheduled news fetch started")
    print("ニュースアイテム呼び出し前!!!!!")
    news_items = fetch_technology_news()
    print("ニュースアイテム呼び出し後!!!!!",news_items)

    for title, description in news_items:
        # ニュースのタイトルと説明を組み合わせたプロンプトで記事を生成
        article = generate_article(title, description)

        # ニュースのタイトルと説明を組み合わせたプロンプトでDALL-Eに画像を生成
        image_url = generate_image(title, description)

        # 生成された画像をアップロードし、WordPressに記事を投稿
        uploaded_image_url = upload_image(image_url)
        print("scheduled_news_fetchでポスト呼び出し")
        post_article_to_wordpress(title, article, uploaded_image_url)

# /////////////////////////////////////////////////////////////////////////////////////////////////////////
# wordpress投稿全体像
def main():
    try:
        logging.info("Running the news fetch and post process")
        tags = get_wordpress_tags()
        news_items = fetch_technology_news()

        if news_items:
            for news_item in news_items[:2]:
                translated_title, description = news_item
                article = generate_article(translated_title, description)

                if article:
                    image_url = generate_image(translated_title, description)
                    local_image_path = download_image(image_url)

                    if local_image_path:
                        image_id = upload_image(local_image_path)
                        post_article_to_wordpress(translated_title, article, image_id, tags)
                        os.remove(local_image_path)
    except Exception as e:
        logging.error(f"An error occurred: {e}")

# WordPressに記事を投稿する関数
def post_article_to_wordpress(title, content, image_id, tags):
    """
    WordPressサイトに記事を投稿する関数。
    与えられたタイトル、内容、画像ID、タグを使用して記事を投稿します。
    投稿に成功すると、投稿された記事のJSONデータを返し、
    失敗するとNoneを返します。

    :param title: 記事のタイトル
    :param content: 記事の内容
    :param image_id: 記事に添付する画像のメディアID
    :param tags: 記事に適用するタグのIDリスト
    :return: 投稿された記事のJSONデータ
    """
    print("wordpressへ投稿開始")
    category_id = determine_category_with_ai(title, content)
    tag_ids = determine_tags_with_ai(title, content, tags)

    data = {
        "title": title,
        "content": content,
        "status": "publish",
        "featured_media": image_id,
        "categories": [category_id] if category_id else [],
        "tags": tag_ids
    }

    response = requests.post(posts_url, json=data, auth=HTTPBasicAuth(username, password))

    if response.status_code == 201:
        logging.info("Article posted successfully")
        print("投稿成功")
        return response.json()
    else:
        logging.error(f"Failed to post article: {response.status_code}, {response.text}")
        return None

# ///////////////////////////////////////////////////////////////////////////////////////////////////////// 
# スクリプトの実行開始点
if __name__ == "__main__":
    main()

5-2 ブログ投稿スクリプトの設定

このセクションでは、自動投稿ブログのためのPythonスクリプト(main_script.py)の設定方法を詳しく説明します。

5-2.1 スクリプトとは?

  • スクリプト: パソコンに特定の作業を自動で行わせるための指示書です。このスクリプトは、ウェブ上からニュースを集めてブログ記事を自動生成し、WordPressに投稿する作業を自動化します。

5-2.2 スクリプトのダウンロードと設定

  1. スクリプトのダウンロード: 5-1から**main_script.py**をコピーし、パソコンの分かりやすい場所にmain_script.pyという名前で保存します。vscodeからファイルを新規作成してコードをコピペすれば良いでしょう。

  2. APIキーの取得と費用:

    • NewsAPIのキーは無料で取得できます。NewsAPIのウェブサイトにアクセスして、アカウントを作成し、APIキーを取得します。

    • OpenAIのAPIキーの取得にはクレジットカード情報の登録が必要です。有料になりますので、OpenAIのウェブサイトで詳細を確認し、必要に応じてアカウントを作成し、APIキーを取得します。

  3. スクリプトへのAPIキーの設定:

    • ダウンロードした**main_script.py**をテキストエディタ(例: メモ帳、VS Codeなど)で開きます。

    • スクリプト内にある**openai.api_key = 'ここにOpenAIのAPIキーを入力'**という行を探します。

    • **'ここにOpenAIのAPIキーを入力'**の部分を、取得したOpenAIのAPIキーで置き換えます。

  4. WordPressのAPI認証情報の設定:

    • WordPressサイトのダッシュボードから「ユーザー」→「プロフィール」に進み、「アプリケーションパスワード」セクションを見つけます。

    • 新しいアプリケーションパスワードを作成し、スクリプトの**username = 'ユーザー名'password = 'パスワード'**の部分にそれぞれ入力します。

5-3 スクリプトのテストと実行

5-3.1 ローカルでのテスト

スクリプトが正しく機能するかを確認するために、まずは自分のパソコンでテストを行います。

  1. VS Codeでスクリプトを開く:

    • VS Code(Visual Studio Code)を開きます。

    • 「ファイル」メニューから「ファイルを開く」を選び、ダウンロードした**main_script.py**を開きます。

  2. ログファイルの設定:

    • スクリプトが実行中に生成するログ(実行記録)を保存するためのファイルを作成します。スクリプトの同じフォルダ内に**auto_press.log**という名前の空のテキストファイルを新規作成します。

  3. 仮想環境の確認とパスを通す:

  • Visual Studio Code(VSCode)を開いて、main_script.pyをファイルとして開きます。

  • ローカルでテストする前に、VSCodeのターミナルを開き、仮想環境が有効になっていることを確認します。

  • 仮想環境が有効でない場合は、以下のコマンドを使用して仮想環境に入ります。

 # Linux or macOS
source venv/bin/activate

 # Windows
\\\\venv\\\\Scripts\\\\activate

仮想環境が有効になったら、以下のコマンドでスクリプトを実行します。スクリプトが正しく動作すれば、テストは成功です。

python main_script.py

5-3.2 サーバーへのアップロード

ローカルでのテストが成功したら、スクリプトをサーバーにアップロードし、実際のウェブサイトで自動投稿を開始します。

  1. サーバーへの接続:

  • ロリポップ!FTPを使用する場合:

    • ダッシュボード内で「サーバーの管理・設定 → ロリポップ!FTP」にアクセスします。

    • 新しいFTPアカウントを作成します。FTPアカウントには、サーバーへの接続に使用する情報が含まれます。

    • ロリポップ!FTPにアクセスすると「wordpress」というフォルダと、「welcome.html」というファルルの二つがあります。このディレクトリに「auto_press」という名前のフォルダを作成し、その配下に「main_script.py」と「auto_press.log」を配置してください。

    • この際、auto_press、main_script.py、auto_press.logの属性は「すべてのアクセスを許可するため、777と設定してください」

    • セキュリティに警戒される場合は、設定ファイルの使用しましょう。APIキー、ユーザー名、パスワードなどの機密情報をスクリプト内に直接記述するのはセキュリティ上のリスクがあります。これらの情報は、外部の設定ファイル(例えば**.env**)に保存し、スクリプトで読み込むようにすると良いでしょう。


その他SSH/FTPクライアントの利用:

SSHまたはFTPクライアントを使ってサーバーに接続します。Windowsでは「PuTTY」や「WinSCP」、Macでは「Terminal.app」や「Cyberduck」が一般的です。
サーバーへのログイン: ホスティングサービスから提供されたサーバーのアドレス、ユーザー名、パスワードを使用してログインします。
ディレクトリの確認: サーバー上で、スクリプトを配置する適切なディレクトリ(通常はウェブルートディレクトリ)を見つけます。
ファイルの転送: **main_script.pyauto_press.log**ファイルを選択し、サーバーの適切なディレクトリにドラッグ&ドロップして転送します。
その後はファイルのアクセス設定は許可としてください。

5-4 サーバー上でのスクリプト実行

5-4.1 ロリポップサーバーへのSSHアクセス

Visual Studio Code (VSCode) のターミナルを使用してロリポップサーバーにSSHでアクセスする方法は以下の通りです。

  • SSHアクセスのコマンド:

    • VSCodeのターミナルを開きます。

    • 次に、以下のコマンドを入力してロリポップサーバーに接続します。

ssh アカウント名@ssh.lolipop.jp -p 2222

プロンプトが表示されたら、
ロリポップサーバーで設定されているSSHパスワードを入力します。
パスワードはターミナル上では表示されませんのでコピペで対応すれば間違いは起こりません。

5-4.2 Python3と必要なライブラリのインストール

ロリポップサーバーにPython3と必要なライブラリをインストールする手順は以下の通りです。

  • Python3の確認:

    • まず、サーバーにPython3がインストールされているかを確認します。

    • もしインストールされていない場合は、ロリポップのサポートまたはドキュメントを参照してインストールしてください。

python3 --version
  • pipのインストール:

  • Python3がインストールされている場合、pip(Pythonのパッケージマネージャー)もインストールされているはずです。もしインストールされていない場合は、以下のコマンドでインストールします。

python3 -m ensurepip
  • 必要なライブラリのインストール:

  • 必要なライブラリをインストールします。例えば、requestsとopenaiライブラリをインストールするには、以下のコマンドを使用します。

pip install requests openai==0.28.0

5-4.3 スクリプトの実行

  • スクリプトがあるディレクトリへの移動:

    • スクリプトが保存されているディレクトリに移動します。アカウント名はあなたのロリポップアカウント名に置き換えてください。

cd /home/users/1/アカウント名/web/auto_press

スクリプトを実行するには、以下のコマンドを使用します。

python3 main_script.py

これらの手順に従って、ロリポップサーバー上でPythonスクリプトを実行する準備が整います。VSCodeのターミナルを使用することで、ローカル環境と同様の操作感でサーバー上での作業が可能になります。また、サーバーへのアクセスやライブラリのインストールには十分注意してください。

5-4.4 実行結果の確認

  • 成功の確認: コマンドラインに「投稿成功」と表示されれば、スクリプトの実行は成功です。

  • エラーのトラブルシューティング: エラーメッセージが表示された場合は、メッセージを読み解き、問題を解決する必要があります。

  • ウェブサイトでの確認: ウェブブラウザを開き、自分のウェブサイトにアクセスして、新しい記事が投稿されているかを確認します。


  1. サーバーでの実行:

    • サーバーのコマンドラインインターフェース(CLI)を使用し、コマンドでスクリプトを実行します。

    • サーバー上でも同様に、エラーがなければ投稿成功です。

python main_script.py

定期実行の設定: サーバー上でスクリプトを定期的に実行するように設定します(詳細は次のセクションで説明)。



6. 定期実行の設定

6.1 Cronジョブについて

Cronジョブは、UNIX系オペレーティングシステムで使用される時間ベースのジョブスケジューラです。このツールを使用すると、特定の時間や間隔で自動的にスクリプトやコマンドを実行することができます。例えば、毎日特定の時刻にデータベースをバックアップする、毎週特定のスクリプトを実行するなどのタスクを自動化できます。
Cronジョブは自動化と定期的なタスクの管理に非常に重要です。この機能により、手動で繰り返し作業を行う必要がなくなり、時間と労力を節約できます。

6.2 lolipopサーバーでのCronジョブ設定方法

lolipopサーバーでCronジョブを設定し、特定のPythonスクリプトを定期的に実行する手順は以下の通りです:

  1. Cronジョブ設定にアクセス:

    • lolipopサーバーの管理パネルにログインします。

    • 「サーバー設定」または「サーバー管理」セクションに移動し、「Cronジョブ」または「定期実行」の設定オプションを探します。

  2. 新しいCronジョブを作成:

    • 「新しいCronジョブを追加」または「Cronジョブを作成」のようなオプションを選択します。

    • スクリプトを実行する頻度を設定します(例:毎日午前3時)。

  3. コマンドの指定:

    • 実行するパスを指定します。auto_press/main_script.pyのように記述します。スクリプトがサーバー上にある正確な位置を示す必要があります。

  4. 設定の保存:

    • 設定を保存し、Cronジョブが有効になることを確認します。

  5. ログの確認:

    • lolipopサーバーでは、Cronジョブの実行結果をログファイルに記録することができます。エラーが発生した場合に備えて、ログファイルの場所と内容を確認しておきます。

6.3 注意点

  • スクリプトのパスやコマンドが正確であることを確認してください。

  • lolipopサーバーのバージョンや設定によっては、Cronジョブの設定方法が若干異なる場合があります。必要に応じてサポートドキュメントを参照してください。

  • 定期実行によるサーバーの負荷を考慮し、実行頻度を適切に設定してください。



7. トラブルシューティング

自動化スクリプトの運用中には様々な問題が発生する可能性があります。以下では、よくある問題とその解決方法について説明します。

7.1 問題1: スクリプトが実行されない

  • 原因:

    • ファイルパスが間違っている。

    • 必要なライブラリがインストールされていない。

    • 実行権限がない。

  • 解決策:

    • 正しいファイルパスを確認してください。

    • 必要な依存関係をインストールします(例:pip install requests)。

    • スクリプトに実行権限を与えます(例:chmod +x script.py)。

7.2 問題2: APIリクエストが失敗する

  • 原因:

    • APIキーが間違っている、または期限切れ。

    • サーバーのエラー。

  • 解決策:

    • APIキーが正しいか確認し、必要に応じて更新してください。

    • サーバーの状態を確認し、一時的な問題であればしばらく待ってから再試行してください。

7.3 問題3: WordPressへの投稿ができない

  • 原因:

    • WordPressの認証情報が間違っている。

    • WordPressのAPIが変更された。

  • 解決策:

    • 認証情報が正しいか確認し、必要に応じて更新してください。

    • WordPressのAPIドキュメントを確認し、必要な変更をスクリプトに反映してください。

7.4 問題4: 予期しないエラー

  • 原因:

    • スクリプトのバグ。

    • 外部サービスの変更や停止。

  • 解決策:

    • エラーログを確認し、スクリプトのコードをデバッグしてください。

    • 外部サービスの状態を確認し、アプリケーションをそれに合わせて調整してください。



8. まとめ

自動投稿ブログシステムを導入することには多くのメリットがあります。時間と労力の節約はもちろん、一貫したコンテンツの提供が可能になり、ウェブサイトのトラフィックとエンゲージメントを向上させることができます。しかし、自動化システムは適切な管理とメンテナンスが必要です。スクリプトの定期的な更新と監視、外部サービスの変更に対する迅速な対応が成功の鍵です。
今後の運用においては、次のポイントに注意してください:

  • 定期的なメンテナンス:スクリプトの更新とサーバーの状態を定期的にチェックします。

  • 監視:エラーログを監視し、問題が発生した場合は迅速に対応します。

  • 内容の質:自動生成されたコンテンツも、ユーザーにとって価値があることを確保します。

  • 適応と改善:外部サービスやAPIの変更に柔軟に対応し、スクリプトを改善し続けます。

この記事が気に入ったらサポートをしてみませんか?