0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Threads自動投稿、Zapier・Make・自作Botで迷って全部試した結果

0
Posted at

Threads自動投稿、Zapier・Make・自作Botで迷って全部試した結果

Threads Publishing APIでの自動投稿、前に一度記事にした。今回はその続きというか裏側の話。実際に手を動かす前に、自分はZapier・Make(旧Integromat)・GitHub Actions・自作の常駐スクリプトの4つを比較検討した。

結局どれも「一応動く」けど「運用に乗せると詰まる」ポイントがそれぞれ違った。この記事では採用しなかった案とその理由を中心に書く。同じ選択で迷っている人の判断材料になればと思う。

結論先出し:自分が最終的に選んだのはWindowsタスクスケジューラ+ローカルPython常駐

自分の環境(普段使いのWindows PC、24時間起動していない)では、クラウド系のNoコードツール(Zapier・Make)は画像投稿とAPI障害時のリトライ制御の両立が難しかった。GitHub Actionsはcron精度と実行時間制限が引っかかった。

最終的にWindowsタスクスケジューラでPythonスクリプトを定期実行し、ローカルSQLiteに投稿ログとリトライ状態を持たせる構成に落ち着いた。「なぜクラウドを使わなかったか」を軸に、判断の経緯を書く。

問題の深掘り:なぜツール選びで詰まるのか

Threads Publishing APIは2024年に一般公開されたばかりで、Zapier・Makeの公式連携(トリガー・アクション)がまだ枯れていない時期があった。自分が触った時点(2024年後半)では、テキスト投稿は動くのに画像投稿でメディアIDの発行ステップが正しく処理できないケースがあった。

Noコードツールは「見えない部分」がブラックボックスなので、失敗した時に原因がAPI側の仕様なのか、ツール側のバグなのか、自分の設定ミスなのか切り分けにくい。デバッグに使える時間が限られている兼業エンジニアには地味に痛い。

もう一つの問題は料金設計だ。ZapierもMakeも「タスク数」または「オペレーション数」で課金される。1日3投稿、画像付きなら1投稿あたり2〜3ステップ(画像アップロード→メディアコンテナ作成→公開)を消費する。月90投稿として最低でも270オペレーション、リトライが絡めば500近くまで跳ねる。無料プランはすぐ枯渇する。

自分は最初Zapierの無料プランで試したが、10日目でタスク上限に当たった。有料プランは月20ドル前後からで、これを「実験のため」に払う気になれず、別案を探すことになった。

解決手順:4つの選択肢をどう検討し、どう捨てたか

選択肢1:Zapier(不採用)

採用しなかった理由:課金体系がタスク単位で、画像投稿のような多段処理だと消費が読みにくい。加えてThreads連携がサードパーティのWebhook経由になっており、公式のPublishing APIを直接叩く構成にできなかった。エンゲージメント取得(後で伸びた投稿を確認する用途)まで広げたかったので、API制御を自分の手元に置きたかった。

無料枠だけで軽く検証した段階で、10日で100タスクの上限に当たった。月3〜4本の投稿ペースなら悪くないが、画像込みで毎日投稿するには合わなかった。

選択肢2:Make(不採用)

採用しなかった理由:ZapierよりHTTPモジュールで柔軟にAPIを叩けるので、実はここまでは良かった。だが「指数バックオフでの自動リトライ」を組むには、シナリオ内でループとエラーハンドラを重ねる必要があり、GUI上で条件分岐が増えるほど見た目が複雑になった。

自分は将来的にリトライ回数やエラー内容をログとして残したかった。GUIフローの中に「失敗したらローカルDBに書く」という処理を組むより、コードで書いた方が10分で終わる作業に見えた。ここで「これはコードで書く方が早い」と判断した。

選択肢3:GitHub Actions(不採用)

採用しなかった理由:cronのスケジュール精度が「指定時刻±数分〜十数分」でずれることがあり、投稿時間を厳密にコントロールしたい用途には向かなかった。加えてPublic/Privateリポジトリの実行時間制限(無料枠だと月2000分)を、画像生成・AI呼び出し・投稿処理を含むジョブで使うと、月内に使い切る計算になった。

自分の場合、投稿文生成にGroq(Llama 3.3 70B)とGeminiを使っており、この呼び出し時間も実行時間に含まれる。無料枠を使い切ってから有料化するより、手元のPCで動かした方がコストが読みやすいと判断した。

選択肢4:Windowsタスクスケジューラ+ローカルPython常駐(採用)

最終的にこれを選んだ理由は3つ。

  1. 実行タイミングを分単位で固定でき、投稿時間の精度が読める
  2. 実行時間・API呼び出し回数に対する追加コストが発生しない(PCの電気代のみ)
  3. リトライ処理・エラーログをコードで直接書けるので、後から仕様変更しても自分でメンテできる

デメリットは「PCが起きていないと動かない」ことだが、自分の生活リズム(PCは平日ほぼ起動している)と噛み合っていたので許容した。

コード/実例:リトライ処理の骨格

import time
import sqlite3
import requests

MAX_RETRY = 3
BASE_WAIT = 2  # 秒

def post_to_threads(payload, access_token):
    url = "https://graph.threads.net/v1.0/me/threads"
    for attempt in range(1, MAX_RETRY + 1):
        try:
            res = requests.post(
                url,
                params={"access_token": access_token},
                json=payload,
                timeout=10
            )
            if res.status_code == 200:
                return res.json()
            raise RuntimeError(f"status={res.status_code}, body={res.text}")
        except Exception as e:
            wait = BASE_WAIT ** attempt
            log_failure(payload, attempt, str(e))
            if attempt == MAX_RETRY:
                save_to_local_db(payload, status="failed")
                raise
            time.sleep(wait)

def save_to_local_db(payload, status):
    conn = sqlite3.connect("post_queue.db")
    cur = conn.cursor()
    cur.execute(
        "INSERT INTO posts (content, status, created_at) VALUES (?, ?, datetime('now'))",
        (str(payload), status)
    )
    conn.commit()
    conn.close()

def log_failure(payload, attempt, error_msg):
    print(f"[retry {attempt}] failed: {error_msg}")

画像投稿は「メディアコンテナ作成」→「公開」の2段階になっているので、上のpost_to_threads相当の処理を2回呼ぶ形になる。1段目が失敗した場合、2段目に進まずリトライキューに戻す設計にしておくと、テキストだけ投稿されて画像が抜ける事故を防げる。

この2段目を作り忘れて、テキストだけ投稿されて画像が永久に付かない、という状態を検証中に1回やった。ログを見て初めて気づいたので、失敗ログの保存は最初から入れておいた方がいい。

落とし穴と対処:NDA範囲内での実体験

一番時間を溶かしたのは、Threads APIのメディアコンテナ作成後、公開までに一定の遅延(数秒〜十数秒)が必要な点だった。作成直後に即座に公開APIを呼ぶと、コンテナがまだ処理中でエラーになることがある。自分はここで30分ほど「なぜ公開できないのか」を調べる時間を使った。

対処としては、コンテナ作成後にステータスを確認するポーリング処理を挟むか、固定で数秒待つ処理を入れるかの二択になる。自分はシンプルに5秒待機を入れて運用しているが、確実性を求めるならステータス確認を入れた方が安全だと思う。

もう一つは、アクセストークンの有効期限管理だ。長期トークンでも60日程度で切れる仕様があり、これを自動更新する処理を後回しにしていたら、ある朝すべての投稿が失敗していた。トークン更新は最初から仕組みに入れておくべきだったと反省している。

関連ツール

投稿文自体を毎日考えるのも地味にしんどい作業で、自分はここも自動化したかった。テーマを1つ入れるとThreads・YouTube・Instagram向けの投稿文をAIで一括生成するCLIツールを作って、note経由でソースコード一式を配布している(sns-hub-v1.1、3,980円)。

Groq(Llama 3.3 70B)とGeminiをプラットフォーム別のプロンプトテンプレートで切り替えて使っており、今回書いたリトライ処理やローカルDB保全もこのツールに組み込んでいる。Windowsタスクスケジューラでの予約投稿もそのまま動く構成にしている。

sns-hub

まとめ

ZapierとMakeは検証コストが低く始めやすいが、画像投稿とリトライ制御を両立させるには課金体系とGUIの複雑さがネックになった。GitHub Actionsは無料枠の実行時間とcron精度で自分の用途とは噛み合わなかった。

結果的にローカルでのPython常駐運用が、コストと制御のバランスが一番良かった。ツール選定で迷っている人は、まず「リトライとログをどこまで自分でコントロールしたいか」を軸に考えると判断が早いと思う。


著者:ぽん(@pon_freelance
C言語実務23年、組み込み/制御系。
副業で技術記事販売と自作ツール販売をやっている。

書いているもの:

  • sns-hub - テーマを1つ入れると Threads / YouTube / Instagram 向けの投稿文をAIが一括生成するCLIツール
    (その他:(なし))

同じ手で作った道具を、インストールなしで試せます — 自分が実際に使っている自作ツールを、ブラウザからそのまま動かせる形で並べています。登録は不要です。
RunStack(無料で試す)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?