【爆速】自作のTwitterBotを簡単に作るライブラリを作った話【初心者向け】

GAS/TwitterBot
この記事は約10分で読めます。

これまでTwitterBotの記事を書いてきましたが、コピペだけで済むとはいえ、少し難易度が高い&処理を書こうとするとコードが冗長になってしまう問題がありました。

今回、よく使われる諸々の処理をまとめたライブラリを公開したのでその紹介と使い方の解説を行います。

Twitterの仕様変更により、elevated以上のトークンしかこちらのライブラリは使用できません。

Exception: Request failed for https://api.twitter.com returned code 403. Truncated server response: {“errors”:[{“message”:”You currently have Essential access which includes access to Twitter API v2 endpoints only.

というエラーが出た際は、
https://developer.twitter.com/en/portal/products/elevated
こちらより申請を行なってください

もしくは新しく作ったver2をご利用ください。

慣れてる人向けの情報(TL;DR)

以下のものを見ればたぶん分かると思います(おい

ライブラリID

1fHCjI78BV3o7nGx2l0lJ7WXM49VFbobGDNdFGqAoVFZyRJ2kepQYzVLd

ライブラリのソースコード

https://github.com/belltreeSzk/TwitterClient/blob/master/TwitterClient.gs

実行サンプルコード

main.gs
GitHub Gist: instantly share code, notes, and snippets.

TwitterClientライブラリとは(超初心者向け)

ライブラリとは

簡単に言うと便利な関数のセットです。

「jQueryはライブラリなのか、フレームワークなのか」という話をたまに聞きますが、ライブラリは関数群、フレームワークはアプリケーションの枠組みです。

だからjQueryはライブラリです。

まぁそれは置いておいて、そういった便利な関数群を作りました。

ライブラリがあると何が便利なのか

こちらも簡単に言うと大きなところは実装負担が減る点です。

本来100行のコードを書く必要がある処理をライブラリの関数を呼び出す1行で実装完了となってしまうこともあります。

実装が減るということは、コードが短くなります

コードが短くなるということは、コードがシンプルになります

コードがシンプルになるということは、不具合が減ります

加えて、仕様変更や不具合が起きて本当は修正しなければならない実装があっても、ライブラリ側で直してくれる場合もあります(つまり俺が、、)

ライブラリを使えば、簡単にやりたいことが出来る…かもしれませんね!

TwitterClientライブラリで出来ること

TwitterClientでは、これまで何度か紹介してきたTwitterBotを作る上で用意してきた関数をパッケージしました。

  • authorize() で認証する処理がシート毎に認証できるように対応
  • Twitterに投稿する postUpdateStatus の処理を postTweet() に集約
  • getRequest,postRequestでAPIを簡単実行
  • スプレッドシートから投稿文を取得する処理

などが集約されています。

TwitterClientの使い方

今回は完全初心者にも分かるようにゼロからの作り方で説明していきます。

スプレッドシートを用意する

まずはベースとなるスプレッドシートを用意します。参考例

余談ですが https://sheet.new から新しいシート作れること知ってましたかー?

GASを用意する

『ツール』から『スクリプトエディア』を選択します。

ライブラリを追加する

表示されたエディタページが開かれると思います。

図のようにファイル名を付けておき、『リソース』→『ライブラリ…』を選択してライブラリを追加していきます。

1fHCjI78BV3o7nGx2l0lJ7WXM49VFbobGDNdFGqAoVFZyRJ2kepQYzVLd

『TwitterClient』が追加されたら保存して完了です。

コードを書く(コピペでOK)

これをコピペしてください!以上!コメントを除くと30行以下だと思います。

「TwitterBotでスプレッドシートの内容を投稿する」であれば最低限これだけでOKです。

CallBack URLを取得する

次にTwitterアプリの用意をするのですが、用意する前にTwitterアプリに登録するために必要なCallbackURLを取得します。

画像の手順で getCallbackUrl を実行するとログに

https://script.google.com/macros/d/[SCRIPT_ID]/usercallback

という形式のURLが取得されるのでメモを取っておきます。

Authorization required が出た場合

初回実行時、私が作ったライブラリにアクセスするために認証が必要です。

上記のポップアップが出た場合、『許可を確認』を選択してください。

ここまで来たら後は諸々許可してください。

ステートメントの前に:がありません が出た場合

今回のコードは新しいApps Scriptランタイムを使用しています(constやclassを使える機能)

そのため、新しいランタイムが無効になっていると「class?なにそれ?エラーだ!」となってしまいます。

「ステートメントの前に:がありません」というエラーが出た場合、『実行』→『新しい Apps Script ランタイムを有効にする』を選択して、改めて実行してみてください。

Twitterアプリを用意する

Twitterの開発者ページからTwitterアプリを作ります。

Use Cases, Tutorials, & Documentation
Publish & analyze posts, optimize ads, & create unique customer experiences with the X API, X Ads API, & X Embeds.

Twitterのアカウントを持っているのであれば右上のSign Inからサインインしてください(既にサインインされているかも?)

右上のAppsからアプリ画面を表示してアプリを作ります。

こちらの記事でTwitterアプリを作っているので参考にどうぞ。

↑の記事ではcallbackURLがブログのURLになっていますが、そこには先程取得したcallbackUrlを登録するようにしてください。

Read and Write権限を付ける

ツイートするためにはTwitterへの書き込み権限が必要です。

Twitterアプリの設定画面で『App permissions』という項目があると思うので、『Read-only』でなく『Read and Write』に変更してください

※ Twitterアプリ開発者登録が済んでいない場合

以下の記事を参考にアカウント登録を行ってみてください(手抜き)

Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ ※2019年8月時点の情報 - Qiita
#本投稿の背景※申請画面が初投稿時(2018年9月)と変わってましたので、内容を更新しました ※2019年8月時点の情報となりますPython Twitterからツイートを取得してテキスト分析(…

Consumer Key をGASに登録する

GASの方に戻って、作ったTwitterアプリのConsumerKeyを登録します。

const consumerKey = 'CONSUMER_KEY'
const consumerSecret = 'CONSUMER_SECRET'

Twitter認証を行う

authorize を選択してTwitterの認証を行います。

authorizeを実行→『表示』→『ログ』で表示されたURLで認証を行ってください。

APIを実行する(投稿の動作確認)

postTweetで投稿するAPIを実行します。

/**
 * ③ APIを実行する(この辺はアレンジしてください)
 * ※この処理では「シート1」から投稿内容を取得してツイートしてます
 */
function postTweet () {
  // pickUpTweetInOrderは用意しました
  let message = TwitterClient.pickUpTweetInOrder('シート1');
  client.postTweet(message);
}

順番に投稿するBotを作りたい場合、 順番用参考例 を参考にしてシートを作りこちらの処理をそのままご利用ください。

ランダムに投稿するBotを作りたい場合、pickUpRandomを用意しましたので、ランダム用参考例 を参考にシートを作り、

TwitterClient.pickUpTweetRandom('シート1');

をご利用ください。

繰り返し実行を設定する

ここまででTwitterBotが完成しました。

最後に繰り返し実行の設定を行います。

以前同じ設定を紹介しているのでこちらを参考にどうぞ!

TwitterBotの機能を拡張する

別のTwiiterAPIを実行する

このライブラリの目的は簡単にTwitterBotを作るだけではなく、やりたいことを直感的に出来るようになることです。

そのため、TwitterAPIを実行しやすいようなメソッドを用意しました。

client.getRequest(url, param);
client.postRequest(url, param);
Overview

↑のようにTwitterのAPIを実行するためには Resource URLParameters が必要です。

このメソッドがGETであれば client.getRequest を利用してください。

例として自分のツイートをいいねする処理を書いてみました。

function favorite () {
  // ユーザーのタイムラインを取得
  let getTweetUrl = 'https://api.twitter.com/1.1/statuses/user_timeline.json';
  let getTweetParam = {
    screen_name: 'belltreeszk',
    count: 1
  }
  // GETリクエストを実行
  let getTweetResult = client.getRequest(getTweetUrl, getTweetParam);
  
  // いいねを付ける
  let favoriteUrl = 'https://api.twitter.com/1.1/favorites/create.json';
  let favoriteParam = {
    id: getTweetResult[0]['id_str']
  }
  // POSTリクエストを実行
  let favoriteResult = client.postRequest(favoriteUrl, favoriteParam);
  Logger.log(favoriteResult);
}

① URLをセット
② パラメータをセット
③ getRequestかpostRequestを実行
④ 受け取った結果を次の処理の ①〜③ に利用する

という流れの繰り返しでメソッドを作ることが出来ます。

GETやPOSTの処理を書いていたり、実行したいAPIによってパラメータの形式を悩まないために形式が共通になるようになっています。

便利だと思ったメソッドはTwitterClientに入れてもらってもOK

ソースコードは下記にまとめています。

GitHub - belltreeSzk/TwitterClient: GASを使ってTwitterBotを作る際に便利なライブラリ
GASを使ってTwitterBotを作る際に便利なライブラリ. Contribute to belltreeSzk/TwitterClient development by creating an account on GitHub.

GitHubで管理しているのでプルリクしてくれれば適当にライブラリも更新します(おい

TwitterのAPIに関係するものは TwitterClient.gs
スプレッドシートに関係するものは Utility.gs

に変更を加えてください。

ベースは作った。あとは任せた。

これまで TwitterWebService を利用してきましたが、微妙に使いにくい部分もあったので、自分の中ではより良いものを作ったつもりです。

場合によっては使いにくいこともあると思います。

その時はいい感じに直すなり、TwitterWebService を使うなり、上手くバランスを取ってほしいなぁと思います。

もちろん引き続き連絡してもらえれば回答・相談には乗りますのでお気軽にご連絡ください。

ここまで読んで頂きありがとうございました!

よろしければ↓からサポートよろしくお願いいたします。

コメント

  1. 詳しく分かりやすい解説で、初心者でも無事投稿まで行うことができました。ありがとうございます!
    ただ、1回目の投稿は成功するものの、2回目にpostTweetを実行すると「TypeError: Assignment to constant variable.at pickUpTweetInOrder(Utility:36:16)」とエラーが表示されて投稿が成功しません。
    調べてみましたが、原因が全然分かりませんでした。
    お手数ですが、何が原因かアドバイス頂けると大変嬉しいです。

    • すみません、これ、こちらのライブラリの不具合です。。。
      修正を行って、新しく 『順番投稿の不具合修正』 というバージョンをリリースしたのでこちらでお試しください。

      補足になりますが、

      TypeError: Assignment to constant variable.at pickUpTweetInOrder(Utility:36:16)

      こちらの不具合は、 const という宣言を使って定義している定数に対して再代入を行っていることが原因です(ライブラリの中でバグっていました)
      また何か問題がありましたらご連絡ください〜〜

  2. とても早く対応していただきありがとうございます!無事2回目以降のツイートも成功しました!
    なるほど、constという定数の部分の問題だったんですね。
    これからも有り難く使わせていただきます!

  3. 大変貴著な資料を公開いただき、ありがとうございます。
    質問です。
    「自分専用のTwitterBotを作り方を完全公開します」にそって作業しました。
    「postUpdateStatus」関数は「完了」となりますが、ツイッターに投稿されません。
    原因として考えられることは何でしょうか。
    ご教授いただきたく、よろしくお願いいたします。

    • コメントありがとうございます!
      「関数はエラーが出ずに終了しているが、投稿されない」という状況ですかね。
      考えられる原因としては、messageにデータが入っておらず投稿処理の前で完了してしまうことが1つ考えられます。

      // ツイートを投稿
      function postUpdateStatus() {
      var message = pickUpTweet();
      if (message == "") {
      Logger.log("投稿しませんでした") // ←ここで終了していると完了になるが、投稿はされない。
      return;
      }
      var service = twitter.getService();
      Logger.log(message)
      var response = service.fetch('https://api.twitter.com/1.1/statuses/update.json', {
      method: 'post',
      payload: { status: message }
      });
      Logger.log("投稿しました")
      Logger.log(message)
      }

      Logger.log() を使って message に投稿文が入っているかを見て頂けると原因がわかるかもしれません。
      また躓くことがあればコメントください!

  4. こういうのを探していたんです!!ありがとうございます!!

    あとリクエストなのですがフォローしたりリフォローしたり、フォローされてない人のフォローを解除したりするにはどのようにすればよいのでしょうか?
    【鬼ったー】というサイトを利用してみようとしてみたのですがうまくいかず…
    自分でbotを作ろうと検索してみても古い情報だったりして、よくわからなかったので…
    どうか、よろしくお願いいたしますm(_ _)m

    • コメントありがとうございます!

      ・フォローしたり、リフォローしたり
      ・フォローされてない人のフォローを解除したり

      どんなサイトでもほぼ確実にTwitterのAPIを連携してそのような機能を作っているので、理論上は作れるはずです。
      フォロー/フォロー解除あたりはまだこのブログであまり言及してなかったので近日書こうと思います〜

  5. ありがとうございます!! あと、ランダムツイートする際に1回ツイートしたら次はそれ以外を選ぶようにするにはどうすれば良いのでしょうか?2回、同じツイートができないので….

    • あー・・・確かに今の実装良くなかったですね。。
      何個か方法が考えられます
      ①投稿文を選ぶ前に、直前のツイートを取得して同じ文章のものがあれば選択肢から外しておく
      ②シートに1列増やし、投稿を行ったら前回実行のフラグを立てて、ランダムの選択肢から外しておく
      などですかね・・・

      早速ですが、②の対応、ライブラリに修正入れました!
      ランダム用参考例 を更新したので、参考例を参考に1列追加して、ライブラリを最新のものに更新すると連続した投稿ができないようになっているかと思います。
      うまく動かないようでしたらご連絡ください!

  6. 大変参考になる記事ありがとうございます。まったくの初心者ですが、わかりやすく非常に助かります。最近ようやくデベロッパーアカウントを取得できました。只今、自動投稿アプリの制作を試みております。。

    1つ質問させていただきたいのですが、自動投稿アプリからの投稿は、viaがそのアプリ名になると思うのですが、Twitter for webやTwitter For App のように表示することは可能でしょうか。自作のアプリからいかにも投稿された感を払拭したいのですが。。なにかいい案はありますか。

    • Twitter for webやTwitter For App のように表示することは可能でしょうか

      Twitterの仕様上できないです…!
      アプリ名を「Twitter for 〇〇」にしたり、Twitterクライアントアプリ(SocialDogやfeatherのようなアプリ)のようにBotっぽくない名前にするのが一番簡単ですね…

  7. 返信ありがとうございます。
    なるほど。。そういう仕様なんですね。
    すずきさんのツイートもみさせてもらっているのですが、ツイート元がTwitter For App になっているときがありましたので、そのようにすることもできるのではないかと思ってました。
    以前あったtweet adderというbot作成機能は、ツイート元が「Web」になっていたようですが、もうそのようなものはないんですかね。。

    • > ツイート元がTwitter For App になっているときがありましたので
      正確には『Twitter Web App』だと思うのですが、これはブラウザから投稿したツイートで、
      『Twitter for iPhone』の時はiPhone用のTwitter公式アプリから投稿しています。

      viaはそのユーザーがどのような経路でツイートしたかの情報で、アプリ作成時に世界に1つだけアプリ毎に割り当てられます
      そのため既にある『Twitter for iPhone』のようなアプリ名は付けられないはずです

      tweet adderの場合は、製作者が『Web』という名前でアプリを作れたため、そのviaで投稿できるという仕組みですね
      ただ、もしWeb以外のviaにも出来るのであればちょっと話が変わってくるのでその時は教えていただきたいです!

    • 今回のやり取りのことが気がかりだったので1つ記事を書いてみました。
      個人的には非推奨ですが記事で紹介しているGASを参考にすると出来なくはないです(間違ってコードを『公開』にしないように…!)
      ご参考まで!
      https://belltree.life/tweet-camouflage-by-cookie/

  8. このような記事をありがとうございます。初心者ですがアプリを作成することができました。
    質問です。ライブラリを見たのですが「findRecentTweet」関数は具体的にはどのように使用すればよいのでしょうか?
    取得したデータからIDなどを取り出すにはどうすればいいのか方法がわかりません。。。
    検索したツイートにいいねやリツイートをするアプリをV8ランタイムで作成したいです

    • 参考にして頂きありがとうございます!
      findRecentTweet ですが、

      const result = client.findRecentTweet('検索したいワード');

      のようにするとツイートのデータを取れます。
      IDの取り出し方などはコメントでは伝えづらかったので↓にサンプルコードを置きました。
      https://gist.github.com/belltreeSzk/780ac4cbe92c1a644db9f1a4a3f777bd

      参考にしていただければ幸いです!また何かあったらコメントください!

  9. 返信ありがとうございます。サンプルコードを参考にしていいねやリツイートするアプリを作成することができました。
    また質問です。どのツイートにいいねやリツイートをしたか分かりやすくしたかったので、ログを使っていいねやリツイートしたツイートの文章とツイートした方の名前を表示したかったのですが、文章のほうは取得できましたが同じように名前を取得しようとしてもnullとなってしまい取得できませんでした。
    ツイートした方の名前を取得するにはどうすればよいのでしょうか?

    • ツイートした人の名前だと、

      Logger.log(tweet.user.name);
      Logger.log(tweet.user.screen_name);

      みたいな形式で取れませんかね?

      どこにデータが入っているか、というのは確かにわかりにくいと感じたので新しく記事を書いてみました。
      https://belltree.life/twitterapi-json
      参考になれば幸いです!

  10. MtWJFxCibKiP9SvrKBk8a0_EqweE_tvXn が新しいエディタだとライブラリに追加できないのですが…

    • エディタの仕様変更で使えなくなったっぽいです。。

      1fHCjI78BV3o7nGx2l0lJ7WXM49VFbobGDNdFGqAoVFZyRJ2kepQYzVLd
      こちらで試していただけますか?

  11. 了解しました。ありがとうございます。

  12. こんにちは、初めまして。初心者にもわかりやすい記事いつも参考にさせていただいています。

    先日まで、問題なくBOTが動いたのですが、数日前から突然エラーが出始め「Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {“errors”:[{“code”:187,”message”:”Status is a duplicate.”}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)」と前にもみたエラーのようで、ただその後はまた問題なく動いていたので特に問題にも思わなかったのですが、3日連続(6時間おきのツイート設定にしています)でツイートがされなくなってしまったのでいよいよ問題があると思い、コードを再び丸コピーをし、ConsumerKeyなど入力して実行しようとすると、「Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 401)。サーバー応答の一部: {“errors”:[{“code”:89,”message”:”Invalid or expired token.”}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)(行 457、ファイル「Service」)」とエラーメールと同じエラー文で、Twitter自体の設定も何も変えていないのでどこに問題があるのか、検索しましたが自分ではどうしても解決できませんでした。初心者丸出しで大変申し訳ありませんが、ご教授いただきたくよろしくお願いいたします。

    • 2つのエラーがあるようなので1つずつ解説していきます。
      > Status is a duplicate.
      というエラーですが、連続で同じツイートをしようとした時に出るエラーです。
      Twitterは同じ文章を連続して投稿できない仕様になっています。

      考えられるケースは
      ・投稿文を1種類だけに変更して同じ投稿が連続して選ばれるようになってしまった
      ・手動とBotを並行して使っていて、Botの投稿の間に手動ツイートしていてエラーは回避できていたが、最近放置気味でBotの投稿だけになってエラーが出るようになった
      等かなと思いました。

      解決策としては
      ・2つ以上の投稿をBotに登録する
      または
      ・RTするBotを利用する https://belltree.life/twitterbot-for-retweet/
      をおすすめします。

      > Invalid or expired token.
      というエラーはConsumerKeyを再発行した時に出るエラーです。
      一度 reset で認証を解除して、authorize を行ってみていただけますか?

  13. コメント失礼します。
    こちらの記事のbotを使用させていただきたいと思って使用していたのですが
    getCallbackUrl()関数を実行すると
    エラー「ステートメントの前に ; がありません。(行 5、ファイル「TwitterClient」、プロジェクト「TwitterClient」)」
    が出るのですが、こちらの解決方法わかりますでしょうか?
    よろしくお願いいたします。

    • このエラーは『V8 ランタイム』という設定をしていないと出るエラーです。
      以下の方法でV8ランタイムを有効にしてもらえると動くようになると思うので試していただけますか?

      新しいエディタの場合

      古いエディタの場合

  14. お早い返信、大変助かります。
    文言の連続ツイート回避させるために複数登録しました。
    resetをしてauthorizeしたら無事ツイートされました。

    ありがとうございました。

  15. コメント失礼します。

    エラー
    Error starting OAuth flow: {“errors”:[{“code”:32,”message”:”Could not authenticate you.”}]}
    Service_.getRequestToken_ @ Service.gs:344
    Service_.authorize @ Service.gs:245

    というエラーが出るのですがどうしたらよろしいでしょうか。

    • まずは GASで 『reset』 → 『authorize』 を実行して再度認証を試していただけますか?

      もしこれで改善しなかった場合、GASに記載のConsumerKeysが誤っている可能性があるので、
      TwitterAppから 『ConsumerKeys』 を作り直してGASに反映してみてください。(※注意:再発行という形になるのでこれまで使っていたものは使えなくなります)
      反映した後、再度 GASで 『reset』 → 『authorize』 を実行して再認証を試していただけますか?

      これで出来なかった場合またご連絡ください!

  16. サイド認証したらツイートができました。

    今現在、別のライブラリ(TwitterWebService)と一緒にTwitterClientを使っているのですがエラーが出るのですが(Property store is required.)、複数のライブラリは使う方法ってありますか?

    • 複数のライブラリを使うこと自体は全く問題ないです。

      “Property store is required” のエラーは複数のライブラリを登録したことが原因でなく、TwitterWebServiceで使われている”OAuth1″というライブラリのバージョンが古いせいなんですよね…
      ライブラリのバージョンをあげれば使えるのですが、作者でないと直せないので各自でコピーしてライブラリを作り直す形になると思います。

      具体的な方法は以下にまとまっていたので参考にしてみると良さそうです。
      https://teratail.com/questions/240990

  17. TwitterWebService、OAuth1はV8 ランタイムを無効にすれば正常に動作できたのですが、TwitterClientはV8ランタイムを有効にしないといけないと思うのですが、どうしたら良いでしょうか。(無知ですみません…)

    • すみません、一番簡単な方法がありました。。
      私の方で TwitterWebService のV8ランタイム対応版を作ったのでこちら使ってみてください。

      13Dc4NZZM4Tq0IilFO5o8zbjNkeCSsbPJ7QxYJOvGyfTBaoNS7WFvuG50
      

      コードの中身は本家と同じなので参考されているページと同じように使えると思います。

  18. わざわざありがとうございます。

    なんども申し訳ございません。

    OAuth2用の認証するためのソースコードってありあmすでしょうか(こちらの記事と関係のない質問ですみません…)

  19. twitterAuthorizeUrlを実行して認証させようとすると、

    TypeError: OAuth1.createService(…).setAccessTokenUrl(…).setRequestTokenUrl(…).setAuthorizationUrl(…).setConsumerKey(…).setConsumerSecret(…).setProjectKey is not a function(行 42、ファイル「twitter」)

    というエラーが出てしまいます。

    • 仕事で回答遅くなってしまいました。

      > twitterAuthorizeUrlを実行して認証させようとすると、
      すみません。 twitterAuthorizeUrl ってなんですかね…?

      もしオリジナルでコードを書いていれば全然サポートするんで仰ってください〜
      見られたくないときは tajukado@gmail.com にメールかTwitterにDMして貰えれば反応しますので!

  20. トークンが無効か、有効期限が切れています。もう一度お試しください。
    と出てしまいます…
    APIキーなどは間違ってないんですがね…
    対処法を教えてほしいです

    • 「認証情報をシートが保持したままになっていた」というのは、これまで何回か質問に来たことがありました。
      一度 reset を行って、認証情報を消した後、もう一度 authorize を実行して認証してみて頂けないでしょうか?

  21. Exception: 範囲の行数には 1 以上を指定してください。(行 24、ファイル「Utility」)と出てしまうのですがどのような内容で、どのようにすれば正常に動作しますか?

    • シートに投稿用のデータが入っていないとそのようなErrorが出てしまいます。
      以下のシートを参考に2行目以降にデータを入れて頂けますか?

      TwitterBotシート_サンプル

  22. ありがとうございます。シートをサンプル通り作成してpostTweetを実行してみたんですけどそしたら今度はこちらが出てしまいました。
    TypeError: Cannot read property ‘getLastRow’ of null(行 67、ファイル「Utility」)

    • あ、コピーのときシートの名前も含めてコピーしましたか?

      そのときはシートの名前が「順番に投稿する」になっていると思うので、

      const message = TwitterClient.pickUpTweetInOrder('順番に投稿する');
      

      に書き換えてみて頂けますか?

  23. とってもわかりやすい記事をありがとうございます!
    一通り完成したのですが、エラーが発生致しましたのでお時間ある時にヒントをくださると嬉しいです。

    一度投稿したツイート内容が選択された時(連続ではない)以下のエラーが発生しツイートされません。
    Exception: Request failed for https://api.twitter.com returned code 403.

    reset→authorizeも行ってみましたが残念ながら。。。

    • 参考にして頂きありがとうございます!

      ブラウザからTwitterのサイトで実際に試してみたのですが、
      連続でなくても短時間に同じ投稿は出来ない仕様になっているようです(時間でなく直近何件かを見ているのかもしれないです)

      具体的な対策ですが、同じ投稿で良ければRTの方が、RTしたタイミングで再度タイムラインに浮上するのでこちらの方が良いかと思いました。
      RTの機能は以下の記事にまとめているので参考にしてみてください!
      https://belltree.life/twitterbot-for-retweet/

  24. 分かりやすい記事をありがとうございます。質問なのですが、Authorizeを実行しようとすると Error starting OAuth flow: (?xml version=’1.0′ encoding=’UTF-8′?)(errors)(error code=”417″)Desktop applications only support the oauth_callback value ‘oob'(/error)(/errors)
    Service_.getRequestToken_ @ Service.gs:344
    Service_.authorize @ Service.gs:245 と出てきて先に進めなくなっております…(resetも試しましたしconsumerkeyも最新の状態です)この場合次にどうすればよいでしょうか?

    ※送信の関係上エラーコードの不等号の部分を()に変えております

    • こちらのエラーが出るときはTwitterのアプリ上で設定が不足している時に起きます。
      TwitterAppの設定ページで画像を参考にチェックを付けて、記事を参考にcallbackUrlを登録して頂けますか?



  25. ありがとうございます!websiteURLのところにはどこのサイトを記入すればよろしいのでしょうか?

    • WebsiteURLはBotの動きに直接関係しないのでなんでもOKです。
      https://twitter.com などでも問題なく動くと思います。

  26. 返信遅れましたが無事動きました!ありがとうございますー!

  27. […] ■ご参考リンク(Twitter Botのライブラリを作成) […]

  28. はじめまして、貴重な情報をありがとうございます。
    こちらを参考に設定したのですが、postTweetを実行すると下記のエラーが出てしまいます。ログを全部チェックしたのですが、同様のエラーが無いようでしたので、よろしければ原因と対処法を教えていただけますでしょうか?
    Exception: Request failed for https://api.twitter.com returned code 401. Truncated server response: {“request”:”\/1.1\/statuses\/update.json”,”error”:”Read-only application cannot POST.”} (use muteHttpExceptions option to examine full response)
    Service_.fetchInternal_ @ Service.gs:457
    Service_.fetch @ Service.gs:305
    お手数ですがよろしくお願いいたします。

    • 参考にして頂きありがとうございます!
      エラーを見たところ、

      Read-only application cannot POST.

      と書かれているので、Twitterアプリの権限がRead-Onlyになっているようです。
      permission
      Twitterのアプリを設定する画面の中に↑のような部分があると思うので『Read and Write』に変更していただくと直るかと思います。

      変更したあとに reset を実行して再度 authorize を実行しないと反映されないのでお気をつけください!

  29. 夜遅くなのに素早いご返信をありがとうございます!
    言われたとおりに直しましたら正常に投稿できました。本当に感謝してます。ありがとうございました!

  30. 初めまして!素敵な記事をありがとうございます!
    GASでTwitterのボットを作成するにあたり、以下のエラーが出ました。
    Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {“errors”:[{“code”:170,”message”:”Missing required parameter: status.”}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)
    at Service_.fetchInternal_(Service:457:22)
    at Service_.fetch(Service:305:15)
    全くの初心者なので、知識がなく困っています。ご回答いただけたら幸いです。

    • ”Missing required parameter: status.” というエラーですが投稿文が取得できなかったエラーです。
      まずは
      ① 用意したシートに余計なスペースや意図しない文字が入っていないか
      ② 用意したシートの名前(ファイル名でなく下のタブに書いている名前)が『シート1』になっているか
      を確認してみてください。

      これで解決しない場合は
      ・そもそも postTweet を使っているか
      ・他にエラーやログが出ていないか
      を教えていただけますか?

  31. 初めまして、有益な記事ありがとうございます。今まで過去の記事を拝見させていただいていましたがいつも挫折してしまっていた初心者です。
    今回初めて成功しました。本当にありがとうございました。
    仕事用、趣味用など複数アカウントを取得しており、仕事用アカウントでAPI申請を行い成功しました。
    仕事用APIを使って趣味用のBotもできればと考えていますが、以前の記事の「複数アカウントでツイートするBot」を拝見しましたが、理解するには至っていません。
    もしかしたらアカウントごとにAPI申請しなければいけないのでしょうか?
    お時間のある時にお返事いただければ幸いです。

    • ありがとうございます。
      こちらこそ初めて成功したという話を聞いて本当に書いてよかったと嬉しい気持ちになれました。

      さて本題ですが、結論から言うとアカウントごとのAPI申請は不要です。
      また本記事のTwitterClientのライブラリであれば複数アカウントで〜という部分も気にしなくて大丈夫です。

      簡潔に言うと古い方法(TwitterWebApp)では認証情報を『Googleアカウント毎に』1つしか持てませんでした。
      それをなんとかしようと工夫したのが「複数アカウントでツイートするBot」の記事で、それを踏まえて新しく作ったのが『TwitterClient』です。

      手順は同じで、
      ①新しくスプレッドシートを作り
      ②同じトークンを貼り付け
      ③認証の時に趣味用のアカウントで認証
      で使えるかと思います。

      全く同じトークンだと投稿のviaが仕事用のAppの名前になってしまうのでそこだけ問題ないかご確認ください。
      API申請が通ったアカウントであれば再申請することなく複数のAppを作れるのでそちらもご検討ください!

  32. 早速のご回答ありがとうございました。
    今まで悩んでいたことがクリアになり無事Appが完成しました。

    >③認証の時に趣味用のアカウントで認証
    上記で、仕事用アカウントをログアウトしていなかったのが原因でエラーが出ており、エラーが出た認証URLで再度認証しようとしてダメでした。
    仕事用アカウントをログアウトしてブラウザ再起動、認証URL再発行、趣味アカウントで認証して出来ました。

    本当にありがとうございました。

  33. 初めまして。Botを自作する必要性がありましてこちらのブログにたどり着きました。
    テストでpostTweetを実行すると下記のエラーが出てしまいます。スプレッドシートのチェックボックスにはチェックが付くのですが、投稿は出来ていません。
    何が原因なのかご教授いただければ幸いです。

    Exception: Request failed for https://api.twitter.com returned code 403. Truncated server response: {“errors”:[{“message”:”You currently have Essential access which includes access to Twitter API v2 endpoints only. If you need access to this endpo… (use muteHttpExceptions option to examine full response)
    Service_.fetchInternal_ @ Service.gs:457
    Service_.fetch @ Service.gs:305

    • ページの上部に記載しているのですが、発行しているトークンがessentialのためです。

      以下のページよりelevatedトークンを取得する申請を行ってください(英語で用途等を書く必要があります)
      https://developer.twitter.com/en/portal/products/elevated

      • 迅速な対応ありがとうございます。Google翻訳で申請してみたところ上手くtweetできました。ありがとうございました。

  34. 初めまして、記事を参考にさせていただき、不特定多数のメンバーに対してTwitter認証を行うGASのwebアプリを作成してみました。下記で困っており、助言をいただきたいと考えています。

    ■発生している問題

    GASアプリの所有アカウント以外のGoogleアカウントでログインしているブラウザ上において、Twitter認証画面で「連携アプリを認証」ボタンを押下後、以下メッセージが表示されます

    トークンが無効か、有効期限が切れています。もう一度お試しください。

    ※Twitter上でのアプリ認証も完了していない状態です

    ■アプリの構成
    ・TwitterIDの入力フォームHTML(A)
    ・Aのsubmit内容を元にTwitter認証URLを発行し、Cを表示するGASアプリ(B)
    ・Twitter認証URLへのリンクのみ張られたHTML(C)
    ・Twitter認証のコールバックとして呼ばれ、認証情報をスプレッドシートに書き込むGASアプリ(D)
    ・完了画面HTML(E)

    ■ここまで試したこと
    都度GAS上のUserPropertyをクリアしながら、GASアプリ所有アカウントでログインしているブラウザ上で処理が正常終了することは複数回確認済みです(スプレッドシートへの登録、Twitter上でのアプリ許可も確認済み)。
    ただし、以下の状態で試すと問題が起きております。
    ① どのGoogleアカウントでもログインしていないブラウザで実施(PCはEdge、スマホSafariで確認)
    ⇒Twitter認証画面で「連携アプリを認証」のボタンを押下後、Googleアカウントでのログインを求められる。GASアプリの所有アカウント以外のアカウントでログインすると、「発生している問題」に記載した事象となる

    ② GASアプリの所有アカウント以外のアカウントでログインしているブラウザで実施
    ⇒「発生している問題」に記載した事象となる

    お手すきの際に、何か原因となる点など心当たりありましたらご教示いただけますと幸いです。
    よろしくお願いいたします。

    • > Twitter認証画面で「連携アプリを認証」のボタンを押下後、Googleアカウントでのログインを求められる。
      の部分が気になりました。

      GASのスクリプトを実行する際にGoogleのログインが求められるのですが、「Twitter認証URLを発行」のところではauthorizeを実行していないんですかね?
      authorizeでは認証URLを発行するだけでなく、発行した認証URLと紐づくキャッシュをUserPropertyに保存します。
      そのため(B)はTwitter認証する人のGoogleアカウントで実行する必要があります(つまりここでGoogleログインが求められるべき)

      今は(B)と(D)で実行するアカウントが違うので、コールバックの時に認証URLと紐づくキャッシュが取れず「トークンが無効」と言われてる気がします。

      UserPropertyなども知っていて、ここまでシステム作れている方なので、この情報だけで修正まで辿り着けそうな気はしますが、無理そうor違ったらまたご連絡ください。

      • 早速のご回答、ありがとうございます!

        最初のコメントに記載すべきでしたが、本アプリはオーナーアカウントのスプレッドシートにアクセスする必要がある都合から、デプロイの設定を以下としておりました。

        次のユーザとして実行:「自分」
        アクセスできるユーザ:「全員」

        そのため、アプリの実行自体はcallback含めて常にオーナーアカウントで実行される想定だったのですが、
        初回アクセス⇒オーナーアカウント
        callback関数呼出し時⇒ユーザアカウント
        での実行となってしまうことでキャッシュ情報の不整合が起きてしまっているということですね、、

        試しにスプレッドシートを共有にした上で、アプリのデプロイをユーザアカウント実行として実施したら正常終了となりました。

        アプリの公開にあたってはスプレッドシートの共有が少しネックではあるのですが、URLがユーザにわかることはないためリスクを受け入れるか、別のGASアプリを噛ませて何とか秘匿性を保つかなど、少しやり方は考えようと思います。

        アドバイスいただきとても助かりました、ありがとうございます。

  35. 無料でこのようなツールを公開していただきまして、ありがとうございます。
    本当に素人なので四苦八苦しながらなんとか実装し、4~5ヶ月前から運用しております。
    画像付きツイートで運用しているのですが、割と同じツイートが選択されてしまうことが多く、気になっていました。
    そこで、久々にUtility.gsを見に行ったら、「投稿された回数をシートに保存しておき、一番投稿された回数が少ない記事を次の記事にする」というメソッド?を発見いたしました。(4〜5ヶ月前から存在しておりましたでしょうか?)
    現在GAS上では、
    function postTweetWithMedia () {
    const postData = TwitterClient.pickUpTweetDataRandom();
    client.postTweetWithDriveData(postData);
    }
    としているのですが、どのように変更したら先ほどのメソッド?が呼び出せますでしょうか。
    (googlespreadsheet上で何か変更が必要になりますでしょうか?投稿回数の行を作る必要があるなど)
    できれば画像添付と重みづけの機能は残しつつ投稿数が少ない項目から選ぶ、という事ができるとありがたいのですが・・・(重みをa、投稿回数をbとすると、b÷aが最も小さい項目をツイートする、など)
    都合の良いことばかり言って申し訳ありませんが、何か方法があればご教示いただけますと幸いです。

    • 4~5ヶ月前は覚えてないですね…

      「投稿された回数をシートに保存しておき、一番投稿された回数が少ない記事を次の記事にする」
      にあたるメソッドの画像つき版は
      『TwitterClient.pickUpTweetDataInOrder();』
      になります。

      function postTweetWithMedia () {
          const postData = TwitterClient.pickUpTweetDataInOrder();
          client.postTweetWithDriveData(postData);
      }
      

      という形で変更してみてください。
      シートの構成は以下のシートを参考にしてください。
      https://docs.google.com/spreadsheets/d/1Xr1G4FTglcE68j7eylcrwJgQtzfN0AB3K7EKZMIFQ8I/edit#gid=98578108

      pickUp~~~系のメソッドは1例として用意しているだけなので、自分で作っても大丈夫ですよ。
      該当のメソッドをコピーして自分のGASファイルに持ってくればセルの位置を変えたり追加の処理を入れられるのでいい感じでやってもらえるとです!