この記事について
Google Apps Script(以下、GAS)を使って、情報収集のために、ある固定のキーワードで定期的に検索を行い、Slackへ自動投稿する、ということをやってみた備忘録です。
GASから定期的に固定メッセージを自動投稿するというのを前回実施したので、その続きです。
(ちなみに、TwitterとSlackの連携は、この手順ですぐできます)
手順
大まかな手順です。
- Twitter Developer Accountの申請
- Twitter Appの作成
- GASスクリプト作成
4. Twitter Bearerトークン取得
5. Twitter 検索
6. Twitterの検索結果をSlackに通知 - GASトリガー設定(定期的実行)
手順詳細
1. Twitter Developer Accountの申請
Twitterの検索APIを呼ぶためには、Twitter Developer Accountの取得が必要です。
Twitter Developerのサイトから申請し、承認される必要があります。
右上の[Apply]から申請を開始できます。
申請時、Twitterアカウントでログインを求められるので、作成するアプリで利用するTwitterアカウントが必要です。私は、既存の普段使っているアカウントを使用しました。
また、Twitter APIを利用する予定のアプリケーションについて、その内容や目的などを英語で書く必要がありました。Google翻訳を利用しながら埋めました。
申請には30分〜1時間くらい時間がかかったので、時間に余裕があるときに取り組むとよさそうです。
Twitter Developerの登録については既に色々な記事が書かれているので、気をつけるべきポイントを事前に確認できました。
承認されると、このようなメールアドレス確認のメールが届きました。
メールアドレスを確認すると、無事にDeveloper Accountが取得できました!
私の場合、申請してから承認されるのに1時間もかからなかった記憶があるのですが、このあたりは申請内容に拠るのだと思います。既出の記事だと、数日かかる場合もあるようでした。
2. Twitter Appの作成
Twitterの公式ドキュメントのGetStartedに従いながら進めます。
Twitter Developer Account / GetStarted
Twitter APIを使用するには、OAuth認証スキームの一部として、アプリを作成する必要があります。
アプリを作成することで、API呼び出しに必要なAPI keysが発行されます。
Twitter DeveloperサイトのAppsページへ行き、Create an appから必要な項目を入力し、Appを作成します。
アプリが作成され、Consumer API keys
が生成されました。
Website URL
が必須項目だったので、作成する予定のGASスクリプトのURLを登録しました。(URLを指定するために、空のGASスクリプトを作成しておきました。)
[Keys and tokens]の注意書きで書かれているように、2020年1月20日以降は、初回にaccess token
とaccess token secret
を生成した以降はこのページで表示されなくなるので、必要なら書き留めておく必要がありそうです。またはいつでもこのサイトから再生成できるようです。
アプリのAccess permission
は、ツイートを読み込むだけでツイートの書き込みはしないので、Read-only
に設定しました。
参考になりそうな公式ドキュメントはこちら です。
これで、Twitter APIを呼び出す準備が整いました。
3. GASスクリプト作成
ここから、GASのスクリプトを書いていきます。
この手順の1-3を参考に、GASのスクリプトを用意します。
1. Twitter Bearerトークン取得
Twitter APIを呼ぶには認証が必要です。
特定のアカウントのデータにアクセスする(ユーザの情報を読み取ったり、そのユーザとして書き込みする)にはアクセストークンでの認証が必要です。公開されている情報にアプリケーションとしてアクセスするにはアプリケーション認証(Bearerトークン)を行います。
今回は、公開されている情報にアクセスすれば十分なので、Bearerトークンを使ったアプリケーション認証を行います。
認証の処理の流れは、こちらの図がわかりやすいです。
出典:Application-only authentication
Twitter認証について参考になりそうなページはこちら です。
- Twitter Developer Docs Autentication overview
- Twitter REST APIの使い方
- OAuth 2.0 Bearer Token
- Application-only authentication
GASで、TwitterのBearerトークンを取得するプログラムを書いていきます。
Twitterのドキュメント(Application-only authentication)に、アプリケーション認証の方法が書かれているので、それに沿って進めます。
POST oauth2/token
に、以下のようなリクエストを行う必要があります。
-
Authorization
ヘッダに、Consumer key
、コロン[:]、Consumer secret
を連結してBase64エンコードした文字列をBasic xxxxxxxxxxx
の形式で設定 -
Content-Type
ヘッダにapplication/x-www-form-urlencoded;charset=UTF-8
を設定 - リクエストボデイに
grant_type=client_credentials
を設定
(ドキュメントでは、最初にConsumer key
とConsumer secret
をRFC1738
に沿ってURLエンコードする必要があると書いてありました。この手順はConsumer key
とConsumer secret
の値を変更しないが、これらの値の形式が将来変更される場合に備えてこの手順を実行する必要があるということです。今回は、現時点で値は変更されないので省略しました。)
参考にしたURLです。
-
Class Utilities(Google Developers)
- GASでBase64エンコードする方法
-
POST oauth2/token(Twitter Docs)
- TwitterのBearerトークン取得のAPIリファレンス
-
UrlFetchApp(Google Developers)
- GASでPOSTする方法
Bearerトークンを取得するコードです。
var consumer_key = 'xxxxxxxxxxxxxxxxx';
var consumer_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
function searchTweetsApps() {
// ①Twitter Bearerトークンの取得(検索APIの呼び出しに必要)
// POST oauth2/token https://developer.twitter.com/en/docs/basics/authentication/api-reference/token
var blob = Utilities.newBlob(consumer_key + ':' + consumer_secret);
var credential = Utilities.base64Encode(blob.getBytes());
var formData = {
'grant_type': 'client_credentials'
};
var basic_auth_header = {
'Authorization': 'Basic ' + credential
};
var options = {
'method': 'post',
'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
'headers': basic_auth_header,
'payload': formData,
};
var oauth2_response = UrlFetchApp.fetch('https://api.twitter.com/oauth2/token', options);
var bearer_token = JSON.parse(oauth2_response).access_token;
ちゃんとBearerトークンが取得できているか見たいので、GASでログに書き出してみます。
Logger.log(bearer_token);
GASの[View]->[Logs]から見ると、Bearerトークンが参照できたので問題なさそうです。
2. Twitter 検索
やっと、本題のTwitter検索です。
Twitterの検索APIは、こちらのドキュメントSearch Tweets API overviewを見ていただけるとわかるのですが、Standard, Premium, Enterpriseの3種類があります。検索対象の期間、有料/無料などが異なり、できることが異なっています。
今回は、無料で7日前までのツイートを検索できるStandardを使います。
APIリクエストのAuthorization
ヘッダに、前述の手順で取得したBearerトークンを、Bearer xxxxxxxxxxxxx
の形式で設定します。
リファレンスはこちら です。
-
Standard search API
- Standard search APIのリファレンス。
-
Tweet objects
- Twitter検索結果のAPIが返すツイートのオブジェクトのリファレンス。
-
Using Standard Search
- クエリの組み立て方についてのリファレンス。
GASで書いたコードです。
変数search_keyword
には、[Using Standard Searchのドキュメント]に沿って、ツイートを検索したい文字列を設定します。
私は検索結果からリツイートを除外したかったので、-rt
を指定しています。
また、検索件数をcount
で指定できるので、3件を指定しました。
// ②Twitter 検索APIの呼び出し
// GET https://api.twitter.com/1.1/search/tweets.json
var search_keyword = 'xxxxx -rt';
var bearer_auth_header = {
'Authorization': 'Bearer ' + bearer_token
};
var search_response = UrlFetchApp.fetch(
'https://api.twitter.com/1.1/search/tweets.json?q=' + search_keyword + '&lang=ja&result_type=recent&count=3',
{ 'headers': bearer_auth_header });
result = JSON.parse(search_response);
3. Twitterの検索結果をSlackに通知
Twitterで検索結果の文字列を、Slackに通知します。
こちらの手順4を参考に、SlackのWebhook URLを呼び出すコードを書きます。
こんなコードになりました。
検索結果が3件なので、forEach
で1件ずつSlackにPOSTしています。
投稿結果がわかりやすいように、ツイートの投稿日時(created_at)やユーザ名(user.name)、区切り線を入れてみました。
// ③Slackに通知 Incoming Webhook
result.statuses.forEach(function(status) {
var data = {
'text': '-----------------------------------------\n' +
status.text +
'\n----------------------------------------\n' +
status.created_at +
'\nby ' +
status.user.name,
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
UrlFetchApp.fetch(slackWebhookUrl, options);
これでGASを実行すると、このように検索結果がSlack通知されました。
(GAS%20Google Apps Script -rt
で検索した結果です)
4. GASトリガー設定(定期的実行)
あとは、定期実行のために、GASでトリガーを設定します。
こちらの手順を参考に、GASのトリガーを設定します。
これで、定期的にTwitterを固定キーワードで検索して、その結果をSlackに投稿することができました!
最後に、全体のコードを載せておきます。
var slackWebhookUrl = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var consumer_key = 'xxxxxxxxxxx';
var consumer_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var search_keyword = 'xxxxxxxx -rt';
function searchTweetsApps() {
// ①Twitter Bearerトークンの取得(検索APIの呼び出しに必要)
// POST oauth2/token https://developer.twitter.com/en/docs/basics/authentication/api-reference/token
var blob = Utilities.newBlob(consumer_key + ':' + consumer_secret);
var credential = Utilities.base64Encode(blob.getBytes());
var formData = {
'grant_type': 'client_credentials'
};
var basic_auth_header = {
'Authorization': 'Basic ' + credential
};
var options = {
'method': 'post',
'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
'headers': basic_auth_header,
'payload': formData,
};
var oauth2_response = UrlFetchApp.fetch('https://api.twitter.com/oauth2/token', options);
var bearer_token = JSON.parse(oauth2_response).access_token;
// ②Twitter 検索APIの呼び出し
// GET https://api.twitter.com/1.1/search/tweets.json
var bearer_auth_header = {
'Authorization': 'Bearer ' + bearer_token
};
var search_response = UrlFetchApp.fetch(
'https://api.twitter.com/1.1/search/tweets.json?q=' + search_keyword + '&lang=ja&result_type=recent&count=3',
{ 'headers': bearer_auth_header });
result = JSON.parse(search_response);
// ③Slackに通知 Incoming Webhook
result.statuses.forEach(function(status) {
var data = {
'text': '-----------------------------------------\n' +
status.text +
'\n----------------------------------------\n' +
status.created_at +
'\nby ' +
status.user.name,
};
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
UrlFetchApp.fetch(slackWebhookUrl, options);
});
}
やってみた感想
TwitterのAPIを触るのがはじめてだったので、Developer Accountの申請、APIの認証方式などについて調べるのに手間取りましたが、Twitterからの定期的な情報収集という目的が果たせたのはよかったです。
Slackへの投稿も装飾したりできそうなので、広げてやってみたらおもしろいかもしれないと思っています。