作業環境・自動化

BlueskyのAPI自動投稿Pythonスクリプトを作って、毎日動かすようになった話

BlueskyのAPI自動投稿Pythonスクリプトを作って、毎日動かすようになった話

この記事は約 4 分で読めます

📖 目次
  1. 📌 最初はシンプルすぎて壊れた
  2. 📌 正しいタイムスタンプと文字数制限の話
  3. 📌 ハッシュタグをリッチテキストで埋め込む
  4. 📌 セッション管理とレート制限の現実
  5. 📌 画像つき投稿の落とし穴
  6. 📌 launchd で毎日3回動かす仕組み
  7. 📌 まとめ
  8. 📌 関連記事

最終更新: 2026-04-28

最初はシンプルすぎて壊れた

Blueskyに自動投稿したいと思ったのは、毎朝同じ作業を手でやっているのがバカバカしくなったから。
AI生成したテキストをコピペして、ブラウザを開いて、投稿ボタンを押す。たった1分だけど、毎日続くと地味に消耗する。

最初に書いたコードは本当に最低限だった。

[コード略 — 詳細は元記事参照]

これ、createdAtをハードコードしてるせいで、Blueskyのタイムラインに過去の日付で投稿されてた。
気づいたのは3日後。その間ずっと2026年元日の投稿として流れてたわけで、エンゲージが全然つかない理由がそれだったと思うとちょっと面白い。

正しいタイムスタンプと文字数制限の話

Blueskyは「300文字制限」だけど、これが「Unicodeのコードポイント数」じゃなくて「UTF-8バイト数」で判定されてる、という罠がある。
日本語1文字 = 3バイト。つまり日本語だと実質100文字ちょっとで上限に引っかかる。

[コード略 — 詳細は元記事参照]

createdAtはちゃんとUTCで現在時刻を入れる。

[コード略 — 詳細は元記事参照]

これだけで「あれ、なんか投稿されてるけどタイムラインに出てこない」問題はほぼ解決した。

ハッシュタグをリッチテキストで埋め込む

テキストに #Python自動化 と書いても、ただの文字列として扱われる。
Blueskyのハッシュタグをクリッカブルにするには facets という構造を使う必要がある。

これが最初わからなくて、「なんでタグがリンクにならないんだ」と30分悩んだ。

[コード略 — 詳細は元記事参照]

バイトオフセットで位置指定するのが罠で、文字数じゃなくてバイト数で「どこからどこまでがタグか」を指定する必要がある。
日本語混じりのテキストで len(text[:n]) をそのまま使うとズレる。

セッション管理とレート制限の現実

毎回ログインしてセッションを取得するのは非効率で、しかもレート制限に引っかかる可能性がある。
com.atproto.server.createSessionは1時間に何十回も叩ける設計ではない。

[コード略 — 詳細は元記事参照]

bluesky_session.json としてローカルに保存して使い回す。
これで毎回ログインしなくなった。refreshJwtの有効期限は確か90日ぐらいなので、launchdで毎日動かしてれば実質ずっと使える。

画像つき投稿の落とし穴

テキストだけの投稿に比べて、画像付きはひと手間かかる。
まずBluesky側にアップロードしてblobのCIDを取得し、それをレコードに埋め込む形になる。

[コード略 — 詳細は元記事参照]

画像の上限は1MB。それ以上はアップロードが 400 Bad Request で落ちる。
僕はサムネ生成後にPillowでリサイズしてから渡している。

launchd で毎日3回動かす仕組み

スクリプト単体ができたあと、launchdに組み込んで自動化した。
07:00 / 12:30 / 20:30 の3回。それぞれ生成AIが作ったテキストをキューから取り出して投稿する流れ。

[コード略 — 詳細は元記事参照]

パスワードはBlueskyの設定画面から「アプリパスワード」を発行する。
メインパスワードをplistに書くのは怖いのでアプリパスワードを使っている。これ大事。

まとめ

完成形のコードは200行いかない。ポイントを整理すると:

  • createdAt は UTCの現在時刻(ハードコード禁止)
  • 文字数制限はバイト数で判定(日本語は3バイト/文字)
  • ハッシュタグは facets で位置指定しないとクリックできない
  • セッションはキャッシュして再利用
  • 画像は事前にBluesky側にアップロードしてからCIDを参照

最初の3日間、元日のタイムスタンプで投稿し続けてたのは今となっては笑い話だけど、リアルタイムで確認してなかったのが原因だった。
自動化は「動いた」で終わりにしないで、最初の数回は手動で確認する習慣をつけてからlaunchdに任せるほうがいい。完璧より継続——でも最低限の動作確認はしておく、というバランスが今のところうまくいってる✨


[コード略 — 詳細は元記事参照]

📘 この記事のテーマをさらに深掘りした本

Blueskyフォロワーを自動で増やすPythonシステム構築術

タグ75個・1日100フォローの自動エンゲージパイプラインを全公開

Kindleで読む →


一ノ瀬泰斗のアバター
一ノ瀬泰斗
AI自動化エンジニア / Python個人開発者

Claude Code × Ollama × launchd で SNS・ブログ・KDPを全自動化。実測データと失敗談を軸に、月5万円収益化のリアルな記録を発信中。

💬 自動化の相談・小規模受託も受付中:「launchd で毎朝 AI が動く仕組みを作りたい」「KDP の自動出版を組みたい」など、X (@taito_automate) の DM からお気軽にどうぞ。


関連記事

✨ AUTHOR'S KDP BOOKS

かかる人向ケ、10分でわかるAI自動化入門

Claude Code / Ollama / launchd の実践テクニックをコンパクトにまとめたシリーズ。非エンジニアの会社員向けに書いてます。

Amazonで見る ›

✨ FOLLOW ME

AI自動化の実験・失敗・実測データを毎日発信中

𝕏 フォローする