Bluesky API × Pythonで画像付き投稿をスケジューリングする方法

備忘録

はじめに

近年、SNSの勢力図は大きく塗り替えられた。
中でも、分散型プロトコル AT Protocol を基盤とする Bluesky は、そのオープンな開発環境と透明性の高さから、エンジニアやクリエイターにとって「最も活動しがいのある場所」へとなりつつある。
特にAI学習を禁止することを利用規約に明文化している点について、クリエイターは心強いことだろう。

毎朝決まった時間に作品をアップしたい」「特定のニュースを自動でシェアしたい
そんな願いを叶えるのが、Pythonによる自動投稿システムの構築だ。

本記事では、最新の atproto ライブラリを使い、画像付き投稿を特定の時間に実行する 実践的なスクリプトの作り方を徹底解説する。


スポンサーリンク
スポンサーリンク

1. 事前準備:App Passwordの発行

Blueskyで自動投稿を行う際、普段ログインに使っているパスワードを直接スクリプトに書き込むのはセキュリティ上、推奨されない。必ず App Password(アプリ専用パスワード) を発行して使用しよう。

  1. Blueskyの「設定」→「高度な設定」→「アプリパスワード」を開く。
  2. アプリパスワードを作成」をクリックし、名前(例:PythonBot)を付けてパスワードを生成する。
  3. 表示された文字列を控えておく。

2. 必要なライブラリのインストール

まずは、Python環境を整える。今回はBluesky APIを操作する公式ライブラリ atproto と、シンプルで直感的なスケジューリングを可能にする schedule を使用する。

pip install atproto schedule

  • atproto: BlueskyのバックボーンであるAT Protocolを叩くための標準的なライブラリだ。
  • schedule: 「○分ごと」「毎日○時」といった人間にとって理解しやすい形式で処理を予約できる。

3. 画像付き投稿スクリプトの実装

単なるテキスト投稿なら簡単だが、画像のアップロードには「Blob(バイナリ・ラージ・オブジェクト)」という概念の理解が欠かせない。少し複雑に感じるかもしれないが、以下のコードをテンプレートとして使えばスムーズに実装できる。

import os
from atproto import Client, models

# 1. 認証情報の設定
# セキュリティのため、環境変数や設定ファイルからの読み込みを推奨
BLUESKY_HANDLE = "your-handle.bsky.social"
BLUESKY_APP_PASSWORD = "xxxx-xxxx-xxxx-xxxx"

def post_to_bluesky(text, image_path=None):
    """
    Blueskyにテキストと画像を投稿する
    """
    client = Client()
    try:
        # ログイン
        client.login(BLUESKY_HANDLE, BLUESKY_APP_PASSWORD)

        embed = None
        if image_path and os.path.exists(image_path):
            # 画像の読み込みとアップロード
            with open(image_path, "rb") as f:
                img_data = f.read()
                # サーバーに画像をBlobとしてアップロード
                upload = client.upload_blob(img_data)

                # 投稿に埋め込むための画像オブジェクトを作成
                # altテキストはアクセシビリティ向上のために重要だ
                images = [models.AppBskyEmbedImages.Image(alt="自動投稿画像", image=upload.blob)]
                embed = models.AppBskyEmbedImages.Main(images=images)

            print(f"画像をアップロードしました: {image_path}")

        # 投稿の実行
        client.send_post(text=text, embed=embed)
        print("投稿に成功しました!")

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

# テスト実行
if __name__ == "__main__":
    post_to_bluesky("Pythonからこんにちは!これは自動投稿のテストです。", "sample_image.jpg")

このコードのポイントは client.upload_blob() だ。画像を直接投稿に載せるのではなく、一度サーバーに「素材」として預け、そのIDを投稿データに紐付けるという手順を踏む。


4. 指定時間に実行するスケジューリング機能

次に、作成した投稿関数を「毎日決まった時間」に動かしてみる。schedule ライブラリを使えば、まるで日本語で指示を出すかのように時間を指定できる。

import schedule
import time

def job():
    print("予約投稿処理を開始する...")
    post_to_bluesky("【定期】おはようございます!今日も1日がんばりましょう。", "morning_vibes.png")

# 毎日 08:30 に実行
schedule.every().day.at("08:30").do(job)

# 毎週月曜日の 09:00 に実行
# schedule.every().monday.at("09:00").do(job)

print("スケジューラー待機中...")

while True:
    schedule.run_pending()
    time.sleep(1)

運用時のテクニック:実行環境の比較

スクリプトが完成しても、自分のPCをずっとつけっぱなしにするのは現実的ではない。目的に合わせて適切な実行環境を選ぼう。

手法 メリット デメリット
自宅PC (ローカル) 無料、環境構築が容易 PCを落とすと停止する
VPS (Ubuntuなど) 24時間稼働、安定性が高い 月額料金(数百円〜)がかかる
GitHub Actions 無料枠がある、環境維持が不要 設定にやや知識が必要(YAML)
Raspberry Pi 低消費電力、自宅で完結 ハードウェアの購入が必要

5. 安定運用のためのTips

自動投稿を「放ったらかし」にするには、いくつかの落とし穴を避ける必要がある。

  • 例外処理の徹底: ネットワークが一時的に切れただけでスクリプトが落ちないよう、try-except でエラーを適切にハンドリングし、ログに残す習慣をつけよう。
  • レートリミット(回数制限): BlueskyにはAPIの呼び出し制限がある。短時間に数百件といった異常な投稿は、アカウント凍結のリスクを招く。
  • 画像サイズの最適化: あまりに巨大な画像はアップロードエラーの元だ。事前に Pillow ライブラリなどでリサイズや圧縮を行うと、より堅牢なシステムになる。

まとめ

Pythonと atproto を組み合わせることで、Blueskyにおける情報発信の自由度は飛躍的に高まる。
手作業で行っていたルーチンを自動化すれば、よりクリエイティブな活動に時間を割けるようになるはずだ。

まずは、シンプルなテキスト投稿から始め、徐々に画像やスケジューリングといった機能を追加していくことをお勧めする。

今回の重要ポイント:

  • App Password を使用してセキュリティを確保する。
  • 画像投稿は Blobアップロード投稿(Record作成) の2ステップ。
  • schedule ライブラリで、自然な感覚の予約設定を実現する。

コメント