Google Apps ScriptからTwitter API v2を使ってツイートする【GAS】
2020年8月にそれまで制限の厳しかったTwitterのAPIが割と簡単に申請して利用できるようになったので、遅まきながらGoogle Apps ScriptからこのTwitter API v2を使ってツイートをしてみた。
しかし、他のREST APIと異なり、OAuth2.0認証ではなく古いOAuth1.0認証のままなので、ちょっとこれまでのコードとは異なる(特に使用するライブラリ)。ということで、ボットなどで使えるように下準備をしてみました。
※2023年1月時点、大きくTwitter APIが変更されており動作しなくなりました。また新しくOAuth2.0認証も登場したので、そちらでコードを書き直しました。以下のエントリーを参考にしてみてください。
目次
今回使用するスプレッドシート等
- Twitter v2 - Googleスプレッドシート
- OAuth1 for Apps Script - 認証用ライブラリ
いつも使ってるOAuth2.0認証用ライブラリではなく、1.0用のライブラリを使用します。コードの書き方は殆ど同じになるように寄せてます。また、本ライブラリはV8ランタイムでもきちんと動作します。
APIリファレンスをよく見て色々な事に活用しましょう。11/15より正式にv2がv1より変わった事に伴ってAPIの追加などもされているので、注意です。
事前準備
Twitter API v2は利用申請が必要です。関連リンクを参考に申請を行い、利用できるようにしておく必要があります。利用できるようになったら、以下の手順でGAS側、Twitter側でそれぞれ準備を行います。
GAS側の事前準備
ライブラリの追加
以下の手順でOAuth1 for Apps Scriptライブラリを追加しましょう。
- スクリプトエディタを開きます。
- サイドバーよりより「ライブラリ」の+ボタンをクリック
- ライブラリを追加欄に「1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s」を追加します。
- 今回はバージョンは18を選択してみます。
- 保存ボタンを押して完了
これで、OAuth1.0認証にまつわる様々な関数を手軽に利用できるようになります。
図:ライブラリを追加した様子
コールバックURLを取得する
コールバックURLとは、認証を完了しAccess Tokenを取得したら戻るべきURLを指定するものです。これは、スクリプトIDをもとに作られているので、スクリプトIDを取得して組み立てます。
- スクリプトエディタのサイドバーより「プロジェクトの設定」を開く
- 情報の中にある「スクリプトID」を控えておく。
- https://script.google.com/macros/d/スクリプトID/usercallback として組み立てる。これがコールバックURLとなる。
図:スクリプトIDはファイル毎に異なるのです。
Twitter側の事前準備
アプリの作成
Twitter側ではアプリのプロジェクトを作成すると共に、API KeyとSecretを取得する必要があります。以下の手順で作成しましょう。
- Twitter DevelopersのDashboardにアクセスする
- 下のほうにある「Create App」をクリックする
- AppNameを指定します。今回は「autotweet_gas」と命名しました。これは後にコード内で利用します。同じ名前は利用出来ないので、誰かが取ってると使えません。
- API KeyとSecretが表示されてるので、コピーしておきます。
- App Settingsをクリックする
- App PermissionsのEditボタンをクリック
- Read and Writeに変更して、Saveをクリックする
- Authentication SettingsのEditボタンをクリックする
- Enable 3-legged OAuthのスイッチをオンにする
- Callback URLsに前述のGAS側のコールバックURLを入れる
- Website URLは適当に入れて、Saveをクリックする
注意点として、最初の1個目はstandardアプリとして作れますが、2個目以降はstand aloneアプリとなり、こちらではGASからはツイートは出来ません(403エラーになります)
図:ここの設定の変更が重要です
利用制限
Twitter API v2のQuotaを調べて見ると、以下のような制限があります。
- ツイートは15分、1アプリ当たり300件(ユーザ単位だと900件まで) - v1エンドポイントの場合
- ツイートは15分、1アプリ当たり200件 - v2エンドポイントの場合
- また、v2エンドポイントでの投稿の場合、3時間以内にユーザ・アプリ毎に300リクエストまでという追加規制があります。
- いいねは、24時間当たり1000リクエストまで
- ツイートの取得は1リクエスト100件まで(100件を超える部分は、next tokenでの取得が必要)
- 画像のアップロードはv1でなければ現在まだアップロード出来ません。v2ではメディアアップロードのエンドポイントがまだ存在していません。v1のドキュメントはこちらにあります。
他にも細かな項目ごとにリミットが掛けられているので、利用する場合には意識する必要があります。特に同じアプリを複数で共有する場合、あっという間にリミットに達してしまうので要注意。応答ヘッダーにその内容がx-rate-limitとして含まれているので、エラー処理を加えたい場合には考慮すると良いでしょう。超過すると429エラー(Too Many Request)が返ってきます。
また、API KeyはPermissionを変更すると使えなくなるので、再度生成する必要性があります。
同じようなキーワードでの検索の場合、リアルタイムでなければスプレッドシートにキャッシュしておいて、それを返すようにしておくと、リクエスト数を減らす事が可能(キャッシュはトリガー使用で1時間ごとに1回取得などにしておくと良いでしょう)。また、連続して大量のツイートを取得するようなケースでは、リミットに抵触しないように、Utilities.sleepでスリープ処理を入れるべきでしょう。
申請不要で使えるようになりました
2021年11月15日、Twitter API v2が正式なAPIとしてv1から移行され、同時にこれまで煩雑な申請が必要であったAPI利用申請ですが、「Essensial」というレベルであれば、申請不要で利用可能になりました。その上位の「Elevated」というレベルでは申請が必要です。既にAPI利用申請を出して取得済みの人は、自動的にElevatedレベルになります(Elevated+やAcademic Researchという研究用レベルも用意されています。)
- Essential : 1アプリケーション、50万ツイート/月の取得まで
- Elevated : 3アプリケーション、200万ツイート/月の取得まで
となっています。詳細はこちらのURLより
図:自動的にElevatedになってた
認証を行う処理を作成する
ここまでで事前準備が完了し、あとは認証を実行してAccess Tokenを取得すればツイートの実行準備はすべて完了になります。
GAS側コード
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
//メニューを構築する function onOpen(e) { var ui = SpreadsheetApp.getUi(); ui.createMenu('▶OAuth認証') .addItem('認証の実行', 'startoauth') .addItem('テストツイート', 'testtweet') .addSeparator() .addItem('ログアウト', 'reset') .addItem('スクリプトプロパティ', 'openCheck') .addToUi(); } //認証用の各種変数 var apikey = 'ここにAPI KEYを入れる'; var apisecret='ここにAPI Secretを入れる'; var tokenurl = "https://api.twitter.com/oauth/access_token"; var reqtoken = "https://api.twitter.com/oauth/request_token"; var authurl = "https://api.twitter.com/oauth/authorize"; var endpoint = "https://api.twitter.com/1.1/statuses/update.json"; //ツイートをするエンドポイント var endpoint2 = "https://api.twitter.com/2/tweets"; //v2のツイートするエンドポイント var appname = "ここにアプリの名称を入れる"; //アプリの名称 //認証実行 function startoauth(){ //UIを取得する var ui = SpreadsheetApp.getUi(); //認証済みかチェックする var service = checkOAuth(appname); if (!service.hasAccess()) { //認証画面を出力 var output = HtmlService.createHtmlOutputFromFile('template').setHeight(450).setWidth(500).setSandboxMode(HtmlService.SandboxMode.IFRAME); ui.showModalDialog(output, 'OAuth1.0認証'); } else { //認証済みなので終了する ui.alert("すでに認証済みです。"); } } //認証チェック用関数 function checkOAuth(serviceName) { return OAuth1.createService(serviceName) .setAccessTokenUrl(tokenurl) .setRequestTokenUrl(reqtoken) .setAuthorizationUrl(authurl) .setConsumerKey(apikey) .setConsumerSecret(apisecret) .setCallbackFunction('authCallback') .setPropertyStore(PropertiesService.getUserProperties()); } //認証コールバック function authCallback(request) { var service = checkOAuth(request.parameter.serviceName); var isAuthorized = service.handleCallback(request); if (isAuthorized) { return HtmlService.createHtmlOutput('認証が正常に終了しました'); } else { return HtmlService.createHtmlOutput('認証がキャンセルされました'); } } //アクセストークンURLを含んだHTMLを返す関数 function authpage(){ var service = checkOAuth(appname); var authorizationUrl = service.authorize(); var html = "<center><b><a href='" + authorizationUrl + "' target='_blank' onclick='closeMe();'>アクセス承認</a></b></center>" return html; } //ログアウト function reset() { OAuth1.createService(appname) .setPropertyStore(PropertiesService.getUserProperties()) .reset(); SpreadsheetApp.getUi().alert("ログアウトしました。") } |
- 取得したAPI Key、API SecretおよびAppNameをそれぞれコード内に記述します。
- 今回利用するTwitter APIのエンドポイントはhttps://api.twitter.com/1.1/statuses/update.jsonとなります。v2用のエンドポイントは、
https://api.twitter.com/2/tweetsとなっています(2021/11/15に追加)
- startoauthを実行して認証を実行すれば、スクリプトプロパティにAccess Tokenが格納されます。
- 認証時に次項のTemplate.htmlが呼び出され、認証完了するとCallback URLに指定したURLにアクセスされて、authCallBackが実行されます。
HTML側コード
template.htmlというダイアログ用のファイルを用意します。ここでアクセス承認を実行し、ログインをすると、アクセストークンその他が取得可能になります。
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css"> <script> //認証用URLを取得する google.script.run.withSuccessHandler(onSuccess).authpage(); function onSuccess(data){ document.getElementById("kinoko").innerHTML = data; } </script> <style type="text/css"> /* --- ボックス --- */ div.section { width: 480px; /* ボックスの幅 */ background-color: #ffffff; /* ボックスの背景色 */ border: 1px #c0c0c0 solid; /* ボックスの境界線 */ font-size: 100%; /* ボックスの文字サイズ */ } /* --- 見出し --- */ div.section h3 { margin: 0; /* 見出しのマージン */ padding: 6px 10px; /* 見出しのパディング(上下、左右) */ background-color: #f5f5f5; /* 見出しの背景色 */ border-bottom: 1px #c0c0c0 solid; /* 見出しの下境界線 */ font-size: 120%; /* 見出しの文字サイズ */ } /* --- ボックス内の段落 --- */ div.section p { margin: 1em 10px; /* 段落のマージン(上下、左右) */ } </style> <div class='section'> <h3 id='header'>OAuth認証の許可が必要です。</h3> <hr> <div id="info"> <p> このスクリプトは、Twitter API V2にアクセスするために、特別なログイン処理を利用しています。<br> 既に特別なログインに関する設定はなされており、承認がされるとプログラムを実行することが出来ます。この承認がなされない場合、プログラムの実行に制限が掛かり、 処理が続行できません。<br><br> <div id="kinoko"></div> </div> <p> <script> function closeMe(){ if(google && google.script && google.script.host){ google.script.host.close(); } else if(window && window.close){ window.close(); } } </script> </div> |
- 実際にこれらのコードで、startoauthを実行すると、スプレッドシート上で認証用のダイアログが出ます。
- 認証でtwitterにログインします
- 取得したAccess Tokenほかはスクリプトプロパティのappnameという項目にガッツリ値が格納されます。
- reset関数はログアウトされて、再度認証ができるようになります。
ツイートを実行する
認証の実行
スプレッドシートを開き直して、メニューより「OAuth認証」を開くと、「認証の実行」があるので、クリックして実行します。ダイアログが出てくるので、実行するとTwitter認証画面が出ます。
連携アプリを認証を実行するとAccess Tokenが取得されてスクリプトプロパティに格納され、認証が完了します。
図:認証を実行してる画面
取得したTokenを確認
本サンプルスプレッドシートは、スクリプトプロパティの中身を見られるように、機能を追加済みです。メニューより「OAuth認証」を開くと、「スクリプトプロパティ」があるので、開くことで、認証結果のTokenなどを確認出来ます。
図:無事取得出来てるのを確認する
ツイートの実行
v1 APIの場合
同じく、メニューより「OAuth認証」を開くと、「テストツイート」があるので、開くと以下のGASのコードを実行し、GAS側からツイートを実行することが可能になります。これを改造して、例えばスプレッドシートに列挙したデータをトリガーなどを使って自動ツイートしてみたりするBotを作る、何かの処理を行った結果を、GASで受け付けて、テストツイートを実行するように仕込んだりで、色々と使いみちがあると思います。
エンドポイントURLはhttps://api.twitter.com/1.1/statuses/update.jsonとなっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//テストツイートする function testtweet(){ //トークン確認 var service = checkOAuth(appname); //リクエストオプション var options = { "method": "post", "payload": { status: 'GASからツイートを実行してみた@v2 API' } } //リクエスト実行 var response = JSON.parse(service.fetch(endpoint, options)); //リクエスト結果 console.log(response) } |
- リクエストはPOSTで行い、service.fetchという形でライブラリの力を借りてリクエストを実行します。
- @アカウント名をstatusに入れれば、リプになります。
- この他ツイートだけでなくデータの取得などのメソッドもたくさん用意されてるので、この仕組があれば、Twitterを色々と操作することが可能になると思います。
図:GASから実行した結果
v2 APIの場合
正式にv2 APIがリリースされたことによって、v2用のエンドポイントURLが用意されました。URLは、https://api.twitter.com/2/tweetsとなり、このURLに対して、POSTメソッドで投げる必要性があります。リクエストパラメータが変更されていて、しかも公式ドキュメントが非常に読みにくい物になっています。
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 |
var endpoint2 = "https://api.twitter.com/2/tweets"; //テストツイートする function testtweet2(){ //トークン確認 var service = checkOAuth(appname); //message本文 var message = { //テキストメッセージ本文 text: 'GASからツイートを実行してみた@v2 API' } //リクエストオプション var options = { "method": "post", "muteHttpExceptions" : true, 'contentType': 'application/json', 'payload': JSON.stringify(message) } //リクエスト実行 var response = JSON.parse(service.fetch(endpoint2, options)); //リクエスト結果 console.log(response) } |
- メッセージ本文はJSON化する必要があります。またその時のリクエストパラメータは本文はtextで指定が必要
- リクエスト時にcontentTypeにてapplication/jsonの指定が必要です。
- 画像などはリクエストパラメータにて、mediaで指定するようですが、こちらはまだ調査中。
ツイートを取得してみる
Twitterをキーワード検索して結果をスプレッドシートに書き出してみようと思います。クエリの作り方については、Building queries for Search Tweetsに記載があります。エンドポイントは、https://api.twitter.com/2/tweets/search/recent?query=となり、これにワードやオプションをつなげて実行します。ユーザ名検索の場合は@マークはつけません(こちらはAPIのバージョンが2となってる)
今回は「Google Apps Script」で検索して日本でのツイートを20件ずつ合計40件取得してみます。また、検索オプションで指定する取得するデータの指定であるtweet.fieldsやレスポンスついてはこちらで確認出来ます。
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
var getpoint = "https://api.twitter.com/2/tweets/search/recent?query="; //ツイートを検索取得する為のエンドポイント //特定ワードでツイートを取得する function gettweet(){ //トークン確認 var service = checkOAuth(appname); //検索オプション(20件で指定) var option = "&tweet.fields=author_id,id,text,created_at&max_results=20"; //検索キーワード(URI Encodeする) var keyword = encodeURIComponent("\"google apps script\" -is:retweet lang:ja") //検索キーワードとURL構築 var url = getpoint + keyword + option; //リクエスト実行 var response = JSON.parse(service.fetch(url)); //リクエスト結果からnext tokenを取得する var next = response.meta.next_token; //dataの中身を配列に書き出す var array = []; var data = response.data; var length = data.length; for(var i = 0;i<length;i++){ //一時配列を用意 var temparr = []; //レスポンスデータを配列に書き出す temparr.push(data[i].author_id); temparr.push(data[i].text); temparr.push(data[i].created_at); //書込み用配列に追加 array.push(temparr); } //次の20件を取得する(nexttokenを使用する) option = option + "&next_token=" + next; //URL構築 url = getpoint + keyword + option; //リクエスト実行 response = JSON.parse(service.fetch(url)); //スリープを10秒入れる Utilities.sleep(10 * 1000); //次の20件のデータをarrayに追加 data = response.data; length = data.length; for(var i = 0;i<length;i++){ //一時配列を用意 var temparr = []; //レスポンスデータを配列に書き出す temparr.push(data[i].author_id); temparr.push(data[i].text); temparr.push(data[i].created_at); //書込み用配列に追加 array.push(temparr); } //arrayをスプレッドシートに上書きで書込み var ui = SpreadsheetApp.getUi(); var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1"); var colcnt = array[0].length; var rowcnt = array.length; ss.getRange(2,1,rowcnt,colcnt).setValues(array); //完了メッセージ ui.alert("ツイートデータの取得が完了しました。") } |
- optionにてツイート内容のうち取得する項目をtweet.fieldsで指定。またmax_resultで1回当たりの取得ツイート数を指定
- キーワードはURL Encodeが必要なのでencodeURIComponentで加工。
- キーワードに於いて、ダブルコーテーションで括って絞り込みが必要な時は、バックスラッシュでダブルコーテーションをエスケープする必要があります。
- また、今回はリツイートは取得しないので、-is:retweetで排除し、日本語だけを取得するので、lang:jaを指定しています。
- 取得データを配列に加えて最後に一発でスプレッドシートに書込みをしています。
- また、今回は20件を2回実行して、合計40件のツイートを取得するので、2回目以降ではoptionにnext_tokenを加える必要があるので、1回目のレスポンスデータに入ってるnext_tokenをoptionに追記させてリクエストしています(これで次の20件が取れる)
- リミットにかからないように、2回目のリクエスト前にUtilities.sleepで10秒間スリープを入れています。
図:無事にツイートを取得できた
関連リンク
- Twitter API アップデート 何が変わって何ができるようになった?
- Announcing manage Tweets endpoints for the Twitter API v2
- Comparing Twitter API’s manage Tweets endpoints
- Fields - Docs Twitter API
- UrlEncode.net
- M-Igashi/TwitterWebService.gs
- Twitter 黒歴史クリーナー
- 2021年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説
- TwitterAPI V2の申請からキーの取得まで
- PythonでTwitter API v2を使ってみよう。ツイートを探す編
- TwitterがAPI機能を拡張、開発者は公開された会話の追跡が可能に
- Twitter API経由でいいねやブロック情報が一覧取得可能に
- Twitter API v2正式リリース。開発者を締め出してきた Twitter API の歴史
- 【GAS】Google Apps Script 活用事例 Twitter API version 2.0で、スプレッドシートに情報を書き出してみよう!!
- Twitter Search API v1.1 と v2の 違いメモ
- Google Apps Script(GAS)のエスケープ文字一覧!文字列の特殊文字をまとめ
- Twitter API v2でツイートを取得する by Bearer token
- TwitterのAPIでcallbackURLをチェックするようになった
- TwitterのAPIがアップデートされ「いいね」などのデータにアクセス可能に