【TwitterAPI ver2対応】自作TwitterBotの作り方

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

ご無沙汰してます。久しぶりの更新で申し訳ないです。

これまで以下のページでTwitter専用のGASライブラリを公開していましたが、Twitterの仕様変更に伴い申請が必須になっておりました。

今回はTwitterの仕様変更に対応した新しいTwitterのライブラリを用意したので紹介します。

解説動画を公開しています

【無料】定期的にツイートするTwitterBotを作ろう!【GAS】

ライブラリの紹介

前回作成したライブラリの反省から機能を分割しました。

TwitterClient2

スクリプトID: 1VSmE-pfiIv6OBa1O1OMorDUI5Cv50s7KM9bg-PwvQlFIXk8ghuH4DrHl
コード: https://script.google.com/home/projects/1VSmE-pfiIv6OBa1O1OMorDUI5Cv50s7KM9bg-PwvQlFIXk8ghuH4DrHl/edit

GasBotKit

スクリプトID: 1t0F6mdxpD7GIU5LaoBg6Ie9YZHfV7eqFSd6zNnct2QvuwAegHgcfdJNC
コード: https://script.google.com/u/0/home/projects/1t0F6mdxpD7GIU5LaoBg6Ie9YZHfV7eqFSd6zNnct2QvuwAegHgcfdJNC/edit

TwitterClient2はTwitterの機能に特化したライブラリです。

認証〜各種APIの実行までを行うことが出来ます。

GasBotKitはスプレッドシートからデータを取得することに特化したライブラリです。

投稿文を順番に取得したり、ランダムに取得することが出来ます。

将来的にSlackClient(仮名)やInstagramClient(仮名)を作ったときに再利用できるのでこのような形にしています。

導入方法・使い方

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

今回は基本となる『順番に投稿するBot』を作ります。

スプレッドシートは

TwitterClient2投稿サンプル
順番に投稿する(pickUpDataInOrder) 投稿回数,投稿文,オプション1(未実装),オプション2(未実装),オプション3(未実装),オプション4(未実装),投稿文,オプション1(未実装),オプション2(未実装),オプション3(未実装),オプション4(未実装) 10,テスト,テスト4 5,テスト2,テスト5...

を参考にしてください(以前のシートと少し形式変えたので注意)

ライブラリを登録する

今回は2つ登録します。

1VSmE-pfiIv6OBa1O1OMorDUI5Cv50s7KM9bg-PwvQlFIXk8ghuH4DrHl
1t0F6mdxpD7GIU5LaoBg6Ie9YZHfV7eqFSd6zNnct2QvuwAegHgcfdJNC

コードを貼り付ける

以前のコードとほとんど変わりませんが、 以下の点が変わりました。

const client = TwitterClient2.getInstance(CONSUMER_KEY, CONSUMER_SECRET)
const data = GasBotKit.pickUpDataInOrder('シート1');

TwitterのAPIを実行するライブラリとシートを解析するライブラリを分割した影響です。分かりにくければコメントください💦

注意点

TwitterClient2は Twitter API v2 向けのライブラリです。

その影響でTwitterClient2は以前出来ていたファイルのアップロードが出来ません(2022年4月現在)

もしも画像や動画を含む投稿をしたい場合はElevatedのトークンを申請して、旧TwitterClientのライブラリをご利用ください。

利用できるAPI一覧は以下になっています(※『OAuth 1.0a User Context』『OAuth 2.0 App Only』にチェックが付いているものは利用できます)

Twitter API v2 authentication mapping

コメント

  1. すみません、上記の記事とは違った質問になります。

    ですが、こちらに投稿しようとすると、


    不正なパラメーターが送信されたため、アクセスをブロックしました。
    対応方法については、こちらをご確認ください。

    と表示されて投稿できませんでした。
    どの文字を除外すればいいのか試したのですが解決しませんで、
    テキスト共有サービスに質問文を投稿しました。

    https://writening.net/page?ejGYw3

    こちらになります。

    お手数おかけいたしますが、上記お読みいただいて何かアドバイスいただけるとありがたいです。

    よろしくお願いします。

    • うお。すみません。返答完全に忘れていました。
      あとこちらの質問、場所が違うので解決次第、削除させてください!

      本題ですが、一度TwitterClientのライブラリのバージョンを確認して頂けますか?
      以前、リツイートを既にしていた場合エラーが出るため修正を入れたのですが、それが入っていないようです。
      今はバージョン22まであるので、もし古ければ22にして同じように試して頂きたいです。

  2. すみません、上記の質問の追記です。

    ログを眺めていたら下記のように失敗と成功があって。
    理由不明なのですが…。

    retweetLatest 時間主導型 2022/04/17 0:03:23 28.524 秒 失敗しました
    retweetLatest 時間主導型 2022/04/16 20:03:23 104.463 秒 完了
    retweetLatest 時間主導型 2022/04/16 16:03:23 62.205 秒 完了
    retweetLatest 時間主導型 2022/04/16 12:03:23 12.082 秒 失敗しました
    retweetLatest 時間主導型 2022/04/16 8:03:23 9.925 秒 失敗しました
    retweetLatest 時間主導型 2022/04/16 4:03:23 21.05 秒 失敗しました
    retweetLatest 時間主導型 2022/04/16 0:03:23 52.481 秒 失敗しました
    retweetLatest 時間主導型 2022/04/15 20:03:23 167.856 秒 完了
    retweetLatest 時間主導型 2022/04/15 16:03:23 287.649 秒 完了
    retweetLatest 時間主導型 2022/04/15 12:03:23 137.398 秒 完了

    成功することもあるのです。

  3. 22でした。

    ここ直近の成功率は9/20という感じで約50%です。

    • 原因まだ掴めてないのですが、一点だけ不具合が起きそうな部分を修正してみました。
      バージョン25をリリースしたので、バージョンを変えて試して頂けますか?

  4. バージョン25で試した所、下記のエラーで実行できないようです。

    一応、reset、authorize、してからRetweetLatestしました。

    エラー
    Error: 認証されていません
    at getRequest(TwitterClient:125:13)
    at getTimeLine(TwitterClient:290:36)
    at pickupTweetsLatest(TwitterClient:254:27)

    その後、22に戻して、reset、authorize、してからRetweetLatestとしても下記のエラーが出るようになってしまいました。

    エラー
    Error: 認証されていません
    at getRequest(TwitterClient:125:13)
    at getTimeLine(TwitterClient:290:36)
    at pickupTweetsLatest(TwitterClient:254:27)

    認証で失敗しているのでしょうか?

    どのようにしたらよいかアドバイスいただけるとありがたいです。

    よろしくお願いたします。

    • Error: 認証されていません
      が出るのは認証できていない状態なので、authorizeした時に表示される認証用のURLに遷移して、認証されるか確認してみてください。
      バージョンは一応25にしていただけると!

      • あー、すみません、ようやく理解しました。

        authorizeは完了と出ていたので処理終わっていたと思っていました!

        表示されたURLで連携して無事動きました!

        しばらく4時間周期で動かしてみます。

        お手数おかけいたしました。
        ありがとうございました。

  5. たびたびすみません…

    [
    ‘hogehoge1’,
    ‘hogehoge2’,
    ‘hogehoge3’,
    ‘hogehoge4’
    ]


    この方法でアカウントが100個以上に増えてきたのですが、ある時から必ずエラーになってしまうようになってしまいました。

    ↓エラー内容↓
    Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 404)。サーバー応答の一部: {“errors”:[{“code”:34,”message”:”Sorry, that page does not exist.”}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)(行 457、ファイル「Service」)
    ↑エラー内容↑

    アカウント数を30個とかに減らすと通るようですが、それでもだめでさらに減らさないと駄目な時もあります。

    何か良い方法ございますでしょうか?

    よろしくお願いたします。

    • エラーだけ見ると『アカウントやツイートが存在しない』というエラーなので、設定した100個のアカウントの中に取れなくなったアカウントがいる気がします。

      アカウントの中にNGなものが含まれているせいで最後まで行かないのであればtry-catchを仕込むと良いかもです。

      /**
       * ③最新のツイートをリツイートする
       */
      function retweetLatest () {
        // 最新のツイートのツイートIDを取得する
        const accountNames = ['belltreeszk', '****', ...]; // 対象のアカウントの @~~~~ の部分を記入
        const includeRT = false; // RTを含むか(セルフリツイート以外の通常RTも含みます)
        const retweetCount = 5; // 直近何件のツイートをRTするか
        for (let i in accountNames) {
          const accountName = accountNames[i];
          try {
            const tweetIds = client.pickupTweetsLatest(accountName, includeRT, retweetCount);
            client.retweet(tweetIds);
          } catch (error) {
            console.warn(error);
            console.warn(accountName);
          }
        }
      }
  6. ありがとうございます!!

    動くようになったようです。
    これでしばらく様子見てみます。

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

    追記:

    一箇所、;が:になってました
    (^^);

    • お、良かったです。
      > 一箇所、;が:になってました
      こっそり直しときました…w

  7. たびたびすみません…

    「タイムアウト」というエラーが表示されるようになりました
    (これは𝔹𝕖𝕝𝕥𝕫さんのスクリプト使いはじめて今まで初めてです)

    今までは、「完了」、または「失敗しました」のみでした。

    ログの中身を見ると、成功している行の間に時々、下記のような「警告」行があります。
    (この警告も初めてです)

    hogehoge##はツイッターのIDです。

    ↓↓↓↓↓
    2022/04/27 20:55:05
    警告
    { [Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {“errors”:[{“code”:327,”message”:”You have already retweeted this Tweet.”}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)] name: ‘Exception’ }
    2022/04/27 20:55:05
    警告
    hogehoge01

    2022/04/27 20:55:10
    警告
    { [Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {“errors”:[{“code”:327,”message”:”You have already retweeted this Tweet.”}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)] name: ‘Exception’ }
    2022/04/27 20:55:10
    警告
    hogehoge02
    ↑↑↑↑

    こちら何かお分かりになりますでしょうか…?

    たびたびもうしわけありません。

    よろしくお願いたします。

    • タイムアウトの件はググるとすぐわかりますね。
      https://hajiritsu.com/gas-timeout-error-routine/
      GASの場合、6分以上掛かると強制終了します。
      量が増えるとどうしても時間がかかるので、シートを分けるとか工夫が必要ですね。

      ちなみに先日行ったtry-catchは『失敗しても次の人にいく』という処理です。
      警告で表示されるユーザーはエラーが起きたユーザーです(これまで止まっていたのがスキップするようになりました)
      これに関しては『警告されたユーザーの最新のツイートがリツイートされているか』を確認してみてください。

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

    2つのシートに分けて分散して動作させた所、どちらも正常に動作するようになりました。

    お忙しいところありがとうございました!

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

    GasBotKitでランダムにデータを取得したいのですがどのようにすれば良いのでしょうか。
    pickUpDataRandomを使用してみたのですがシートの形式があっていないのか、2行目のみが取得されてしまいます。
    また、TwitterBotは作成せずにGasBotKitのみを使用したいのですがなにか問題などはないでしょうか。

    どうかよろしくお願い致します。

    • すみません。ver1のコードを雑にコピペしてしまったせいでうまく動いてなかったです。。
      GasBotKitのversion7をリリースしましたのでお試しください!
      シートは以下の形式でお願いします。
      https://docs.google.com/spreadsheets/d/13g0-frl0AsIhYfc7Htb-RY5JsV_h1FGL37yiXzSaGyI/edit#gid=2090133204
      また投稿文の列が変わるので少々コードに修正が必要なります。

      /**
       * メイン処理
       */
      function main() {
        const data = GasBotKit.pickUpDataRandom('シート1');
        client.postTweet(data[2]); // 左端が0番目とすると投稿文は2番目
      }
  10. 返信ありがとうございます。

    バージョンとシートの形式を変更したところ、正常に動作するようになりました。

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

  11. すみません。またコメント失礼いたします。

    searchRecentTweetsを使用したいのですが利用方法がわかりません。
    定期的にツイートを検索して、検索されたツイートの内容や日時をスプレッドシートに記録していくものを制作しようとしています。

    ですが日時などの細かい情報を取得するにはオプションパラメータを設定しないと取得できないようでした。
    試行錯誤したのですがうまくいかず。。どのようにすればオプションパラメータを設定することができるのでしょうか。

    ご教授いただければ幸いです。

  12. すみません。自己解決しました。
    パラメータを変数に入れればよかったんですね。。。

  13. 何度もすみません。検索コマンドを使用して検索するとツイートがうまく取得できなくなってしまうのですが、どのようにすればツイートを取得できるのでしょうか。

    試しに”猫%20filter%3Avideos%20-from%3Acatdreams5%20-from%3Atyomateee2″とコマンドをつけて検索してみたところ
    結果が”{meta={result_count=0.0}}”になってしまいました。ほかのコマンドでも同様です。

    どうかよろしくお願いいたします。

  14. 正常にコメントを取得できるようになりました。ありがとうございます!

  15. コメントじゃなくてツイートでした。。。

    あとhas:~~に直してもツイートが取得できなかったので色々試したところ、
    User authentication settingsのOAuth 2.0をオンにしたら正常に取得できるようになりました。
    そのあとオフにしても正常に取得できています。

    何処かで「解決した方法は残しておいたほうがいい」と聞いたので記載しておきます。同じ症状で悩んでいる方は試してみてください。

    • 最高な補足です!ありがとうございます!

  16. はじめまして

    記事の内容で、テストが一回目は実行が成功しましたが、

    できたり、できなかったりと安定しません。

    原因がわかりません。ご教授いただけますでしょうか?

    条件

    〇時間 一分毎 (テストのため)

    〇出たエラー

    Error: 認証されていません
    TwitterClient2.postRequest @ TwitterClient2.gs:321
    TwitterClient2.postTweet @ TwitterClient2.gs:81


    Exception: Request failed for https://api.twitter.com returned code 400. Truncated server response: {“errors”:[{“message”:”Please include either text or media in your Tweet.”}],”title”:”Invalid Request”,”detail”:”One or more parameters to your req… (use muteHttpExceptions option to examine full response

    また、他の方の質問にある
    TwitterClientのライブラリのバージョン 22とは何でしょうか?

    私のライブラリの場合(TwitterClient2) 16が最新として表示されています。。

    • ① の『Error: 認証されていません』は記載の通り、認証が切れていることが考えられるので、一度 reset を実行したあとに authorize を実行して再認証してみてほしいです。
      ② のエラーは投稿の際に空白の箇所が選択されていて投稿に失敗しているエラーです。
      シートの列に抜けがないか、または関係のない行に文字が書かれていないかご確認頂けますか?

      > TwitterClientのライブラリのバージョン 22とは何でしょうか?
      こちらについては別のライブラリの話をしていました。
      https://belltree.life/twitterbot-library/

      ver2の方が将来の仕様変更に対応できるので今のままお使いください!

  17. 𝔹𝕖𝕝𝕥𝕫

    早速のご連絡ありがとうございます

    スプレッドシートに余計なメモを入れていたため、
    テンプレート以外の書き込みをなくしたので、無事動きました

    すみませんが、追加で質問させてください

    おそらくですが、投稿回数が2回以上行った段階で、以下のエラーにより

    投稿が失敗します

    翻訳にかけたところ、「重複するツイートの投稿は許可されていない」とのことなので、

    短時間に同文をつぶやいたことにエラーであっていますでしょうか?

    条件

    時間 1分ごと

    以下、実行数のログより

    Exception: https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {“detail”:”You are not allowed to create a Tweet with duplicate content.”,”type”:”about:blank”,”title”:”Forbidden”,”status”:403}(応答の全文を見るには muteHttpExceptions オプションを使用してください)
    at Service_.fetchInternal_(Service:457:22)
    at Service_.fetch(Service:305:15)

    • そうですね。
      連続していなくても近い時間に同じ内容の投稿をするとエラーになります
      (twitterの公式ページから投稿しても同じ投稿をするとエラーになります)

      頻度を抑えたり、ツイートの種類を増やすなどして対応したほうが良いと思います!

      • ありがとうございます😂

  18. べるつさん初めまして。
    大変参考になる記事ありがとうございます。
    丁寧なご説明のおかげで動画付きの投稿をbot運用するまでこぎつけることができました。

    次のステップとして、下記実装したく存じます。ですが過去記事等拝見しましたが見つけることが出来ず。この場を借りてご教示ください。

    ■やりたいこと
    ①本投稿
    ②サブ投稿
    ★①に対して②をスレッド投稿(ツリー投稿)をほぼ同タイミングで行う(数分以内)

    ■運用面
    今のスプレッドシートは
    A列 投稿内容
    B列 投稿回数
    C-F列 Google drive URL
    です。
    イメージでは
    同じ行のG列以降にスレッド投稿内容を記載し運用できればと存じます。

    お忙しいところすみませんがよろしくお願いします。

    • 本投稿をした結果に書いてあるIDをリプライ対象に投稿を行えばスレッド投稿になります

      リプライに対応したバージョンをリリースしたので、TwitterClient2をVer17以上にした上で以下のコードを参考にプログラムを書いてみてください

      https://gist.github.com/belltreeSzk/b26d27132cc03a99ec271d2e7ef502ec

      • べるつさん
        お返事が遅くなり大変申し訳ございません。
        また、早々にご回答ありがとうございます。

  19. 神記事!
    ほんとこんないい記事を投稿していただき感謝感激です。
    人間国宝です

  20. 非常に勉強になる記事ありがとうございます!
    うまくいかない部分がありご質問なのですが、スプレッドシートとApps Scriptのファイルは配置する箇所に決まりはありますでしょうか?

    main関数を実行すると以下のシート名をうまく拾えていないライブラリ側エラーが出力されます。
    (初歩的な質問で申し訳ありませんが、スプレッドシートの在りかをどうやって判断しているのかな?と疑問に思いました)
    ご確認いただけると幸いです。

    TypeError: Cannot read property ‘getSheetByName’ of null
    initSheetCells @ common.gs:19
    pickUpDataInOrder @ common.gs:36

    • 決まり、ありますね!
      AppsScriptのファイルは単体でも作れるのですが、今回はスプレッドシートのメニューの『拡張機能』→『AppsScript』から作ってください。

      作り方によってAppsScriptの概要欄に記載のコンテナの情報が変わります。

      • 迅速な返信ありがとうございます!
        おー完全に見落としておりました。こちらの方法でScriptファイル作成してうまくbot動作させることできましたTT

        本当にありがとうございます!!

  21. はじめまして。こちらを参考にボットを作成していますが、「missing ; before statement」というエラーが、出てしまい、困っています。動いていたのですが、突然投稿が不安定になり、確認した次第です。どこを直せばよいか、教えてください。よろしくお願いいたします。

タイトルとURLをコピーしました