第2章 Google Apps ScriptでTwitter botを作ってみる

75回生 sashiming

2.1 はじめに

はじめまして、75回生のsashimingです。今回初めて部誌の執筆をします、よろしくお願いします。

今回の部誌では、 Google Apps Script (通称GAS、以下「GAS」と表記)でTwitterのbotを作ることについて書いていきます。

2.2 予備知識

C/C++やJavaなど、他のプログラミング言語で条件分岐、ループ、配列などの基本的なことを知っていることを前提に進めていきます。JavaScriptの基本を知っておくとなおよいです。

2.3 Twitter botの大まかな仕組み

今回の部誌で作るbotは以下のようなものです。

bot作成例

図2.1: bot作成例

このようなbotの動作、特にツイートを実行する部分の動作はどのような仕組みになっているのでしょうか。

Twitterには、Twitter APIという仕組みがあり、プログラムからTwitterのサービスを呼び出す事ができます。言うなれば、プログラムとTwitterサービスを繋ぐ存在です。例えば、「『〇〇』という内容をツイートして」というリクエストをプログラムからTwitter APIを通してTwitterのサービスへ送ることで、実際にツイートが実行されます。図に表すと、次のようになります。

Twitter botの仕組み

図2.2: Twitter botの仕組み

ここで、タイトルにもある「Google Apps Script(GAS)」はどこで使われているのかというと、プログラムの部分で使われています。次の項では、GASとはどういったものなのかを紹介します。

2.4 GASの概要

GASとは

クラウド上でスクリプトを実行することでGoogleのサービスを操作できる、Google公式のサービスです。

GASを使うことでGmailやGoogleドライブなど、様々なサービスを操作することができます。

開発環境は不要

一般的に、プログラミングでは最初に開発環境を整える必要がありますが、GASの開発環境はGoogle側で用意してくれています。必要なものはPC、ネット環境、Googleアカウントのみです。これらさえあれば、誰でもすぐにGASのプログラミングを始められます。

実行はGoogleサーバー側で

普通、常に動作しているようなbot等を作る際は常時起動しているPCまたはサーバーを用意する必要がありますが、GASのスクリプトはGoogle側のサーバーで実行してくれます。つまり、自分でサーバー等を準備する必要がありません

また、GASにはトリガー機能があり、トリガーを設定することで定期的にスクリプトを実行することができます。そのため、スクリプトエディタを起動していなくても自動的にスクリプトを動かすことができます。これは定期実行系のbotを作る際には重宝する機能です。

JavaScriptベース

GASを学ぶメリットとして、JavaScriptが同時に学べることが挙げられます。

GASで書くスクリプトの言語はJavaScriptがベースとなっているので、JavaScriptで使える機能は基本的にGASでも使えます。そのため、GASを学ぶと同時にJavaScriptも学ぶことができます。逆に、JavaScriptを触ったことがあるならJavaScriptを書く感覚でGASを操れます。

APIが叩ける

GASには、HTTPリクエストを送ってWebページの情報を取得するUrlFetchApp.fetch()メソッドや、JSON形式のデータを取得できるJSON.parse()メソッド(こちらはJavaScriptに用意されているメソッドです)などが用意されているので、APIを叩く処理が実装できます。これらのメソッドのおかげでGASでbotが作れるというわけです。

ライブラリ機能

よくある処理だが実装がめんどくさい、といった機能の実装を自力でやるとなるとかなり大変です。そこで、先人の残した知恵を借りてしまいましょう。

GASには、作成した関数を他のプロジェクトからでも使うことの出来る「ライブラリ機能」があります。ライブラリをインポートすれば、普通ならば数十行の実装だって、たった一文で書けてしまいます。

逆に、自分で関数を書いて、ライブラリとして世に送り出すことも出来ます。自分の書いたコードで他人に貢献できるってステキじゃないですか?

2.5 GASを触ってみる

うだうだとGASの紹介をしているのも退屈なので、実際にGASを使ってみましょう。ここからはGoogleアカウントを既に取得しているものとして進めていきます。

Googleにログインしている状態で、https://drive.google.com/からGoogleドライブを開きましょう。

次に、画面上の何もないところを右クリックして、「Google スプレッドシート」をクリックしましょう。Googleスプレッドシートが開かれるはずです。

スプレッドシート起動

図2.3: スプレッドシート起動

上部メニューから「ツール」→「スクリプト エディタ」をクリックしましょう。次図のような画面になるはずです。

スクリプトエディタ起動

図2.4: スクリプトエディタ起動

このエディタにスクリプトを書く形になります。それでは、実際にコードを書いてみましょう。

注意

GAS(JavaScript)は仕様がかなり複雑な言語です。簡単なプログラムを作る場合には問題はないのですが、JavaScriptの仕様をフルに利用した高度なコード*1を書く場合は十分に注意して実装する必要があります。

ここでは、複雑な仕様に触れない初歩の部分を載せています。僕は、JavaScriptの細かな仕様は実際にbotを作る実践段階で学んでいけばよいと思っています。

[*1] 激うまギャグ

世界に挨拶しよう

最初は皆さんおなじみHello, Worldから。次のソースコードを書きましょう。

function myFunction(){
  Logger.log("Hello, World");
}

コードを書いたら、Ctrl+Sで適当な名前をつけて保存しましょう。保存ができたら、上部メニューの右向き三角形のマークのボタンを押してスクリプトを実行してください。

画面上部のメッセージ「関数myFunctionを実行中...」の表示が消えたら、上部メニューから「表示」→「ログ」をクリックしましょう。
Hello, Worldが表示されるはずです。これでGASの世界に挨拶することができました。

Hello, World実行

図2.5: Hello, World実行

Logger.log(data)
文字列や数値などをログとして出力する関数。主にデバッグ用に使います

変数を使ってみる

GASでも他言語と同じように変数が使えます。変数を宣言する方法は以下の通りです。

var a;  // "a"という名前の変数を宣言
var b = 334;    // "b"という名前の変数を宣言し、初期値を334にする
var c = "Nada Junior and Senior High School"; // 動的型付けなので、いろいろな型のものを入れられます

変数を使ったプログラムを見てみましょう。

function myFunction() {
  var a;
  a = "SAIL AWAY";
  var b = 73;
  Logger.log(a);
  Logger.log(b);

  b = "Nada School Festival";
  Logger.log(b);
}

先ほどと同じようにして実行すると、以下のようになります。ログに73ではなく73.0と表示されるのは仕様です。

variable.gs実行結果

図2.6: variable.gs実行結果

var a;で変数aを宣言し、a = "SAIL AWAY";で変数aに文字列"SAIL AWAY"を代入しています。また、var b = 73;で宣言と代入を同時におこなっています。

8行目 b = "Nada School Festival";のように、同じ変数に再び数値や文字列を代入することもできます。

基本演算

GAS・JavaScriptでの基本演算はC/C++やJavaと同じです。

表2.2: 演算子一覧

演算子説明
+加算
-減算
*乗算
/除算(整数切り捨てにはならず、実数値になります)
%剰余

以上の演算子のほか、++でのインクリメントや、--でのデクリメント、+=-=も使えます。

比較演算子

以下の表のような比較演算子を使うことで2つの変数の値を比較することができます。基本的には他言語と同じですが、GAS・JavaScript特有の比較演算子があります。

表2.2: 比較演算子一覧

比較演算子説明
>左の値が右の値より大きい
<右の値が左の値より大きい
>=左の値が右の値より大きい、もしくは等しい
<=右の値が左の値より大きい、もしくは等しい
==左の値と右の値が等しい
!=左の値と右の値が異なる
===左の値と右の値の型や内容、すべてが同一である(==より厳しい比較)
!==左の値と右の値の型や内容が同一ではない

注意点として、GAS・JavaScriptでは=====で違いがあります。例えば

  • 123 == "123"trueですが、
  • 123 === "123"falseです。

これらのことを確かめるにはLogger.log(123 == "123");などとするとするとよいです。

条件分岐

条件分岐をおこなうif文の構文は、C/C++やJavaと同じです。

if(条件式1) {
  // 条件式1がtrueならこの部分を実行
} else if(条件式2) {
  // 条件式1がfalseで、条件式2がtrueのときにこの部分を実行
} else {
  // 条件式1, 2ともにfalseのときにこの部分を実行
}

以下は、if文を使ったコードの例です。

function myFunction() {
  var a = 1333;
  if(a == 1333) {
    Logger.log("a is 1333");
  } else {
    Logger.log("a is not 1333");
  }
  if(a > 1024) {
    Logger.log("a is greater than 1024");
  }
  if(a < 1024) {
    Logger.log("a is less than 1024");
  }
}

実行すると、以下の通りになります。

a is 1333
a is greater than 1024

a == 1333trueなので、4行目が実行され、6行目は実行されません。また、a > 1024trueなので9行目が実行されますが、a < 1024falseなので12行目は実行されません。

ここで、2行目のa = 1333a = 753に変えてみます。すると、実行結果は以下の通りになります。

a is not 1333
a is less than 1024

a == 1333falseなので、4行目が実行されず、6行目が実行されます。a > 1024falseなので9行目は実行されませんが、a < 1024trueなので12行目は実行されます。

繰り返し処理

for文

for文は、繰り返し回数が決まっているときに使う構文です。

for(初期値; 条件式; 増減式) {    // 増減式の最後にはセミコロンはつけません
  // 繰り返す処理
  // 条件式がtrueである限りこの部分は実行されます
  // 処理が終わるごとに増減式を実行します
}

以下は、for文を使ったコードの例です。

function myFunction() {
  var a = 10;
  for(var i = 0; i < a; ++i) {
    Logger.log(i);
  }
}

実行結果は以下の通りです。

0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0

for文は、後ほど紹介する配列の要素を参照するときによく使われます。

while文

何回繰り返すか分かっていないときはwhile文を使いましょう。while文を書くときは、無限ループになっていないか十分に確認をしましょう。さもないと、兵庫県警に逮捕されます。*2

リスト2.1: while文.gs

while(条件式) {    // 条件式の最後にはセミコロンはつけません
  // 繰り返す処理
  // 条件式がtrueである限りこの部分は実行されます
  // 繰り返す処理の最後には必ず増減式を書きましょう
}

以下は、while文を使ったコードの例です。

function myFunction() {
  var a = 0;
  while(a < 10) {
    Logger.log(a);
    a += 2;
  }
}

実行結果は以下の通りです。

0.0
2.0
4.0
6.0
8.0

breakとcontinue

for文やwhile文のループ処理の中でbreak;を入れると、完全にループから抜け出します。以下はコード例です。

function myFunction() {
  var a = 10;
  for(var i = 0; i < a; ++i) {
    if(i > 5) break;
    Logger.log(i);
  }
}

実行結果は以下の通りです。

0.0
1.0
2.0
3.0
4.0
5.0

i6のときにbreak;が実行され、for文を抜け出しています。


ループ処理の中でcontinue;を使うと、そこから後の処理は行われず、次のループに移ります。

以下はコード例です。

リスト2.2: continue_example.gs

1
2
3
4
5
6
7
function myFunction() {
  var a = 10;
  for(var i = 1; i <= a; ++i) {
    if(i % 2 == 1) continue;
    Logger.log(i);
  }
}

実行結果は以下の通りです。

2.0
4.0
6.0
7.0
10.0

1から10までの偶数を出力するプログラムです。iが奇数のときはcontinue;が実行され、次のループに移ります。

配列

通常の配列

空の配列の初期化のしかたは、次の通りです。

var arr = [];

配列を作成するには、角括弧を使います。

初期値をもつ配列の作り方は、次の通りです。

var arr = [33, 4, 57, 114, 514, 810];

初期値はもたないが要素数が定まっている配列の作り方は、次の通りです。

// 長さ 575 の配列を作る
var arr = Array(575);

実際に長さ575の配列を作れているかどうか確認してみましょう。

function myFunction() {
  var arr = Array(575);
  Logger.log(arr.length);
}

実行結果は次のようになります。

575.0

(配列名).lengthで配列の長さを求めることができます。

配列の後ろに要素を追加するには、push()を使います。使用例は次の通りです。

function myFunction() {
  var arr = [33, 4, 114, 514, 1919];
  arr.push(810);
  Logger.log(arr);
}

実行結果は次のようになります。

[33.0, 4.0, 114.0, 514.0, 1919.0, 810.0]

配列[33, 4, 114, 514, 1919]の後ろに810が追加され、[33, 4, 114, 514, 1919, 810]になりました。

逆に、配列の先頭に要素を追加するには、unshift()を使います。使用例は次の通りです。

function myFunction() {
  var arr = ['b', 'c', 'd', 'e'];
  arr.unshift('a');
  Logger.log(arr);
}

実行結果は次のようになります。

[a, b, c, d, e]

配列['b', 'c', 'd', 'e']の先頭に'a'が追加され、['a', 'b', 'c', 'd', 'e']になりました。


配列の末尾の要素を削除するには、pop()を使います。使用例は次の通りです。

function myFunction() {
  var arr = ['a', 'b', 'c', 'p'];
  arr.pop();
  Logger.log(arr);
}

実行結果は次のようになります。

[a, b, c]

配列['a', 'b', 'c', 'p']の末尾の要素'p'が削除され、['a', 'b', 'c']になりました。

逆に、配列の先頭の要素を削除するには、shift()を使います。使用例は次の通りです。

リスト2.3: array_shift.gs

function myFunction() {
  var arr = ['a', 'b', 'c'];
  arr.shift();
  Logger.log(arr);
}

実行結果は次のようになります。

[b, c]

配列['a', 'b', 'c']の先頭の要素'a'が削除され、['b', 'c']になりました。

配列の値を参照するには、他言語と同じように、そえをつけます。添字は1から始まる(1-indexed)のではなく、0から始まる(0-indexed)ので気をつけましょう。

以下は使用例です。

リスト2.4: array_index.gs

function myFunction() {
  var arr = ['a', 'b', 'c', 'd', 'e'];
  Logger.log(arr[3]);   // 4 番目の値が出力されます
  Logger.log(arr[0]); // 1 番目の値が出力されます
}

実行結果は以下の通りです。

d
a

配列とfor文を組み合わせて、配列の全要素にアクセスすることもできます。

以下は、配列とfor文を組み合わせた例です。

リスト2.5: array_for.gs

function myFunction() {
  var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  var sum = 0;
  for(var i = 0; i < arr.length; ++i) {
    sum += arr[i];
  }
  Logger.log(sum);
}

配列に格納された数値の総和を求めるプログラムです。

実行結果は次の通りです。

55.0

連想配列

通常の配列とは違った配列として、連想配列があります。

連想配列とは、キーを指定して値を紐づけることができる配列です。C++でいうところのstd::map、JavaでいうところのHashMapです。

通常の配列では、添字は0から始まる数値ですが、連想配列では文字列のキーを指定して、そのキーに対応する値を代入します。

連想配列の初期化のしかたは、次の通りです。配列では角括弧を使いましたが、連想配列では波括弧を使います。

var hash = {};

初期値をもつ連想配列をつくるには、次のようにします。

var hash = {
  red: "赤色",
  blue: "青色",
  green: "緑色"
};

コロンの左にキー名、右に値を書きます。


連想配列に要素を追加するには、連想配列名.キー = 値や、連想配列名["キー"] = 値などとします。

var hash = {};
hash.red = "赤色";
hash["blue"] = "青色";

連想配列の要素の参照は連想配列名.キーや、連想配列名["キー"]などとするとよいです。


連想配列の全要素を表示するには、for-in文を使います。

リスト2.6: hash_allshow

var hash = {
  red: "赤色",
  blue: "青色",
  green: "緑色",
  yellow: "黄色",
  orange: "橙色"
};

for(var key in hash) {
  Logger.log(key + " の値: " + hash[key]);
}

実行結果は以下の通りです。

red の値: 赤色
blue の値: 青色
green の値: 緑色
yellow の値: 黄色
orange の値: 橙色

連想配列の要素を削除するには、deleteを使います。

var hash = {
  red: "赤色",
  blue: "青色",
  orange: "橙色",
  green: "緑色"
};

delete hash["orange"];

for(var key in hash) {
  Logger.log(key + " の値: " + hash[key]);
}

実行結果は以下の通りです。

red の値: 赤色
blue の値: 青色
green の値: 緑色

ちゃんとorangeがキーとなる要素が削除されているのが分かります。

自作関数

JavaScriptでの関数の書き方は次の通りです。

function 関数名 (引数1, 引数2, ...) {
  // 処理
  return 返り値;
}

引数がない場合は空白にしても構いません。また、返り値がない場合はreturn~の文は書かなくて構いません。

関数は、同じ処理を何回も実行するときに役に立ちます。

以下は、関数を使ったコードの例です。

リスト2.7: function_example

function rating(money) {
  var res;
  if(money < 400) res = "You are gray coder";
  else if(money < 800) res = "You are brown coder";
  else if(money < 1200) res = "You are green coder";
  else if(money < 1600) res = "You are cyan coder";
  else if(money < 2000) res = "You are blue coder";
  else if(money < 2400) res = "You are yellow coder";
  else if(money < 2800) res = "You are orange coder";
  else res = "You are red coder";

  return res;
}

function main() {
  var rate = 1305;
  Logger.log(rating(rate));
  rate = 2810;
  Logger.log(rating(rate));
  rate = 421;
  Logger.log(rating(rate));
}


AtCoder*3のレーティングから色分けを出力するプログラムです。実行結果は以下の通りです。

You are cyan coder
You are red coder
You are brown coder

2.6 Twitter API キーの取得

一通りGASを触ってみたら、いよいよ本題です。Twitter botを作る準備をしましょう。

Twitter botを作るためには、Twitter APIのAPIキーを取得しなければいけません。Twitter APIを叩くことで、スクリプトからツイートを送信したり、Twitterの様々なコンテンツ (ツイート、タイムライン、フォロワーなど)を取得したりできます。

Twitter APIのAPIキーは、以前はhttps://apps.twitter.com/から簡単に取得できましたが、2018年7月からAPIの使用条件が厳格になり、Twitterアカウントとは別にhttps://developer.twitter.com/からの開発者アカウントの登録が必須になりました。しかも、この開発者アカウントの登録が面倒で、Twitter APIを使う目的を英語で300文字以上書かされたりします。botを作る前段階の時点で初心者殺しですね。*4

[*4] 実は少し前までは開発者アカウントの登録にはTwitter側による審査が必要で、長い時間をかけないと登録ができない鬼畜仕様でした

開発者アカウントの登録

それでは、この面倒な開発者アカウントの登録をやっていきましょう。

まず、Twitterの通常のアカウントを用意しましょう。登録手順は省略します。

次に、https://developer.twitter.com/にアクセスしてください。

ページ右上の「Apply」をクリックした後、「Apply for a developer account」をクリックしましよう。

開発者アカウント登録手順_01

図2.7: 開発者アカウント登録手順_01

Twitterアカウントに携帯電話番号を紐づけていないと以下のような画面になるので、「Add a valid phone number」から携帯電話番号を登録しましょう。すでに携帯電話番号を紐づけている場合は「Add a valid phone number」の部分が「Continue」になっているので、そこをクリックしましょう。

開発者アカウント登録手順_02

図2.8: 開発者アカウント登録手順_02

Twitter APIを利用するアカウントの詳細情報を入力します。

開発者アカウント登録手順_03

図2.9: 開発者アカウント登録手順_03

Twitter APIの使用用途にチェックを入れます。

開発者アカウント登録手順_04

図2.10: 開発者アカウント登録手順_04

Twitter APIをどのように使用するかを詳細に記載します。英語で300文字以上書かないといけません。頑張って書きましょう。

開発者アカウント登録手順_05

図2.11: 開発者アカウント登録手順_05

APIで入手した情報を政府機関が利用できるか確認されます。個人利用なのでもちろん「No」を選びましょう。

開発者アカウント登録手順_06

図2.12: 開発者アカウント登録手順_06

利用規約に同意して、開発者アカウントの登録申請をしましょう。

開発者アカウント登録手順_07

図2.13: 開発者アカウント登録手順_07

開発者アカウント登録手順_08

図2.14: 開発者アカウント登録手順_08

「あなた宛にメールを送信したよ!」という画面になり、Twitterからメールが送信されます。

開発者アカウント登録手順_09

図2.15: 開発者アカウント登録手順_09

送信されたメールの内容です。「Confirm your email」をクリックしましょう。

開発者アカウント登録手順_10

図2.16: 開発者アカウント登録手順_10

僕の場合、この時点でTwitter APIを使用できる状態になっていましたが、もし「審査中です」というような画面になっていた場合、審査が終わるまで待ちましょう。Twitter側からメールが来た場合、要求されている内容を英語で書いて返信してください。承認されれば、ようやく開発者アカウントの登録は終わりです。

APIキー取得

Get Started(https://developer.twitter.com/en/account/get-started)のページから、「Create an app」をクリックしましょう。

APIキー取得_01

図2.17: APIキー取得_01

「Create an app」をクリックします。

APIキー取得_02

図2.18: APIキー取得_02

以下の画像の通りに必要事項を入力しましょう。

APIキー取得_03

図2.19: APIキー取得_03

APIキー取得_04

図2.20: APIキー取得_04

APIキー取得_05

図2.21: APIキー取得_05

「Callback URLs」には次のURLを指定してください。角括弧は必要ありません。

https://script.google.com/macros/d/[GASのスクリプトID]/usercallback

GASのスクリプトIDは、GASのエディタの上部メニュー「ファイル」→「プロジェクトのプロパティ」を開くことで見ることができます。

スクリプトIDの場所

図2.22: スクリプトIDの場所

必要事項を記入し終わったら、「Create」をクリックしましょう。その後、APIの使用に関する注意が出るので、一読してから「Create」をクリックしましょう。

API使用に関する注意画面

図2.23: API使用に関する注意画面

これでAppを作成できました。今回のbot作成では、「Key and tokens」から見られる、2つのConsumer API keysを使います。

Key and tokensをクリック

図2.24: Key and tokensをクリック

今回使うConsumer API keys

図2.25: 今回使うConsumer API keys

これで、APIキーを取得することができました。

2.7 GASでTwitter APIを使う

これでようやくAPIキーを取得することができました。あともう一息です。

今度は、GASのライブラリ「TwitterWebService」*5を導入します(公式のものではありません)。TwitterWebServiceライブラリを導入することで、OAuth認証の処理が楽になります。

GASのエディタを開いて、上部メニュー「リソース」から、「ライブラリ」を選択してください。次に、「ライブラリの追加」の欄に以下に示すプロジェクトキーを入力し、「追加」ボタンをクリックしてください。

プロジェクトキー:1rgo8rXsxi1DxI_5Xgo_t3irTw1Y5cxl2mGSkbozKsSXf2E_KBBPC3xTF

以下のような画面になるので、バージョンを「2」に合わせて、「保存」を押してください。

ライブラリ追加

図2.26: ライブラリ追加

バージョンを2に合わせて保存

図2.27: バージョンを2に合わせて保存

これでTwitterWebServiceライブラリを導入することができました。

ツイッタランドにHello, World!

以下のソースコードを書いてください。3・4行目には、先ほど取得したConsumer API keysのAPI keyとAPI secret keyを入れてください。

リスト2.8: TwitterHello.gs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 認証用のインスタンス
var twitter = TwitterWebService.getInstance(
  " (Consumer API keysのAPI key) ",
  " (Consumer API keysのAPI secret key) "
);

// 認証
function authorize(){
  twitter.authorize();
}

// 認証解除
function reset(){
  twitter.reset();
}

// 認証後のコールバック
function authCallback(request){
  return twitter.authCallback(request);
}
// ここから上は変えないようにしてください

function postTweet(){
  var service  = twitter.getService();
  var message = "Hello, World!";
  var response = service.fetch("https://api.twitter.com/1.1/statuses/update.json", {
    method: "post",
    payload: { status: message }
  });
}

ソースコードを書いたら、まずauthorize関数を実行しましょう。authorize関数の走らせ方は以下の画像の通りです。

authorize関数実行手順

図2.28: authorize関数実行手順

実行が終わったら、ログを表示させます。以下の画像のようにURLが表示されますので、ブラウザの別タブでそのURLに飛びましょう。

認証ページのURL

図2.29: 認証ページのURL

すると、ツイ廃にとってはおなじみの画面が表示されました。「連携アプリを認証」をクリックしましょう。

おなじみの認証画面

図2.30: おなじみの認証画面

「Success」の表示が出れば、認証成功です。このタブは閉じても構いません。ちなみに、2回目以降の実行では、以上の認証作業は必要ありません。

認証が終わったので、ようやくツイート処理がおこなえます。それでは、先ほどauthorize関数を実行したのと同じようにして、postTweet関数を実行してみましょう。

実行が終了した後、Twitterを開いて確認してみましょう。ちゃんと「Hello, World!」という内容のツイートが送信されています。

ツイート送信完了

図2.31: ツイート送信完了

2.8 お天気botを作る

この記事の冒頭で紹介した、明日の天気を発信するお天気botを、実際に作ってみましょう。

お天気botを作るためには、明日の天気情報をどこかから入手する必要があります。今回は、Livedoorの天気API(http://weather.livedoor.com/weather_hacks/webservice)を利用します。これは、地域を指定するとその地域の今日・明日・明後日の天気・最高気温・最低気温のデータをJSON形式で取得できるというものです。

手っ取り早く作りたいという方のために、先にソースコードを載せておきます。コード解説は後ほど。

リスト2.9: weatherbot.gs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 認証用のインスタンス
var twitter = TwitterWebService.getInstance(
  " (Consumer API keysのAPI key) ",
  " (Consumer API keysのAPI secret key) "
);

// 認証
function authorize(){
  twitter.authorize();
}

// 認証解除
function reset(){
  twitter.reset();
}

// 認証後のコールバック
function authCallback(request){
  return twitter.authCallback(request);
}
// ここから上は変えないようにしてください

function weatherTweet(){
  var tweet;
  var weatherJSON = JSON.parse(UrlFetchApp.fetch("http://weather.livedoor.com/forecast/webservice/json/v1?city=270000").getContentText());

  var weather = weatherJSON["forecasts"][1]["telop"];
  var maxtemp = weatherJSON["forecasts"][1]["temperature"]["max"]["celsius"];
  var mintemp = weatherJSON["forecasts"][1]["temperature"]["min"]["celsius"];

  var tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);
  var datestr = String(tomorrow.getMonth()+1) + '月' + String(tomorrow.getDate()) + '日';

  tweet = "明日("+datestr+")の大阪の天気は "+weather+" の予想です。\n最高気温は "+maxtemp+"℃、最低気温は"+ mintemp+"℃ の予想です。";

  twitter.getService().fetch("https://api.twitter.com/1.1/statuses/update.json", {
    method: "post",
    payload: { status: tweet }
  });
}

コード解説

  • 25行目

大阪市の天気情報を http://weather.livedoor.com/forecast/webservice/json/v1?city=270000 から入手し(UrlFetchApp.fetch(url))、それをJSON形式のデータとして扱えるようにしています(JSON.parse())。

入手したJSON形式のデータの構造の概略は次の画像の通りです。JSON形式のデータは階層構造でデータが格納されています。

天気JSONデータの構造

図2.32: 天気JSONデータの構造

  • 27~29行目:天気のJSONデータを取得

JSON形式のデータでは、連想配列と同じようにして特定のデータにアクセスすることができます。

27行目では明日の天気、

28行目では明日の最高気温、

29行目では明日の最低気温

を参照しています。

  • 31~33行目:日付表示の処理

31行目では、日付情報を格納するDate型を使い、今日の日付情報(new Date())を変数tomorrowに代入しています。

32行目では、変数tomorrowが今日の日付情報になっているのを明日の日付情報に直しています。

33行目では、明日の日付を「○月○日」の形の文字列として変数datestrに代入しています。tomorrow.getMonth()で返ってくる値は実際の月より1小さいので(例えば5月なら4が返ってきます)、実際の月に直すために1を足しています。

  • 35行目:ツイート内容となる文字列型変数tweetをつくる

文字列では、+を使うと文字列同士の結合ができます。また、String()を使うと、数値型のものを文字列型にキャストすることができます。

  • 37~40行目:ツイート送信処理

Hello, Worldのツイートを送信したときと同じように、「変数tweetをツイート内容にしてツイートして」というリクエストを送っています。

仕上げ

実装をしただけでは、まだ自動実行するbotとはいえません。最後の仕上げとして、このスクリプトを定期的に実行するようにしましょう。

この記事の最初のほうに書いたGASの紹介で、トリガー機能について述べました。今回は、このトリガー機能を使って自動実行させるようにします。

まず、エディタの上部メニュー「編集」→「現在のプロジェクトのトリガー」を押しましょう。別タブが開くはずです。

次に、ページ右下の「トリガーを追加」を押して、次の画像のように設定してください。「時刻の選択」は自分の好きな時間帯にして構いません。「エラー通知設定」についても、自由に設定して構いません。

トリガーの設定

図2.33: トリガーの設定

設定が終わったら、下部の「保存」を押しましょう。次の画像のような表示になれば、トリガーの設定は成功です。

トリガー設定完了

図2.34: トリガー設定完了

実際に、「時刻の選択」で設定した時間帯になると自動的にツイートが実行されるかと思います。これでようやくお天気botの完成です!

2.9 さいごに

今回作ったお天気botは実装が楽な部類のもので、JavaScriptの関数をもっと学べばさらに高度なbotを作ることができます。また、GASにはスプレッドシートなどと連携した機能があるので、変数データをスプレッドシートに保存しておくといった使い方もできます。

JavaScriptのリファレンスはネットにたくさん転がっており、GAS特有の関数についてもGoogle公式によるリファレンスが(英語ですが)あります。

GASリファレンス:https://developers.google.com/apps-script/reference/

これらを読んで、あなたも便利な機能をもったbotを作りましょう!