Google Apps ScriptとTwitter APIで自動でツイートといいねするtwitter botを作ってみた

目的

あっという間に3月になっていることに気づき、定期的に日時を教えてくれるtwitter botでも作って時間の大切さを噛み締めようかなと思い作りました。

設計

定期的に日時をツイートしているbotを探してみると見つかりました


ただ、毎日ツイートされると鬱陶しいので毎週ツイートしてくれるbotにしようと思いました。

タイミングはもうこんなに時間が過ぎたのかと思ったときに、先延ばしにしていることを始めやすいように土曜日の朝6時にしました。
文面についても残りの日数だけでなく過ぎた日数も記述することにしました。

1つのgmailで複数のツイッターアカウントの作り方

以下の記事を参照してください。


enjoy.sso.biglobe.ne.jp

コード

// ツイッター認証
function getTwitterService() {
  return OAuth1.createService('twitter')
      .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
      .setConsumerKey('CONSUMER_API_KEY')
      .setConsumerSecret('CONSUMER_API_SECRET_KEY')
      .setAccessToken('ACCESS_TOKEN','ACCESS_TOKEN_SECRET');
}

// ツイッター投稿
function makeRequest() {
  //ツイッター認証
  var twitterService = getTwitterService();

  var today = new Date();
  var month = today.getMonth() + 1;
  var date = today.getDate();
  var hour = today.getHours();

  //今年の指定の日付を取得
  var oomisoka = today.getFullYear() + "/12/31";
  var ganzitsu = today.getFullYear() + "/1/1";
  
  //秒単位同士を引き算して日数に戻す
  var leftDays = Math.floor((Date.parse(oomisoka) - today.getTime()  ) / (24*60*60*1000));
  var pastDays = Math.floor(( today.getTime() - Date.parse(ganzitsu)  ) / (24*60*60*1000)) + 1 ;

  //0日の場合(大晦日または元旦)は残り時間を表示
  if (pastDays === 0) {
    pastDays = hour + '時間';
  } else {
    pastDays = pastDays + '日';
  }

  if (leftDays === 0) {
    leftDays = 24 - hour + '時間';
  } else {
    leftDays = leftDays + '日';
  }
  
  // 文面
  var text = '今日は' + month + '月' + date + '日です\n' + '今年ももう' + pastDays + 'が過ぎ、残すところあと' + leftDays + 'です';

  // ツイッター投稿
  var response = twitterService.fetch('https://api.twitter.com/1.1/statuses/update.json', {
    method: "post",
    payload: {status: text}
  })  
}

コードの解説

  • Date.parse()

協定世界時(1970 年 1 月 1 日 00:00:00 )からのミリ秒を算出。

developer.mozilla.org

timeZoneの変更


f:id:KaneyHonest:20210401142256p:plain
左の歯車マーク→ 「「appsscript.jsonマニフェスト ファイルをエディタで表示する」にチェック


f:id:KaneyHonest:20210401142533p:plain
appsscript.jsonのtimeZoneを"Asia/Tokyo"に変更

Twitter Developerに登録して鍵を取得

以下サイトを参照のこと www.itti.jp
入手した鍵をgetTwitterService関数の該当箇所に入力

    .setConsumerKey('CONSUMER_API_KEY')
    .setConsumerSecret('CONSUMER_API_SECRET_KEY')
    .setAccessToken('ACCESS_TOKEN','ACCESS_TOKEN_SECRET');


ライブラリの追加

f:id:KaneyHonest:20210315192605p:plain
「ライブラリ」を選択

f:id:KaneyHonest:20210315192718p:plain
スクリプト IDは 1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s


f:id:KaneyHonest:20210315192807p:plain
バージョンは最新(数字の一番大きいバージョン)でOAuth1を追加

初回時の確認


f:id:KaneyHonest:20210307092533p:plain
この画面が出てきたら、「権限を確認」を選択


f:id:KaneyHonest:20210307093422p:plain
スプレッドシートを編集しているアカウントを選択


f:id:KaneyHonest:20210307094135p:plain
左にある「詳細」を選択

f:id:KaneyHonest:20210307092804p:plain
スプレッドシートのプロジェクト名 +(安全でないページ)に移動」を選択


f:id:KaneyHonest:20210307094222p:plain
「許可」を選択


結果


変数ganzitsuとoomisokaを今日(4/1)と設定する(もし今日が元日と大晦日なら)と


自動化

f:id:KaneyHonest:20210306155451p:plain
左側の一覧から「トリガー」を選択


f:id:KaneyHonest:20210306160058p:plain
右下の「トリガーを追加」から


f:id:KaneyHonest:20210306155604p:plain
実行する関数を「makeRequest」、イベントのソースを「時間主導型」を選択


感想

前回のGoogle Apps Scriptを使ったときと比べて格段に早くかたちにできた。成長が感じられて嬉しい。

追記(オリンピック開催までの残り日数)

botを作ったからにはフォロワーが増えることを期待していたのですが、全く増えないためにフォロワー獲得のためにオリンピック開催までの残り日数もツイートに追加してみました。


7月23日の夜の8時が開会式らしく、ちょうど4月14日が残り100日だということでそれに乗っかってフォロワー数が増やす狙いです

youtu.be
コードは以下の通り(makeRequest関数内に追加)

//オリンピックの日にち
var olympic = today.getFullYear() + "/7/23"
    
//オリンピックの日にちから今日の日にちを引いて残りの日数を算出
var olympicDay = Math.floor((Date.parse(olympic) - today.getTime()  ) / (24*60*60*1000)) + 1;

//残りの日数が0、つまり残り〇〇時間の場合と残り1日以上の場合を条件分岐
if (olympicDay === 0) {
  olympicDay = '東京オリンピック開催まであと' + 20 - hour + '時間';
} else {
  olympicDay = '東京オリンピック開催まではあと' + olympicDay + '日';
}

さらに自動でいいねする機能も追加

function favoriteTweets() {
 
  //前回実行時の一番新しいツイートのidをスプレッドシートから取得
  var sheet = SpreadsheetApp
                        .getActiveSpreadsheet()
                        .getActiveSheet()
                        .getRange('A1')
                        .getValues();
  var id = sheet[0][0]

  //ツイッター認証
  var twitterService = getTwitterService();

  /*
  「五輪まで」または「オリンピックまで」を
 「RT」(リツートされたツイートには検索結果の文面に含まれる)とメンション(@)を排除して
  新しい順で前回のツイートから最新のツイートの範囲を検索
  
  初回時は &since_id=' + id をコメントアウトしてください
  ※ その後「'」を最後に付け加えてください
  */
  var json = twitterService.fetch('https://api.twitter.com/1.1/search/tweets.json?q=%22五輪まで%22%20OR%20%22オリンピックまで%22%20RT%20filter%3Amentions&result_type=recent&since_id=' + id);
  var array = JSON.parse(json);

  //検索結果が0(新しいツイートがない)なら終了
  if (array.statuses.length === 0) {
    return;
  }
  
  //一番新しいツイートのidをスプレッドシートに転機
  var sheet = SpreadsheetApp
                        .getActive()
                        .getSheetByName('シート1')
                        .getRange(1, 1)
                        .setValue(array.statuses[0].id_str);

  // 検索結果のツイートのいいねがされていないならそのツイートのidからいいねをつける
  for (let i = 0; i < array.statuses.length; i++) {
    if (array.statuses[i].favorited === false) {
      let id_str = array.statuses[i].id_str;
      var response = twitterService.fetch('https://api.twitter.com/1.1/favorites/create.json?id=' + id_str, {
        method: 'post'
      });
    } else {
      return;
    }
  }
}


コード解説

  • .setValue(array.statuses[0].id_str);

ツイートの検索結果は検索の範囲で現在から過去へ処理されていきます。
なので一番新しいツイートのidを取得する際には検索結果の0番目の配列を指定します。

アカウントのスパム扱い

タイマーを1分に設定して運用していると、半日で1000いいねを超えたあたりでスパム扱いされて3日間制限がかかりました。
apiまたは手動での1日のいいねの上限は1000だそうです。気をつけましょう。

developer.twitter.com

1日のいいねの上限を1000までにする

/*
カウントを0にリセットする

makeRequest関数に追記してツイートしたら実行するようにもできる
*/
function clearCount() {
  var sheet = SpreadsheetApp
                        .getActive()
                        .getSheetByName('シート1')
                        .getRange(1, 2)
                        .setValue(0);
}

/*
favoriteTweets関数に以下のコードを追加。

カウントの値を取得
*/
var sheet = SpreadsheetApp
                      .getActiveSpreadsheet()
                      .getActiveSheet()
                      .getRange('A1:B1')
                      .getValues();
var id = sheet[0][0];
var count = sheet[0][1];

//検索結果が0なら終了。カウント+検索結果が1000より多ければ終了、1000未満であればカウントに検索結果を足す
  if (array.statuses.length === 0) {
    return;
  } else {
    if (count + array.statuses.length > 1000) {
      return
    } else {
      count = count + array.statuses.length;
    }
  }

//スプレッドシートにカウントを転記
var sheet = SpreadsheetApp
                    .getActive()
                    .getSheetByName('シート1')
                    .getRange(1, 2)
                    .setValue(count);

半分過ぎたら

今年が半分過ぎた時にアナウンスしてほしかったので追加しました。

if (pastDays === Math.ceil(365 / 2)) {
    pastDays = '半分(' + pastDays + '日)'
  }

  if (pastDays === Math.ceil(365 / 3)) {
    pastDays = '1/3(' + pastDays + '日)'
  }

  if (pastDays === Math.ceil(365 * 2 / 3)) {
    pastDays = '2/3(' + pastDays + '日)'
  }

  if (pastDays === Math.ceil(365 / 4)) {
    pastDays = '1/4(' + pastDays + ')'
  }

  if (pastDays === Math.ceil(365 * 3 / 4)) {
    pastDays = '3/4(' + pastDays + '日)'
  }

Math.ceil()(小数点繰り上げ)をしているのは、例えば365/2の答えは182.5でこの小数点5というのは1日の半分ということで12時間になります。
自動ツイートの設定は毎日朝5〜6時なのでコードのif文のすべての場合で少数を時間になおすと、自動ツイートの時刻はまだその時間に到達していないことになります。
なので整数部分の日数+1日するために小数点を繰り上げしているわけです。

主要参考文献

twitter.com

enjoy.sso.biglobe.ne.jp

www.youtube.com

dianxnao.com

developer.mozilla.org

walking-elephant.blogspot.com

www.itti.jp

github.com

youtu.be

www.hanabe.tokyo

belltree.life

developer.twitter.com

developer.twitter.com

www.howtonote.jp

developer.twitter.com