X(旧ツイッター)×GAS 自動ポストツールの作成方法

  • URLをコピーしました!

この記事では、X(旧ツイッター)のAPIとGoogle Apps Script(GAS)を活用して、定期的に自動投稿を実行するツールの作り方を解説します。

対象:

  • X(旧ツイッター)に定期的に投稿したい方
  • Googleスプレッドシートを使って簡単なシステムを作ってみたい初心者
  • 手作業の投稿を自動化して作業効率を上げたい方

X(旧ツイッター)のAPIを利用すると、プログラムからツイートの投稿が可能になります。
今回のツールは、Googleスプレッドシートに入力した内容がXへ自動投稿を実現します。

目次

準備するもの

Googleスプレッドシートの作成と設定

  • 新しいスプレッドシートを作成し、シート名を「投稿リスト」にする
  • シートのレイアウトは以下の通り:
    • A列: ツイートID(投稿成功時にツイートのIDを記録する場合に利用)
    • B列: 投稿内容(実際のツイート文を入力)
    • C列: 投稿日時(ツイートが送信された日時を記録)

※ 本ツールでは、シート「投稿リスト」のB列に入力された内容を順次(1件ずつ)処理し、ツイート送信後にC列へ投稿日時を記入します。

X API(旧ツイッターAPI)の設定

  • X Developer Platformにアクセスし、Xに投稿を行いたいアカウントでログインする
  • 「Create an App」または「Apply」をクリックし、アプリを作成する
    • App permissions: 「Read and write」を選択
    • Type of App: 「Web App, Automated App or Bot」など、用途に合わせた項目を選択
    • Callback URL/Redirect URL: GASエディタのURL形式(例:bashコピーするhttps://script.google.com/macros/d/【scriptID】/usercallback )を入力
    • WebSite URL: 自身のブログなど、参考URLを任意で入力
  • 作成完了後、表示されるClient IDClient Secretをコピーし、安全な場所に保管する

GASプロジェクトの準備

OAuth2ライブラリの追加

  • スプレッドシート上部の「拡張機能」→「Apps Script」をクリックしてプロジェクトを開く
  • 左側メニューの「ライブラリ」アイコンをクリックし、下記のスクリプトIDを入力する:コピーする1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
  • ライブラリが追加され、必要に応じて承認手順を完了する

コードの実装

以下のコードは、OAuth2認証の設定と、シート「投稿リスト」から順次ツイート送信する処理を実装したものです。
コード内のコメントで各処理内容を確認してください。

全体の流れ

  • 認証処理(OAuth2)
    初回実行時に認証URLを生成し、認証手順を実施。認証後はアクセストークンを取得し、以降のAPIリクエストで利用します。
  • PKCE(Proof Key for Code Exchange)対策
    セキュリティ向上のため、ランダムな文字列からcode_verifiercode_challengeを生成します。
  • ツイート送信処理
    シート「投稿リスト」のB列(投稿内容)とC列(投稿日時)のデータをまとめて取得。
    上から順に、B列に投稿内容がありC列に投稿日時が未記入の行を対象にツイート送信を実行。
    送信成功時は、C列に現在日時を記録し、次回以降はその行が再投稿されないようにします。
// --- ユーザープロパティのクリア(デバッグや再認証時用) ---
function clearUserProperties() {
  PropertiesService.getUserProperties().deleteAllProperties();
}

// --- API認証情報 ---
// ※ ここに実際のClient IDとClient Secretを入力してください。
const TWITTER_CLIENT_ID = 'あなたのClientIDをここに';
const TWITTER_CLIENT_SECRET = 'あなたのClientSecretをここに';

// --- 認証初期化関数 ---
// 認証済みかどうかを確認し、未認証なら認証用URLをログに出力します。
function initializeAuth() {
  var twService = createTwitterService();
  if (twService.hasAccess()) {
    Logger.log("認証済みです。");
  } else {
    var authUrl = twService.getAuthorizationUrl();
    Logger.log("認証が必要です。次のURLにアクセスして認証後、再度実行してください: %s", authUrl);
  }
}

// --- Twitter認証サービスの生成 ---
// OAuth2ライブラリを使い、Twitter APIへのアクセス設定を行います。
function createTwitterService() {
  var userStorage = PropertiesService.getUserProperties();
  // PKCE用パラメータを生成(未生成の場合)
  generatePkceChallenge(userStorage);
  
  return OAuth2.createService('twitterAPI')
    .setAuthorizationBaseUrl('https://twitter.com/i/oauth2/authorize')
    .setTokenUrl('https://api.twitter.com/2/oauth2/token?code_verifier=' + userStorage.getProperty("pkce_verifier"))
    .setClientId(TWITTER_CLIENT_ID)
    .setClientSecret(TWITTER_CLIENT_SECRET)
    .setCallbackFunction('twitterAuthCallback')
    .setPropertyStore(userStorage)
    .setScope('users.read tweet.read tweet.write offline.access')
    .setParam('response_type', 'code')
    .setParam('code_challenge_method', 'S256')
    .setParam('code_challenge', userStorage.getProperty("pkce_challenge"))
    .setTokenHeaders({
      'Authorization': 'Basic ' + Utilities.base64Encode(TWITTER_CLIENT_ID + ':' + TWITTER_CLIENT_SECRET),
      'Content-Type': 'application/x-www-form-urlencoded'
    });
}

// --- Twitter認証コールバック ---
// OAuth2ライブラリの認証処理完了後に呼び出されるコールバック関数です。
function twitterAuthCallback(requestData) {
  var service = createTwitterService();
  var isAuthorized = service.handleCallback(requestData);
  return HtmlService.createHtmlOutput(isAuthorized ? 'Success!' : 'Authorization Denied.');
}

// --- PKCEパラメータ生成 ---
// ランダムな文字列からcode_verifierとcode_challengeを生成し、ユーザープロパティに保存します。
function generatePkceChallenge(storage) {
  if (!storage.getProperty("pkce_verifier")) {
    var verifierStr = '';
    var charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
    for (var i = 0; i < 128; i++) {
      verifierStr += charSet.charAt(Math.floor(Math.random() * charSet.length));
    }
    
    // SHA-256ダイジェストの生成
    var digest = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifierStr);
    // URLセーフなBase64エンコード
    var challengeStr = Utilities.base64Encode(digest)
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
    
    storage.setProperty("pkce_verifier", verifierStr);
    storage.setProperty("pkce_challenge", challengeStr);
  }
}

// --- ツイート投稿処理 ---
// スプレッドシート「投稿リスト」から投稿内容を上から順に確認し、
// 未投稿の最初の1件をTwitterへ投稿します。成功すれば、投稿日時を記録します。
function processTweetSubmission() {
  var service = createTwitterService();
  if (!service.hasAccess()) {
    var authLink = service.getAuthorizationUrl();
    Logger.log("認証が必要です。以下のURLから認証してください: %s", authLink);
    return;
  }
  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('投稿リスト');
  if (!sheet) {
    Logger.log("シート「投稿リスト」が存在しません。");
    return;
  }
  
  var lastRowNum = sheet.getLastRow();
  if (lastRowNum < 1) return; // データが存在しない場合は終了
  
  // 投稿内容(B列)と投稿日時(C列)を一括取得(列番号は2,3)
  var entries = sheet.getRange(1, 2, lastRowNum, 2).getValues();
  
  // 各行を上から確認し、投稿内容があって投稿日時が未記入の行を探す
  for (var i = 0; i < entries.length; i++) {
    var content = entries[i][0];
    var timeStamp = entries[i][1];
    
    if (content && !timeStamp) {
      var tweetData = { text: content };
      var endpoint = 'https://api.twitter.com/2/tweets';
      
      // POSTリクエストでツイート送信
      var response = UrlFetchApp.fetch(endpoint, {
        method: 'POST',
        contentType: 'application/json',
        headers: {
          'Authorization': 'Bearer ' + service.getAccessToken()
        },
        muteHttpExceptions: true,
        payload: JSON.stringify(tweetData)
      });
      
      var jsonResult = JSON.parse(response.getContentText());
      Logger.log(JSON.stringify(jsonResult, null, 2));
      
      // 成功した場合、responseにdata.idが含まれているはずです
      if (jsonResult && jsonResult.data && jsonResult.data.id) {
        // 投稿成功なら、その行のC列に投稿日時を記録
        sheet.getRange(i + 1, 3).setValue(new Date());
      } else {
        Logger.log("ツイート送信失敗。行 %s, 結果: %s", i + 1, JSON.stringify(jsonResult));
      }
      
      // 1件送信後はループを抜け、次回以降で次の投稿を処理する
      break;
    }
  }
}

使い方の流れ

初回認証

  • GASエディタで initializeAuth() を実行します。
  • ログに表示される認証URLにアクセスし、認証を完了してください。
  • 認証完了後、再度 initializeAuth() を実行すると「認証済みです」と表示されます。

ツイート投稿の実行

  • スプレッドシート「投稿リスト」のB列にツイート内容を入力します。
  • GASエディタで processTweetSubmission() を実行すると、入力された中でまだ投稿されていない最初の1件がXに投稿され、投稿成功時にその行のC列に現在日時が記録されます。

定期実行の設定

  • GASの「トリガー」機能を利用し、一定間隔(例:毎日、毎時など)で processTweetSubmission() を自動実行するように設定することで、定期的な自動投稿が可能となります。

注意点

  • セキュリティ管理
    APIキーやシークレット情報は第三者に漏れないよう安全に管理してください。
  • テストの実施
    実際の運用前に、テスト環境で十分な動作確認を行い、不具合がないか確認してください。
  • エラーチェックとログの確認
    ツイート投稿に失敗した場合のエラーログなどを定期的に確認し、問題があれば迅速に対処できる体制を整えることをおすすめします。

まとめ

今回のツールは、GoogleスプレッドシートとGoogle Apps Scriptを活用して、X(旧ツイッター)への自動投稿を実現するシステムです。

  • 初回認証 では、OAuth2認証とPKCEを利用して安全にTwitter APIへのアクセス権を取得し、
  • 投稿処理 ではシート「投稿リスト」の各行を順次確認し、未投稿のツイートを投稿後に記録する仕組みとなっています。
  • また、GASのトリガー機能を利用すれば、定期実行も可能なため、手作業による投稿作業を大幅に自動化でき、業務効率を向上させることができます。

これらの手順と注意点を守って実装すれば、初心者でも安心してXへの自動投稿ツールを構築・運用することができるでしょう。

  • URLをコピーしました!
目次