Python

Python ChatGPTを活用してブログを完全自動化:【記事自動作成、自動投稿】②

この記事は、ChatGPTのAPIをPythonから利用し、「ブログ記事を自動で生成させ、更にWordpressへ自動投稿してしまおう!」という、ブログの運営者にとって夢の様なチュートリアルの第二回目です!!

前回の記事で、ChatGPTはPythonを介してAPIを利用できるようになっていると思います。
今回の記事では、ブログに最適化された質問をChatGPTに送信し、最適な回答を得る方法について説明し、さらにChatGPTからの返答をHTMLと組み合わせて投稿可能な状態にする方法について解説したいと思います。

読者に読まれる最適なブログ記事構成とは

アフィリエイトブログをやられている方や、文章が得意な方は常に最適な記事構成を意識してブログを書かれているかと思います。私は文章が下手なので、一般的な記事構成しか提示できませんが、下記のような記事構成が最適だと言われています。

最適な記事構成
  1. タイトル – 記事の主題を明確に表現する。
  2. 導入 – 読者に興味を引く情報を提供し、記事の内容や目的を明示する。
  3. 問題の説明 – 解決すべき問題や課題を説明する。
  4. 解決策の提案 – 問題を解決するための提案や解決策を示す。
  5. 顧客の声や評価 – 実際の顧客の声や商品の評価を引用し、信頼性を高める。
  6. 製品の紹介 – アフィリエイト商品やサービスの詳細を説明する。
  7. 利用シーンや具体的な例 – 商品やサービスの具体的な使用シーンや例を示す。
  8. 価格や割引情報 – 商品やサービスの価格や割引情報を説明する。
  9. ボタンやリンク – 購入や詳細を促すボタンやリンクを設置する。
  10. おすすめ理由や特典 – 商品やサービスのおすすめ理由や特典を説明する。
  11. FAQ – よくある質問や疑問に対する回答をまとめる。
  12. 結論 – 記事の内容をまとめ、再度商品やサービスの利点を強調する。
  13. 免責事項 – アフィリエイトリンクを含む記事に免責事項を追加する。

免責事項については必要なら入れる感じで良いかと思います。上記はアフィリエイトブログによくある構成ですが、通常のブログでも読者が何を知りたいのかを伝えることが大切なので、「問題提起 → 問題の説明 → 解決策 → まとめ」は最低限必要です。

今回は、上記のアフィリエイトブログの構成をChatGPTに自動で作ってもらうという流れで解説します。

少し内容を変更する事で、どんな形式のブログでも作れるかと思います。

API呼び出し部分を関数化

前置きが長くなってしまいましたが、早速スタートしましょう!
まずは前回、Pythonプロンプトから実行したコードを関数化して再利用性の高い形に変更しましょう。

ファイルの作成

まずはターミナルを開き、ディレクトリと.pyファイルを作成します。

mkdir openai # ディレクトリ名はなんでも良いです。
cd openai
touch makeBlog.py # ファイル名はなんでも良いです。

GUIで作成していただいても構いません。

例では、「openai」というフォルダを作成して、その中に「makeBlog.py」というファイルを作成しました。

関数を作成

makeBlog.pyを開いて、下記のコードを書き写してください。

import openai # openai のインストールに失敗しているとここでエラーが出ます。 

# openAIへAPIリクエストを投げて、レスポンスを返却するクラス
def getOpenAIResponse(question):
    openai.api_key = "sk-<your secret key>" # 取得したAPIキーを入力
    print(question) # debug
    
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=question,
        max_tokens=1000,
        echo=False
    )
    
    responsetext = response['choices'][0]['text'].replace('\n', '')
    print(responsetext) # debug
 
    return responsetext

前回Pythonプロンプトで実行した内容を関数に置き換えた形が上記になります。

getOpenAIResponse関数へ引数questionを渡して呼び出すと、関数内でChatGPTへAPIリクエストを送り、応答のテキスト部分を、response[‘choices’][0][‘text’].replace(‘\n’, ”) で改行文字を無くした状態で返却する様になっています。

上記のコードに関数の呼び出しを追加して、確認してみましょう。

import openai # openai のインストールに失敗しているとここでエラーが出ます。 

# openAIへAPIリクエストを投げて、レスポンスを返却するクラス
def getOpenAIResponse(question):
    openai.api_key = "sk-<your secret key>" # 取得したAPIキーを入力
    print(question) # Debug
    
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=question,
        max_tokens=1000,
        echo=False
    )
    
    response_text = response['choices'][0]['text'].replace('\n', '')
    print(response_text) # Debug
 
    return response_text

# ここから追加
question = "これはテストです。何か文章を作って返してください。"
response = getOpenAIResponse(question)

print("--- 以下、Debug出力 ---")
print(response)

次の様に、ターミナル若しくはコマンドプロンプトから実行して出力を確認してください。

python makeBlog.py

# 私は下記の様な出力になりました。

これはテストです。何か文章を作って返してください。
美しい日差しが空を染めている、この穏やかな日を楽しもうと思います。
--- 以下、Debug出力 ---
美しい日差しが空を染めている、この穏やかな日を楽しもうと思います。

上の2行は関数内のprint文で出力されています。
「— 以下、Debug出力 —」以降が関数を呼び出したメイン部分の出力です。

上記の結果から、引数で私た質問文と、ChatGPTから返ってきた返答がメイン部分と関数部分で受け渡しできている事が分かります。

HTMLの簡単な解説

HTMLの詳細を解説しようとすると、とても1記事にまとめる事は出来ないので、簡単に解説します。

HTML(HyperText Markup Language)とは、ウェブページの構造やコンテンツを書くためのマークアップ言語です。ウェブブラウザはHTMLコードを解釈し、ウェブページを表示するために使用されます。

HTMLは、タグ(< >で囲まれた要素)を使用して要素を囲います。タグで囲うことにより、ブラウザはテキスト、画像、リンク、見出し、段落などの異なる要素を判別して、それぞれの適切な表示方法でブラウザに表示しています。。

ブログの記事構成には大きく分けて、見出し・本文・リンクがあります。また引用文などもあります。最低限、その部分のHTMLを理解していれば今回は問題ありません。

記事の自動作成に最低限必要なHTMLタグ
  1. <h1>〜<h6>: 見出しを定義するためのタグ。<h1>が最も重要な見出しで、<h6>が最も小さな見出しとなります。
  2. <p>: 段落を定義するためのタグ。テキストをまとめて段落ごとに表示する際に使用します。
  3. <blockquote>: 引用文を定義するためのタグ。通常は文の左側に垂直な線が表示され、引用部分を視覚的に区別するために使用されます。
  4. <strong>: テキストを強調するためのタグ。通常は太字で表示され、重要なキーワードや文を強調するために使用します。
  5. <a>: リンクを作成するためのタグ。href属性を使用してリンク先のURLを指定し、クリック可能なテキストや画像を作成します。

簡単な例で説明します。

<h1>こんにちは、これはタイトルです。</h1>
<p>これは、文章の段落を表しています。</p>
<a href="リンク先のURL">これはリンクです。</a>

</h1> </a> </p>はそれぞれの終了タグと呼ばれます。タグはブラウザには表示されず、タグの種類に応じて、タグに囲われた部分の表示をブラウザがおこなっています。

基本はこれだけ分かれば、記事にする要素を作成できます。

文字列をHTMLとして構成する

それでは早速作っていきましょう。まず前提知識として、Pythonで文字列を連結する方法を覚えてください。

Pythonで、文字列を連結するために様々な方法がありますが、f文字列(f-string)を使用すると便利です。f文字列を使うと、変数や式を文字列内に埋め込むことができます

f文字列は、文字列の前に f もしくは F を付けて作成します。その中に {}(中括弧)を使って変数や式を挿入します。具体的な例を書きますので、是非Pythonプロンプトで実行してみてください。。

name = "太郎"
age = 25
message = f"私の名前は、 {name} で現在 {age} 歳です。"
print(message)

このコードでは、name 変数と age 変数の値を message 文字列に挿入しています。f を付けた文字列であるため、中括弧 {} 内の変数や式は評価され、その結果が文字列に埋め込まれます。

もう想像がついている方がいらっしゃるかと思いますが、ChatGPTからの返答をPythonの文字列連結を使い、HTMLタグと連結し、記事を構築するというのが、記事の自動生成になります。

では、先ほど作成した、makeBlog.py を下記の様に編集してください。

import openai 

# openAIへAPIリクエストを投げて、レスポンスを返却するクラス
def getOpenAIResponse(question):
    openai.api_key = "sk-<your secret key>" # 取得したAPIキーを入力
    #print(question) # debug
    
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=question,
        max_tokens=1000,
        echo=False
    )
    
    response_text = response['choices'][0]['text'].replace('\n', '')
    #print(response_text) # debug
 
    return response_text

# ここから追加
# 引数で受け取ったHTMLタグで引数contentsを囲う
def getFormatContent(html_tag, contents):
    return f"<{html_tag}>{contents}</{html_tag}>"
    
question = "面白そうなブログタイトルを考えてください。"
response = getOpenAIResponse(question)

title = getFormatContent("h2", )

print("--- 以下、Debug出力 ---")
print(title)

getFormatContent関数を定義しました。
この関数は引数で受け取ったHTMLタグで、引数で受け取った文字列(contents)を囲い、返却します。
返却されたHTML文字列を変数 title で受け取っています。

以下の様にターミナルなどで、実行して出力を確認してください。

 python makeBlog.py
--- 以下、Debug出力 ---
<h2>『毎日が豊かな人生を過ごす秘訣!』</h2>

HTMLでマークアップできた事が確認できると思います。
あとは、これを複数回繰り返すことでブログ記事として構成できます。
次節で、繰り返しをしたり文章を作りやすい構成にPythonのコードをアップデートさせます。

記事整形部分をクラスにしてループできる様にする

基本動作は前の節で出来上がっているので、コード全文を載せてから解説します。

import openai
openai.api_key = "sk-<your secret key>" # 取得したAPIキーを入力

# openAIへAPIリクエストを投げて、レスポンスを返却するクラス
def getOpenAIResponse(question):
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=question,
        max_tokens=1000,
        echo=False
    )
    
    response_text = response['choices'][0]['text'].replace('\n', '')
 
    return response_text

# HTMLでフォーマット
class HtmlFormat:
    # 各プロパティの初期化処理
    def __init__(self, item, request, response, html_format, open_api_flg):
        self.item = item
        self.request = request
        self.response = response
        self.html_format = html_format
        self.open_api_flg = open_api_flg
        
    # HTMLでフォーマット   
    def getFormatContent(self):
        if (self.item != "タイトル"):
            return f"<{self.html_format}>{self.response}</{self.html_format}>"
        else:
            return self.response
        

# main
title = "" # タイトル保存
solution_1 = "" # 方法1を保存
solution_2 = "" # 方法2を保存

# リクエスト配列 - 記事の構成をお好きな形に変更して下さい。
html_format_list = [
    HtmlFormat("タイトル", "ダイエットのブログタイトルを1つ考えて下さい。語尾は「方法」でお願いします。", "", "", True),
    HtmlFormat("リード文のタイトル", "", "はじめに", "h2", False),
    HtmlFormat("リード文", "のリード文を考えて下さい。", "", "p", True),
    HtmlFormat("2つの方法", "", "2つの方法", "h2", False),
    HtmlFormat("方法1", "のやり方を箇条書きで10文字以下で1つ考えて下さい。", "", "h3", True),
    HtmlFormat("方法1詳細", "の詳細を100文字以上で教えて下さい。", "", "p", True),
    HtmlFormat("方法2", "のやり方を箇条書きで10文字以下で1つ考えて下さい。", "", "h3", True),
    HtmlFormat("方法2詳細", "の詳細を100文字以上で教えて下さい。", "", "p", True),
    HtmlFormat("まとめタイトル", "", "まとめ", "h2", False),
    HtmlFormat("まとめ", "の結論を200文字以上で教えて下さい。", "1", "p", True)
]

# 項目ごとにリクエスト内容を変更するので、ラムダを使用して変換
request_dic = {"タイトル": lambda x:x.request, 
               "リード文": lambda x:title + x.request,
               "方法1": lambda x:title + x.request,
               "方法1詳細": lambda x:solution_1 + x.request,
               "方法2": lambda x:solution_1 + "以外で" + title + x.request,
               "方法2詳細":lambda x:solution_2 + x.request,
               "まとめ": lambda x:title + html_format.request
            }

for html_format in html_format_list:
    while True:
        if html_format.open_api_flg:
            html_format.request = request_dic[html_format.item](html_format) 
            html_format.response = getOpenAIResponse(html_format.request)
        if html_format.item == "タイトル":
            title = html_format.response
        elif html_format.item == "方法1":
            solution_1 = html_format.response
        elif html_format.item == "方法2":
            solution_2 = html_format.response
                
        if html_format.response is None:
            print("リクエストに失敗しました。再実行します。")
        else:
            break
        
print("--- Debug用出力 ---")
for html_format in html_format_list:
    print(html_format.getFormatContent())

いきなり長くなって驚かれた方がいるかもしれませんが、やっている事は先程の応用です。ブロックに区切り詳しく解説します。

OpenAI APIの設定

前回関数化した際に、関数の中に入れていましたが、シークレットキーを毎回関数の中で設定するのは無駄なので、外に出しました。次回の記事で解説しますが、シークレットキーはコードの中に書くものではありません。別に設定ファイルを用意してそこから読み出すようにすべきです。この辺りは次回記事で変更します。

import openai
openai.api_key = "sk-<your secret key>" # 取得したAPIキーを入力

getOpenAIResponse 関数

def getOpenAIResponse(question):
    # OpenAI APIにリクエストを送信してレスポンスを取得
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=question,
        max_tokens=1000,
        echo=False
    )
    response_text = response['choices'][0]['text'].replace('\n', '')

    return response_text

先程作成した関数です。この関数は、与えられた質問(prompt)をOpenAI APIに送信し、APIから返されたレスポンスを取得しています。

APIのモデル(model)は “text-davinci-003” を使用し、最大トークン数(max_tokens)を1000に設定しています。

返されたレスポンスは改行文字を削除し、テキストの形式で返されます。

HtmlFormat クラス

class HtmlFormat:
    def __init__(self, item, request, response, html_format, open_api_flg):
        self.item = item
        self.request = request
        self.response = response
        self.html_format = html_format
        self.open_api_flg = open_api_flg
    
    def getFormatContent(self):
        if self.item != "タイトル":
            return f"<{self.html_format}>{self.response}</{self.html_format}>"
        else:
            return self.response

このクラスは、HTML形式でのフォーマットを行うクラスです。

インスタンス変数として、項目(item)、リクエスト(request)、レスポンス(response)、HTMLのフォーマット(html_format)、ChatGPTからの返答なのか固定文字列なのかを判断するフラグ(open_api_flg)を持ちます。ChatGPTからのレスポンスの場合は「true」を設定しています。固定文字列とChatGPTからのレスポンスで表示の切り替えを行う為に使用します。

getFormatContent メソッドは、各項目を適切なHTMLフォーマットで返します。

メインの処理

title = ""
solution_1 = ""
solution_2 = ""

タイトルと2つの方法を保持するための変数を宣言・初期化します。今回は方法を2つChatGPTに聞く構成なので、方法を保持する変数を2つ用意しています。

html_format_list = [
    HtmlFormat("タイトル", "ダイエットのブログタイトルを1つ考えて下さい。語尾は「方法」でお願いします。", "", "", True),
    ...
]

リクエスト内容とレスポンスを受け取るためのHtmlFormatオブジェクトのリストを定義します。

各HtmlFormatオブジェクトは、項目(item)、リクエスト(request)、レスポンス(response)、HTMLのフォーマット(html_format)、固定文字列かChatGPTの返答かを判断するフラグ(open_api_flg)を持ちます。

request_dic = {"タイトル": lambda x: x.request, 
               "リード文": lambda x: title + x.request,
               "方法1": lambda x: title + x.request,
               "方法1詳細": lambda x: solution_1 + x.request,
               "方法2": lambda x: solution_1 + "以外で" + title + x.request,
               "方法2詳細": lambda x: solution_2 + x.request,
               "まとめ": lambda x: title + x.request
               }

各項目ごとにリクエストの内容を生成するためのラムダ式(無名関数)を保持する辞書(request_dic)を定義しています。このラムダ式は下記の様に動作しています。

  1. "タイトル": lambda x: x.request: タイトルの場合、そのままHtmlFormatオブジェクトのrequestプロパティ(リクエスト内容)を返します。
  2. "リード文": lambda x: title + x.request: リード文の場合、事前に保存されたtitle変数とHtmlFormatオブジェクトのrequestプロパティを結合してリクエスト内容を生成します。
  3. "方法1": lambda x: title + x.request: 方法1の場合、同様に事前に保存されたtitle変数とHtmlFormatオブジェクトのrequestプロパティを結合してリクエスト内容を生成します。
  4. "方法1詳細": lambda x: solution_1 + x.request: 方法1の詳細の場合、事前に保存されたsolution_1変数とHtmlFormatオブジェクトのrequestプロパティを結合してリクエスト内容を生成します。
  5. "方法2": lambda x: solution_1 + "以外で" + title + x.request: 方法2の場合、事前に保存されたsolution_1変数とtitle変数を結合し、さらにHtmlFormatオブジェクトのrequestプロパティを結合してリクエスト内容を生成します。
  6. "方法2詳細": lambda x: solution_2 + x.request: 方法2の詳細の場合、事前に保存されたsolution_2変数とHtmlFormatオブジェクトのrequestプロパティを結合してリクエスト内容を生成します。
  7. "まとめ": lambda x: title + html_format.request: まとめの場合、事前に保存されたtitle変数とHtmlFormatオブジェクトのrequestプロパティを結合してリクエスト内容を生成します。
for html_format in html_format_list:
    while True:
        if html_format.open_api_flg:
            html_format.request = request_dic[html_format.item](html_format) 
            html_format.response = getOpenAIResponse(html_format.request)
        if html_format.item == "タイトル":
            title = html_format.response
        elif html_format.item == "方法1":
            solution_1 = html_format.response
        elif html_format.item == "方法2":
            solution_2 = html_format.response
                
        if html_format.response is None:
            print("リクエストに失敗しました。再実行します。")
        else:
            break

それぞれのHtmlFormatオブジェクトに対して、リクエストの内容は対応する項目のラムダ式を使用して生成されます。

print("--- Debug用出力 ---")
for html_format in html_format_list:
    print(html_format.getFormatContent())

確認用のに、各HtmlFormatオブジェクトのフォーマット内容ループして表示します。

それでは下記の様にターミナル若しくはコマンドプロンプトから実行して出力を確認して下さい。私の環境では下記の様に出力されました!!

python makeBlog.py

--- Debug用出力 ---
「本気で痩せる!効果的なダイエット方法」
<h2>はじめに</h2>
<p>「あなたにも体重管理に本気で取り組める!最も効果的なダイエット方法をお届けします!」</p>
<h2>2つの方法</h2>
<h3>①運動する</h3>
<p>運動をする際には、まず有酸素運動をするのが一般的です。有酸素運動とは、長時間かつ継続的に行う運動のことです。踊りやウォーキング、ランニングなどがあげられます。その他にもサイクリング、水泳なども試してみるのもいいでしょう。また、動きやすく、ゆっくり行うストレッチも加えると、心身に良い効果があります。定期的に運動を行うことで、健康的な生活を送ることができます!</p>
<h3>食事制限</h3>
<p>食事制限とは、1日に摂取する食事量や栄養バランスを計画的に増やしたり減らしたりすることです。例えば、カロリーを抑えるために大量の食事を減らし、野菜や果物などの食物群を一定の比率で摂取するといった、健康的な食事行動を行うことが指示されます。また、無理な節約や衛生的な食事行動を求めて行わないなども重要で、可能な限り自然な状態・味・栄養の健康的な食生活を心がけることも重要です。</p>
<h2>まとめ</h2>
<p>本気で痩せる効果的なダイエット方法として、「食事療法」「運動療法」「異常栄養療法」の3つがあります。1つ目の食事療法では、食生活を改善するために、量や種類などを適切にして摂取するように心がけることが大切です。2つ目の運動療法では、筋トレなどを行うことで健康維持や便秘解消などに役立ちます。また、ただストレスを発散するだけでなく、楽しみながら家族や友人などと行うと効率的に痩せることができます。最後の異常栄養療法では、生活習慣病や内分泌障害などの病気により太りやすい人を対象として、栄養情報に基づいた食行動を改善させ、適切な食事による痩身を行う療法として活用されています。この3つを合わせ、日常の生活の中で心がけることで、本気で痩せることができます。</p>

簡単な内容ですが、指定した通りの構成でブログ記事を作ることができました!!

まとめ

如何でしたか?ブログ記事がプログラムからChatGPTを利用することで一瞬で出来上がって驚いたと思います。生成された文章もちょっと変かなと思う部分がありますが、かなり自然なものになっているかと思います。

今回のコードを少し変更することで、どんな構成のブログでも簡単に作れることがわかるかと思います。

次回の記事では次の内容を行い、このチュートリアルを終了したいと思います。

  1. シークレットキーを設定ファイルから読み込む様に変更
  2. 記事のタイトルなどがプログラムに直書きで、他の記事を作る際にプログラムを修正する必要があるので、例えばエクセルなどでタイトル一覧を管理できる様に変更
  3. 実際にWordpressなどで公開しているサイトへ自動投稿を行う機能の実装
  4. 定期的に自動実行するように設定する方法
  5. Python以外の言語からChatGPTを使用し、ブログ記事を作る方法。下記の言語で解説します。
    • PHP
    • Excel VBA

以上を解説します。
次回を楽しみにしていて下さい!!