定期的にリツイートを行うTwitterBotの作り方

GAS/TwitterBot
two 3d humans give their hand for handshake
この記事は約7分で読めます。

久しぶりにTwitterBotに対するご要望を頂きました。

「毎日、任意の時間(たとえば朝・昼・版の一日3回)に、最新10ツイートを自動でセルフリツイートする」といったことをしたい

任意のリスト(DMや外部連携)に貼り付けられたツイートをリツイートしたい

リツイート関連のTwitterBotの需要ってかなり高いんですね。。

以前、リツイートを行うTwitterBotを作ったのですが、こちらは指定した単語を含むツイートがあったらいいねやリツイートするものでした。

今回はご要望にあったリツイートに特化して

  • 特定のユーザーの最新ツイートを定期的にリツイートするTwitterBot
  • 指定したツイートを定期的にリツイートするTwitterBot

この2つの機能を簡単に導入できるようにライブラリを更新しました。

今回の記事では、その使い方、実装内容や注意点を解説していきます。

定期的にリツイートを行うTwitterBotの作り方

最初の基本的な準備は以下の記事を参考にしてください。

ざっくりとした流れとしては

  1. Googleスプレッドシートを用意する
  2. Google Apps Scriptを用意する
  3. TwitterClientライブラリを導入する
  4. コードをコピペする(今回もここをカスタマイズします)
  5. 認証を行う

となります。

1fHCjI78BV3o7nGx2l0lJ7WXM49VFbobGDNdFGqAoVFZyRJ2kepQYzVLd

こちらのIDのライブラリの最新のバージョンを更新してご利用ください。

特定のユーザーの最新ツイートを定期的にリツイートするTwitterBot

“セルフリツイート”という形で要望頂きましたが、自分自身を指してもらえばセルフリツイートになるので、特定のユーザーの最新ツイートを定期的にリツイートするBotの実装方法を紹介します。

スプレッドシートの準備

今回の場合すべてTwitter上のデータで完結するので白紙のスプレッドシートでOKです。

コード

ライブラリを作った話のコードの③の部分を上記コードに差し替えてください。

自身のツイートをリツイートしたい場合はaccountNameを自身に、誰かのツイートを追ってリツイートしたい場合はaccountNameをその人のアカウントにすれば取得できます。

自分のツイートだけをRTする場合はincludeRTはfalse、他の人のRTも含めてRTしちゃう場合はtrueにしてください。

リツイートする数を調整したい場合は、retweetCountを調整してください。

指定したツイートを定期的にリツイートするTwitterBot

リリースした後に定期的に特定のツイートを繰り返しリツイートしたいとか、そういう場合はこちらが参考にしてください。

スプレッドシートの準備

参考例を用意しました(参考にするほどでもない内容だけど…)

A列にツイートの詳細のURLを貼り付けていってください。

コード

こちらはシートから一覧を取得するだけですので比較的シンプルです。

シートのURLからツイートIDを取っていくのでそのままRTを行います。

コード例

最後に「全体としてこんな感じになるよ」という例を書きます。「なんかどうしても動かないんだけど」という時の参考にしてください。※consumerKey と consumerSecret は各自書き換えてください!

指定した時間に繰り返し実行するには?

コピペしただけでは定期実行はされません。GASにはタイマー機能があるのでそれで設定を行います。

以前使い方を図で解説しているので参考してください!(ポチポチするだけなので簡単なはず)

自動的に投稿するように設定を行う

解説&使用上の注意点

最後に今回の実装の内部実装を紹介します。

今回作成した関数は

  • pickupTweetsLatest
  • pickupAllTweetLink
  • retweet

です。

pickupTweetsLatest

pickupTweetsLatestでは指定したアカウントの最新のツイートを取得する機能ですが、一番実装方針を悩まされました。

最新のツイートの定義は人によって曖昧で、ユーザーの要望に合わせたカスタマイズ性が必要でした。

『最新の5件』を取得する場合、Twitterの最新のツイートを取得するAPIは図の黄色の範囲になります。

ただ、自分のツイートのみに限定したものが適切では?という考えや、別アカウントのツイートを含めて複数回RTする仕様が良いという声もあり、pickupTweetsLatest では図の赤と紫の範囲のツイートを選択式で選べるように実装しています。

またRTや@を含まない最新の5件を取得するとAPIでは黄色の範囲しか取得しません。

そのためAPIで多めに取得して適切に5件取得できるように実装しています。

その影響で10件取得したい場合でもAPIでは30件分取得している可能性もありえます。

極端に数が多い場合、APIで取得しきれないエラーが出たり、APIを叩きすぎてエラーになる可能性はあるので、常識の範囲内でご利用ください(ちなみに@やRTを含めた直近100件までは見てきます)

この辺に関しては結構力技で実装してしまっているので解説はしませんが、興味のある方はは GitHubTwitterClient – Google Apps Script でコードを公開していますので御覧ください。

pickupAllTweetLink

特に特筆する内容はないですが、今の実装ではシートに書いてある全てのツイートを一度にごっそりリツイートします。

例えば10個のツイートを順番にRTしていきたいという場合、今回は自分で考えてもらいたいかなと思ってます。

ヒントになる記事は既に書いているからです(似たような処理を何度も書きたくなかった)

↓の記事では投稿文を順番に取得して、ツイートを投稿しています。

投稿文ではなくリンクを取得して、IDを渡せば…?

こういう組み合わせから「プログラミング楽しい」と思ってくれると嬉しいなぁ(´・ω・`)

retweet

これも普通にリツイートの処理だけでは行っていないです。

通常のリツイートのAPIは既にリツイートされている場合はエラーを返す仕様になっています

ただリツイートを一度消して再度リツイートすると再度上位に上げることが出来るので、この機能を活かすべく、内部処理ではリツイートされているものが対象になっている場合は一度リツイートを削除した上で再度リツイートしています。

注意点ですが引数が配列なので自分でカスタマイズする場合はTweetIdをStringのまま送らないように!

まとめ

ライブラリのコードは GitHubTwitterClient – Google Apps Script で見ることが出来ます。

興味のある方は御覧ください(GitHub手動で更新してるので反映遅いかも)

また引き続き質問や要望承っています。

週末など時間が空いた時に作るので緊急性の高いものは厳しいですが、「今度この作り方の解説して」と言われれば多分作ります。やらなくても個人ブログなのでそこんとこは許してクレメンス(´・ω・`)

今後の予定ですが、

  • ブログでの解説がごちゃごちゃしてきているので綺麗にまとめて技術書化をすること
  • GASで各々で作ってもらう形式でなく、簡単に導入が出来るサービスを作ること

この2つを目標にしています。

へただなあベルツくんへたっぴさ……..!収益化のさせ方がへた….。」と言われないように少しずつ価値あるもの作っていきたいと思います(コメントで応援くださるとモチベーション上がります)

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

コメント

  1. take より:

    初めまして!すごく参考になりました!ありがとうございます!
    プログラミングしたことがないのですが、もし「複数のアカウントを指定してRTする」という操作をしたい場合、

    const accountName = ‘a’
    const accountName2 = ‘aa’

    という風に増やせば実行できますか?

  2. take より:

    2度送信になってるかもしれません(汗
    プログラミングが初めてのものです。

    このサイトを見て、「指定した複数のアカウントのツイートをRTする」という操作を実行したいのですが、
    ③のコードの

    const accountName = ‘a’
    const accountName = ‘aa’

    という風に増やして実行することであってますでしょうか?
    動くには動きましたが、バグがあるかどうか仕様が分からないので教えていただけると嬉しいです!

    また、現在の仕様の場合、ツイートの取得を定期的に時間をセットして確認するようになっていますが、
    これをツイートしたら即RTするという風に書き換えるにはどうしたらいいでしょうか?

    • 𝔹𝕖𝕝𝕥𝕫 より:

      参考になってよかったです〜

      『特定のユーザーの最新ツイートを定期的にリツイートするTwitterBot』 を複数アカウントで対応する場合ですが、色々やり方はあります。

      takeさんの行ったような書き方でも動くには動きます
      constで同じ名前の変数を書いてしまうとエラーになるので別名にしなければいけないですが↓こんな感じになるかと思います。
      https://gist.github.com/belltreeSzk/33eb3bed5e0b045602fd5a582c6daeb0

      ただそのようにすると対象者が増えた時に大変なので、↓のように書くとスマートなのでお試しください!(accountNamesにカンマ区切りで追加するだけで動きます)
      https://gist.github.com/belltreeSzk/548c746b8749ee7ff8c9d7a1969b2930

      > ツイートしたら即RTするという風に書き換える
      これGASでは出来ないんですよね。。
      即RTをするにはTwitterのサーバーを24時間監視するプログラムを書く必要があるのですが、
      GASは長い時間プログラムを動かし続けられる機能がないので実行時間の間隔を短くしてカバーする方法しかないのです。。

  3. take より:

    うわ・・・めちゃくちゃ簡単にできますね・・・笑
    すごく面白いです!!ありがとうございます!!

    あと、動かしてみて思ったのですが、すでにRTされているものも定期的にRTさせるとRT対象に含まれてしまいます。
    これを取り除く方法はあるのでしょうか?

  4. take より:

    おおおおお!!!ありがとうございます!!!
    以前いただいたコードと組み合わせたら複数アカウントでも動きました!!ありがとうございます!!!

  5. 瑠璃 より:

    コードを読んでなんとなく分かる程度の初学者です。こういう記事を探していました、ライブラリーをインポートするだけなんてめちゃくちゃありがたいです!本当に助かります……!

    RTの自動化につきまして、「リスト内の全ツイート(リプライやRTも含む)を一定件数遡り、それらを古いものから順にRTする(ただし、すでに自分が行ったRTは取り消さない)」という処理をさせたいのですが、下記の2点について教えてください。

    1) RT対象のユーザーを複数指定する際、Twitter IDを列挙する代わりに、リストのURLを用いて同様の結果を得る方法はありますか?

    2) 公開してくださっているretweet関数をそのまま実行すると過去のRTが取り消されるため、ライブラリーのコードを改変して使用させていただきたいのですが、改変後のものを新たなライブラリーとして保存するにはどうすればよいですか?

    お忙しいところ恐縮ですが、よろしくお願いいたします。

    • 𝔹𝕖𝕝𝕥𝕫 より:

      色々参考にしていただいてありがとうございます!

      > 1) RT対象のユーザーを複数指定する際、Twitter IDを列挙する代わりに、リストのURLを用いて同様の結果を得る方法はありますか?
      あります。
      リストのURLからリストに登録されているメンバーを取得するAPIがあるのでそれを使ってみましょう!
      https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/create-manage-lists/api-reference/get-lists-members
      サンプルコードも作ったので参考にどうぞ!
      https://gist.github.com/belltreeSzk/8c86330b4e05bcb5324f263c3c895664
      ただ 1) の方法だと、メンバー間でツイートの頻度に偏りがあっても平等に指定した数のツイートを取得することになりますね。

      > 2) 改変後のものを新たなライブラリーとして保存するにはどうすればよいですか?
      その場合は別のライブラリとして作ってしまってもらったほうが簡単です(著作権的なものは個人利用の範疇なら気にしてないので大丈夫です)
      良い機会だったので、ライブラリを新しく公開する方法を記事にまとめてみたので、こちらご参考ください。
      ササッと書いたので、もしわかりづらい場合コメントください〜
      https://belltree.life/google-apps-script-library-publish/

  6. 瑠璃 より:

    お返事が遅くなり申し訳ありません。
    参考だなんてとんでもない、勉強になってます……!
    サンプルコードまで書いてくださりありがとうございました、個人利用(商用でない)で使わせていただきます!

  7. 瑠璃 より:

    度々すみません。
    上のコードだと、取得したメンバー一人一人に対してfor文が回るため、例えばAさんとBさんの2人からなるリストに対して実行すると、自分のタイムラインが

    ↑新しい

    ・RTしました! 2021-03-21
    ・RT: Bさんのツイート「~~~」 2021-03-20
    ・RT: Bさんのツイート「~~~」 2020-01-01
    ・RT: Bさんのツイート「~~~」 2019-01-01
    ・RT: Aさんのツイート「~~~」 2021-03-19
    ・RT: Aさんのツイート「~~~」 2021-03-18
    ・RT: Aさんのツイート「~~~」 2015-01-01
    ・これからRTします! 2021-03-21

    ↓古い

    というふうになるかと思うのですが、これを時系列順にRTするにはどうすればよいでしょうか……?
    lists/statuses で得たツイート一覧を配列に格納すればいけると踏んでいるのですが、書き方が分かりません……。
    何卒よろしくお願いいたします。

  8. 瑠璃 より:

    あー、なるほど!
    分かりやすい説明、ありがとうございました……!

  9. 瑠璃 より:

    頂いたコードでなぜか取得漏れが発生したので、やはり lists/statuses を利用しようと思うのですが、

    const ListURL = ‘https://api.twitter.com/1.1/lists/statuses.json’;

    と書き換えてコードを実行後、 ListResult に返される長いデータから id_str のみ取り出すにはどうすればよいですか?

    頂いたコードは、 ListResult に返されるデータのうち、各メンバーの users という項目から screen_name だけ取り出しているのだろうと考えたのですが(間違っていたらすみません)、 lists/statuses から返されるデータを見ても id_str の親(?)項目がなく、どのように書き換えたらよいか分かりません。検索していく中で目にした JSON.parse() なども試してみましたが、うまくできずお手上げです。

    よろしければお手すきの際にでもご教示いただけますと幸いです。

    • 𝔹𝕖𝕝𝕥𝕫 より:

      忙しくて返信できておりませんでした。。

      const listResult = client.getRequest(listURL, listParam);
      

      このように結果を取得しているのであれば、

      Logger.log(listResult[0].id_str);
      

      で id_str を取得できるかと思います。
      for を使って全部取りたい場合だと以下のような感じになります。

      for (let i = 0, il = listResult.length; i < il; i++) {
          Logger.log(listResult[i].id_str);
      }
      

      > 返されるデータを見ても id_str の親(?)項目がなく、
      これ、慣れてないとわからないですよね…
      JavaScriptのデータには "配列" と "連想配列(オブジェクト)" というものがあります。
      users などの親項目(正しくはkeyと呼びます)があれば、〇〇.users という形で取れるのですが、
      今回のような同じものが複数入っているデータだと配列というものになり 〇〇[数字] でデータを取ります。

      今回は配列形式の結果になるため listResult[0].id_str のように一度配列のデータを取り出して id_str を呼び出す書き方になります。

      データ自体は↓のページのレスポンスボディ (JSON) という所にわかりやすく書かれているのですが、
      https://syncer.jp/Web/API/Twitter/REST_API/GET/lists/statuses/

      [ ] で囲われている部分は配列で、 { } で囲われている部分は連想配列です。
      データが取れない!って時はちょっと思い出してみてもらえると解決するかもです〜

      回答になりましたかね?不明点があったらまたご連絡ください。

  10. 瑠璃 より:

    なるほど……配列が入れ子になっているので、まず ListResult[0] で

    0: {
    ……
    }

    の部分を読み出し、次にその中の id_str というキーを指定するということですね……。

    VBAで少しだけ二次元配列を扱ったことがあるのですが、表のデータを扱うためのものだとばかり思っていたので、実は配列を入れ子にしたものなのだと分かって目から鱗が落ちた気分です。

    大変分かりやすい解説で助かりました。ありがとうございました。

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