🕊️

Github Actions で定期投稿X(Twitter) Bot を作る

2025/01/14に公開

はじめに

この記事のスコープは以下となります。

  • Github Actions による定期実行
  • X(Twitter) への画像付き投稿

以下は Bot の投稿内容の一例として処理を示しますが、詳細は省きます。

  • OpenAI の API
  • 画像生成時の精度向上のためのプロンプト調整

忙しい人向け

スクリプトと設定ファイル、は以下のようになります。python3.11が実行できる環境で適切な環境変数に認証情報を入れてください。
例として、今回は画像生成に DALLE-3 を使っています。

# main.py

import tweepy
import os
from openai import OpenAI
import requests
from datetime import datetime

def setup_twitter_clients():
    # Twitter API v1認証(メディアアップロード用)
    auth = tweepy.OAuthHandler(
        os.getenv("TWITTER_API_KEY"),
        os.getenv("TWITTER_API_SECRET")
    )
    auth.set_access_token(
        os.getenv("TWITTER_ACCESS_TOKEN"),
        os.getenv("TWITTER_ACCESS_TOKEN_SECRET")
    )
    api_v1 = tweepy.API(auth)

    # Twitter API v2認証(ツイート投稿用)
    client_v2 = tweepy.Client(
        consumer_key=os.getenv("TWITTER_API_KEY"),
        consumer_secret=os.getenv("TWITTER_API_SECRET"),
        access_token=os.getenv("TWITTER_ACCESS_TOKEN"),
        access_token_secret=os.getenv("TWITTER_ACCESS_TOKEN_SECRET")
    )

    return api_v1, client_v2


def generate_and_post_image(prompt, tweet_text):
    client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
    temp_image = "temp_image.png"

    try:
        # 画像生成
        response = client.images.generate(
            model="dall-e-3",
            prompt=prompt,
            size="1024x1024",
            quality="standard",
            n=1
        )

        # 画像ダウンロード
        image_url = response.data[0].url
        image_response = requests.get(image_url)

        with open(temp_image, "wb") as f:
            f.write(image_response.content)

        # Twitter APIクライアント取得
        api_v1, client_v2 = setup_twitter_clients()

        # 画像アップロード(v1 API)
        media = api_v1.media_upload(temp_image)

        # ツイート投稿(v2 API)
        tweet = client_v2.create_tweet(text=tweet_text, media_ids=[media.media_id])

        os.remove(temp_image)
        print("ツイートを投稿しました")
        return tweet.data['id']

    except Exception as e:
        print(f"エラーが発生しました: {str(e)}")
        return e

    finally:
        if os.path.exists(temp_image):
            os.remove(temp_image)

if __name__ == "__main__":
    # 画像生成と投稿
    prompt = "紅い目で長い銀髪の20代ぐらいの女性、全身、幻想的な背景、日本のアニメーション調の繊細で多彩な色彩の画像"
    tweet_text = "Generated By #DALLE3 #AI #AIart #AIイラスト #銀髪"
    generate_and_post_image(prompt, tweet_text)
name: AI Image Generation and Twitter Post

on:
  schedule:
    - cron: '0 0 * * *'  # 毎時実行
  workflow_dispatch:  # 手動実行用

jobs:
  post-image:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          
      - name: Install dependencies
        run: |
          pip install openai tweepy requests
          
      - name: Run script
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          TWITTER_API_KEY: ${{ secrets.TWITTER_API_KEY }}
          TWITTER_API_SECRET: ${{ secrets.TWITTER_API_SECRET }}
          TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
          TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
        run: python main.py

本題

Github Actions で 定期投稿する Bot を作る方法について、 投稿するためのスクリプトと Github Actions の設定ファイルの面で解説していきます。

全体の流れとしては以下のようになっています。

X(Twitter)への投稿

ただ Xへ投稿するだけであれば各種ライブラリや認証情報についていろんな方や公式が使い方書いているので割愛します。

例)

画像投稿については少々面倒な仕様なので本記事でも書いておこうと思います。

# 画像投稿の部分

import tweepy

def setup_twitter_clients():
    # Twitter API v1認証(メディアアップロード用)
    auth = tweepy.OAuthHandler(
        os.getenv("TWITTER_API_KEY"),
        os.getenv("TWITTER_API_SECRET")
    )
    auth.set_access_token(
        os.getenv("TWITTER_ACCESS_TOKEN"),
        os.getenv("TWITTER_ACCESS_TOKEN_SECRET")
    )
    api_v1 = tweepy.API(auth)

    # Twitter API v2認証(ツイート投稿用)
    client_v2 = tweepy.Client(
        consumer_key=os.getenv("TWITTER_API_KEY"),
        consumer_secret=os.getenv("TWITTER_API_SECRET"),
        access_token=os.getenv("TWITTER_ACCESS_TOKEN"),
        access_token_secret=os.getenv("TWITTER_ACCESS_TOKEN_SECRET")
    )

    return api_v1, client_v2

...
        # Twitter APIクライアント取得
        api_v1, client_v2 = setup_twitter_clients()

        # 画像アップロード(v1 API)
        media = api_v1.media_upload(temp_image)

        # ツイート投稿(v2 API)
        tweet = client_v2.create_tweet(text=tweet_text, media_ids=[media.media_id])

        os.remove(temp_image)
        print("ツイートを投稿しました")
        return tweet.data['id']
...

なにやらごちゃごちゃしていますが、これは画像投稿する場合には Twitter API を2種類コールする必要があるためです。
Claude に書かせてみたところ、最初v2 APIのみを利用しようとしていたので2種類使うよう指示したところAPIクライアントも2種類用意するようなコードになりました。
実際片方のクライアント(OAuth1.0a)だけで v1,v2リクエストできるらしいですがこの辺は Twitter の意向次第で今後どういう仕様になるかわからないですし、バックエンドのみでユーザー認証を挟まない Bot という性質上 OAuth1.0a は利用できないです。

ちなみに詳細は触れませんが DALLE-3 の APIコールで画像生成させてその画像をツイートするようにしてあります。同じOpenAI の API を使えば画像の説明を投稿内容に含めることもできそうです。

Github Actions による定期実行

ツイートを投稿するスクリプトができたら、Botとして運用するにはそのスクリプトを定期実行させる必要があります。今回は無料で使える Github Actinos の schedule を使います。

まず注意点なのですが、Github Actions による定期実行は遅延する可能性があると明言されているので、○時○分に実行しなければいけないようなものには不向きです。

https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule

GitHub Actions のワークフローの実行によって高い負荷がかかっている間、schedule イベントが遅延する可能性があります。 高負荷の時間帯には、毎時の開始時点が含まれます。 負荷が十分に高い場合、キューに登録されたジョブの一部が削除される可能性があります。 遅延の可能性を減らすために、Ⅰ時間の中の別の時間帯に実行されるようワークフローをスケジューリングしてください。

他にも長期間メンテされてないタスクは無効化されるなどあるので公式ドキュメントをチェックしておきましょう。

Github Actions の設定の記載に必要なものは今回は以下の 4点です。

  • いつ実行したいか
  • 実行環境
  • 実行したいスクリプト(や実行ファイル)を動かすコマンド
  • 環境変数(に入れるsecret)

これらを記載したものが以下のような設定ファイルとなります。 リポジトリの .github/workflow 配下に作成すれば実行されるようになります。

# ジョブ実行結果などに表示される名前
name: AI Image Generation and Twitter Post

on:
  schedule:
    - cron: '0 0 * * *'  # 毎時実行
  workflow_dispatch:  # 手動実行用

jobs:
  post-image:
    runs-on: ubuntu-latest # 実行環境
    
    steps:
      - uses: actions/checkout@v4
      # 実行環境の用意
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      # 依存関係インストール
      - name: Install dependencies
        run: |
          pip install openai tweepy requests
          
      - name: Run script
        # 環境変数の設定
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          TWITTER_API_KEY: ${{ secrets.TWITTER_API_KEY }}
          TWITTER_API_SECRET: ${{ secrets.TWITTER_API_SECRET }}
          TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
          TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
        run: python main.py

workflow_dispatch はテスト用に手動実行できるように設定しています。
環境変数についてですが、Github のリポジトリ設定で設定できます。
以下のように Setting >> Secrets and Variables >> Actions で設定しましょう。

また、若干サボってしまっていますが python の依存パッケージのインストールは当然ながら requirements.txt などを使う方が良いです。

おわりに

Tittwr Bot の作成に関しては、Render や AWS, GCP などを使った方法が散見されますが、個人開発程度であれば Github Actions でも全然許容範囲かつリポジトリ設定もお手軽なので記事として書いてみました。
もしまだ自前のPCやラズパイなんかで python ファイル動かしたりしていて、管理が面倒と感じている
人が居たらぜひ Github Actions を検討してみてください。

Discussion