Twitterに自動投稿するbotをGoogle App Scriptで自作する #3

前回までで、SpreadSheetに記載してある情報をランダムにTwitterに自動で投稿するbotを作りました。 

これで、いわゆる"Twitter bot"と言うものの運用ができるようになりました。 

とはいえ、このままだといくつか問題があるので少しずつ解消していきたいと思います。

1.同じtweetをしてしまう際のエラーメッセージについて

前回のスクリプトを複数回回すと、下記のようなメッセージが出て投稿されないことがあります。
https://api.twitter.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: {"errors":[{"code":187,"message":"Status is a duplicate."}]}(応答の全文を見るには muteHttpExceptions オプションを使用してください)

 こちらは、Twitterの仕様で全く同じ内容を短時間に複数回tweetすることを禁止されていることから起こるエラーです。1,2回のことであればただ投稿されないだけの問題ですが、繰り返し発生するとアカウントを凍結される理由になってしまいますので注意が必要です。

 設定だけで防げる対策としては、 下記があります。

①自動投稿の間隔を空ける。(1時間おき⇒8時間おきにするなど)

②ランダムtweetする文章のリストをたくさん用意して被らないようにする。

ですが、一定の確率でこのエラーは発生してしまいます。ここでは、日付もしくは時間を追記することで文章を少し変更してこのエラーを回避する方法を紹介します。ちなみにですが、Twitterはそもそも"同一の趣旨の内容"を連続してTweetすることを禁止しており、この対策をしてもアカウントを凍結される可能性はあります。ですので、①②の対策と合わせて実施することを強くお勧めします。 

今後再利用する可能性があるので日付の文字列を作成するスクリプトを作成します。

こんな感じです。名前をgetDateInfoとしていますが、お好みに合わせて変えてください。

  //日付情報を作る
function getDateInfo() {
  
  var date = new Date();
  var month = date.getMonth() + 1;//月
  var day = date.getDate();//日付
  var hour = date.getHours();//日付
  var minute  = date.getUTCMinutes();//日付
  
  var arrDay = ['日','月','火','水','木','金','土'];
  var dayNum = date.getDay();//曜日を数字で取得
  var dayStr = arrDay[dayNum];
  
  var dateInfo = month + '月' + day + '日(' + dayStr + ') '+ hour + '時' + minute + '分';//mm月dd日(day) hh時mm分の情報を作成
  
  console.log(dateInfo);
  return dateInfo;
}

順番に説明します。

4行目でdateと言う変数にdate型の時間情報を格納します。Date()の()の中を空白にしておくと、現在の時間情報が自動で格納されます。このままでは読みづらい情報なので5行目以降で日本語で読みやすい形に変換します。

5~8行目でdateから、月、日、時、分の情報を取得します。date.getMonthのような形で各情報を取得します。注意が必要なのは月だけは0~11の情報なので日本語に変換するときは+1をする必要があることです。これは、英語文化圏では月を数字では無くてJanuaryとかのように文字列で認識することに起因しています。

10~12行目でdateから曜日の情報を取得します。dateの中では曜日情報は0~6の数字で格納されているので、まず10行目でarrDayと言う配列を定義し、その中に"日"から始まる曜日情報を取得します。9行目でdayNumに曜日の数字情報を格納します。10行目でarrDay配列の中のdayNum番目の要素をdayStrに格納します。

14行目でdateInfoに日付の文字列を格納します。変数はそのまま、文字列は''で括り、それぞれの間は+で結合します。ここでは月日時分曜日の全情報を乗せているので、必要に応じて不要な情報は削除してください。

実行してみると今の時間と異なる情報が出力される可能性があります。この場合には、スクリプトの時間帯を変える必要があります。詳しくは別記事を参照ください。

ここまで出来たら準備は万端です。前記事で作成したスクリプトの、postTweetMessageの直前に下記を追記してください。


  //日付情報の追加
  var dateInfo = getDateInfo2()
  postMessage = dateInfo + '\n' + postMessage

これで、日付情報を追記したtweetをすることができるようになりました。毎分違う文字列が追加されるので、これで同一内容でtweet失敗することは無くなりました。

2.指定の時間にTweetする

前回設定したGASのトリガーの設定では、"〇時間ごと"の 投稿はできるのですが、例えば8時ぴったりに投稿したい場合には、8時ぴったりにトリガーの設定ボタンを押して24時間ごとに動かさなければいけないですし、9時から17時まで1時間ごとにtweetし、残りの時間は動かない。と言うような設定ができません。

そういった場合、cronを定期的に動かすような運用では、スクリプトの頭にif文で現在時刻が何時だったらどう動く、と言うような設定をするのですが、GASではもう少し簡単な作業で複雑な設定を出来るので、それを説明したいと思います。

まず、同じプロジェクト内で新しいスクリプトを作成します。名前は何でもよいです。"Triggers"とかで良いと思います。と言うのは、このスクリプトは今後いろいろな形で別プロジェクトにも流用する可能性が高いので分けておいた方がその際に便利だからです。

そこに、下記のスクリプトを記載します。

function setTriggerTime(scriptName, hour, minute) {
  var setTime = new Date();//script設定の時間を定義
  var curTime = new Date();//現在時刻を定義
    
  //時間を設定
  setTime.setHours(hour);
  setTime.setMinutes(minute); 

  //過去になってしまう場合、翌日に設定
  if(curTime >= setTime){
    setTime.setDate(setTime.getDate()+1)
  }
  ScriptApp.newTrigger(scriptName).timeBased().at(setTime).create();  
}

上から順に説明します。

1行目ではスクリプトの名前と引数を定義しています。ややこしいのですが、この引数のscriptNameと言うのは、トリガーを設定するスクリプトの名前を表しています。hourとminuteはこれからスクリプトを設定する際の時間を定義します。

2,3行目ではDateタイプの変数"setTime"と"curTime"を定義しています。それぞれ、スクリプトをセットする時間と現在時間を定義するのに使います。

6,7行目では、引数で指定されたhourとminuteの値をsetTimeの時間と分の情報に格納していきます。

10~12行目では、セットする時間によっては過去のトリガーを設定することになってしまうので、現在時刻より過去の時間を設定した際に翌日にsetTimeをずらしています。
これにより、毎回同じ時間にスクリプトを回すと翌日に起動できるし、午前中に午後のトリガ時刻を指定するときは当日の時刻を指定できる、と言うような動きを一つのスクリプトで定義できます。

5行目では、ScriptApp.newTriggerで新しくトリガーを設定していきます。scriptNameでスクリプト名を指定し、timeBased(=時間をトリガになる)のタイプのトリガーをsetTimeで指定する。と言うことになっています。

これが完成したら、postTweetMessageの中に、setTriggerTime('postTweetMessage', 12, 0)と言ったような行を追加すると自動で12時に次回のスクリプト起動をするトリガを設定できます。また明日の12時にスクリプトが起動されると更に次の日のトリガが自動で設定されるので、永遠に毎日スクリプトが起動されるようになります。

ここで関数名は'postTweetMessage' のように''で括る必要があるので注意してください。そうしないと、postTweetMessageと言う変数は無いよ、とエラーが出てしまいます。

ちなみに、これだけだと機能としては動くのですが、毎日トリガーの情報がトリガー一覧の中に溜まっていってしまいます。これを防ぐために、

 

function delTrigger(functionName) {
  var allTriggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < allTriggers.length; i++) {
    if (allTriggers[i].getHandlerFunction() == functionName) {
      ScriptApp.deleteTrigger(allTriggers[i]);
      break;
    }
  }
}

と言うスクリプトを作成し、先ほどsetTriggerTimeを記述した前の行にdelTrigger(postTweetMessage)

と言う行を追記してください。後の行に間違えて入れてしまうと、せっかくsetTriggerTimeで設定したトリガが消されてしまうので注意してください。

ここまでは自動で投稿するだけでしたが、いよいよロボットの三要素である認知/判断の部分を実装していきます。次の記事をどうぞ。

コメント