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側コード
//メニューを構築する
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というダイアログ用のファイルを用意します。ここでアクセス承認を実行し、ログインをすると、アクセストークンその他が取得可能になります。
<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となっています。
//テストツイートする
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メソッドで投げる必要性があります。リクエストパラメータが変更されていて、しかも公式ドキュメントが非常に読みにくい物になっています。
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やレスポンスついてはこちらで確認出来ます。
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がアップデートされ「いいね」などのデータにアクセス可能に








