今回は、Google Apps Script(GAS)でTwitter APIのFree Plan v2を使用して自分のユーザー情報を定期実行でスタックするプログラムを作成しました。Twitter Free Planの制限なども知らなくて、苦労をしたので、注意するべきところ含めて解説しています。昔はできた!ってのが羨ましくちょっと悲しい
はじめに
ども!最近はブログサムネイル警察という取り組みを始めた龍ちゃんです。ブログが投稿されて、サムネイルに問題が発生している場合は、サムネイルをお届けするサービスを社内でひっそり展開しています。
さて!今回は、Google Apps Script(GAS)でTwitter APIを触る会になります。私の部署でやっているTwitterが、バッチを獲得しました。その流れもあって、Twitterの動向を定期的に取りたいというのが動機になっています。このブログでわかることは以下になります。
- GAS Free Planの制限に関して
- GASでTwitter API v2をOAuth2.0で使用するためのスクリプト
- 毎日、自分のフォロワー数・フォロー数・いいねされた数を取得してスプレッドシートに保存するスクリプト
それでは、Twitter APIに5日ほど悩まされた恨みを込めてまとめていきます。
Twitter Free Planの制限
もし、以下のエラー文で悩まされている方がいたらここをしっかり読んでみるといいかもしれません。
When authenticating requests to the Twitter API v2 endpoints, you must use keys and tokens from a Twitter developer App that is attached to a Project. You can create a project via the developer portal.
訳して、「ちゃんと設定しているのに!!」となった人は一度深呼吸をしましょう。落ち着いたら以下のサイトを開いてみてください。こちらの公式サイトを開いてください。各プランのアクセスすることができる制限が記載されています。
Free Planの場合は、Only Tweet creationとなっています。つまり、ツイートの作成しかできないわけです。(どおりでツイート周りの記事はいっぱいあると思った…)
次にTwitter Developer Portalを開いて、以下の画像を確認してください。ここでは、各プランがアクセスすることができるAPIが記載されています。
以上の情報から、Twitter API v2 Free Planでは、以下の二つのことが可能です。
それ以外のAPIにアクセスした時点ではじかれます。そして、もう一個制限がありまして。もし書くAPIにBearer tokenでアクセスした場合も同様にはじかれます。
これは、各リファレンスに記載があるのですが、OAuth2.0かOAuth1.0aじゃないと認証が通りません。(これを理解するのに3日かかりました…)
というわけで、本題に移っていきます。
Twitter API v2(OAuth2.0)で自分の情報を取得する
まずはAPIの利用申請を行う必要があります。その後、システムの全体像の説明と実装の説明に入っていきます。ちょっと長いですが、必要なところだけ抜き出しちゃってください。
Twitter API利用申請
まずは、利用申請です。こちらは、英語で作文が必要なのですが、ChatGPTと会話しながら作成したら行けると思います。まずは、原案をChatGPTにぶん投げます。それを添削してもらえば楽です。
原案はこちらの方を参考にさせていただきました。
全体像と事前に用意するもの
全体像としては以下になります。
ひとまず、Google Apps Scriptファイルと情報を書き込み先のスプレッドシートを作成しましょう。GASのファイルは、この後の設定で使うので開いておいてください。
青色が認証認可の流れで、赤色がTwitterAPIを使用した情報取得になります。
Twitter OAuth2.0利用申請
Twitter Developer Portal上で、OAuth2.0の利用申請を行いましょう。
クリックすると設定画面が開きます。権限周辺に関しては適したものを選択してください。今回の構成の場合はREAD
のみで大丈夫です。アプリケーションのタイプに関しても、Automated Appなので下です。Website URLは自分が持っているサイトのURLを書いておきましょう。もし、持っていない人は迷惑が掛からなさそうなところで申請しちゃいましょう。重要な設定としては、Callback URIになります。
ここは先ほど、作成したGASのIDを使用して以下のURLを作成します。
https://script.google.com/macros/d/{スクリプトID}/usercallback
すると、クライアントIDとシークレットが取得されます。一時的にメモしておきましょう。
GAS側にスクリプトプロパティ設定
先ほど取得した情報をスクリプトプロパティとして保存しておきましょう。スクリプトプロパティ何それ?という方は、こちらの記事を読んでみてください。
設定する項目としては、以下になります。
プロパティ名 | 説明 |
---|---|
CLIENT_ID | Twitter API OAuth2.0で取得したやつ |
CLIENT_SECRET | Twitter API OAuth2.0で取得したやつ |
SHEET_ID | 用意したGoogleシートのID |
設定項目は以上です。ちゃんと保存をしておきましょう。
GASでOAuth2.0用ライブラリをインストール
GAS上でOAuth2.0の認証認可を行うためにライブラリをインストールしておく必要があります。左側の「ライブラリ」を開いて以下の文字列を検索してください。追加するライブラリの情報はこちらです。
1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
以下の画面で追加してください。
これで実装前の準備が完了しました。
実装
それでは一気に実装に進んでいきます。ここまで準備が完璧だと、すんなり進んでいくと思います。
OAuth2.0認証を通す
まずは、APIを実行するための認証・認可を行う必要があります。ライブラリの公式リファレンスを参照に以下のコードをコピペしてmain
を実行してください。
function getService() {
pkceChallengeVerifier();
const userProps = PropertiesService.getUserProperties();
const scriptProps = PropertiesService.getScriptProperties();
const clientId = scriptProps.getProperty('CLIENT_ID');
const clientSecret = scriptProps.getProperty('CLIENT_SECRET');
return OAuth2.createService('twitter')
.setAuthorizationBaseUrl('https://twitter.com/i/oauth2/authorize')
.setTokenUrl('https://api.twitter.com/2/oauth2/token?code_verifier=' + userProps.getProperty("code_verifier"))
.setClientId(clientId)
.setClientSecret(clientSecret)
.setCallbackFunction('authCallback')
.setPropertyStore(userProps)
.setScope('users.read tweet.read tweet.write offline.access')
.setParam('response_type', 'code')
.setParam('code_challenge_method', 'S256')
.setParam('code_challenge', userProps.getProperty("code_challenge"))
.setTokenHeaders({
'Authorization': 'Basic ' + Utilities.base64Encode(clientId + ':' + clientSecret),
'Content-Type': 'application/x-www-form-urlencoded'
})
}
function authCallback(request) {
const service = getService();
const authorized = service.handleCallback(request);
if (authorized) {
return HtmlService.createHtmlOutput('Success!');
} else {
return HtmlService.createHtmlOutput('Denied.');
}
}
function pkceChallengeVerifier() {
var userProps = PropertiesService.getUserProperties();
if (!userProps.getProperty("code_verifier")) {
var verifier = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
for (var i = 0; i < 128; i++) {
verifier += possible.charAt(Math.floor(Math.random() * possible.length));
}
var sha256Hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifier)
var challenge = Utilities.base64Encode(sha256Hash)
.replace(/\\+/g, '-')
.replace(/\\//g, '_')
.replace(/=+$/, '')
userProps.setProperty("code_verifier", verifier)
userProps.setProperty("code_challenge", challenge)
}
}
function logRedirectUri() {
var service = getService();
Logger.log(service.getRedirectUri());
}
function main() {
const service = getService();
if (service.hasAccess()) {
Logger.log("Already authorized");
} else {
const authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s', authorizationUrl);
}
}
実行が完了したら、ログの部分に認証・認可用のURLが払い出されます。そこにアクセスしましょう。
許可を行い、「Success」が表示されたら成功です。
シートに記載する関数を作成
ここでは、実行結果を保存するための関数を用意しておきます。スクリプトプロパティからsheetID
を取得してシートを開いて最後の列に挿入しています。シート名をTwitterUserAnalytics
という名前で用意する必要があります。
function insertSheet([followers_count, following_count, tweet_count, listed_count, like_count]) {
const scriptProps = PropertiesService.getScriptProperties();
const sheetID = scriptProps.getProperty('SHEET_ID');
const file = SpreadsheetApp.openById(sheetID)
const sheet = file.getSheetByName("TwitterUserAnalytics")
const date = Utilities.formatDate(new Date(), 'JST', 'yyyy-MM-dd');
sheet.appendRow([date, followers_count, following_count, tweet_count, listed_count, like_count])
}
Twitter APIからユーザー情報を取得して保存
最終的に、Twitter APIにアクセスして情報を取得しましょう。エンドポイントにパラメータを追加して、標準で受け取る情報を拡張しています。標準では、内部ID・ID・名前しか取得することができません。ほかに取得できるパラメータとしては、公式リファレンスに記載されています。
const endpointMe = "https://api.twitter.com/2/users/me?user.fields=public_metrics";
function getUserMe() {
let service = getService();
if (service.hasAccess()) {
const response = UrlFetchApp.fetch(endpointMe, {
method: "get",
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
},
muteHttpExceptions: true,
contentType: "application/json"
});
const result = JSON.parse(response.getContentText());
const public_metrics = result["data"]["public_metrics"]
insertSheet([public_metrics["followers_count"], public_metrics["following_count"], public_metrics["tweet_count"], public_metrics["listed_count"], public_metrics["like_count"]])
} else {
Logger.log("Not Authorized");
return null;
}
}
ちなみにレスポンスとしては、こんな感じで帰ってきます。
{
"data": {
"id": "xxxxxxxxxxxxxxxxx",
"username": "RyuReina_Tech",
"name": "龍:Ryu",
"public_metrics": {
"followers_count": 0,
"following_count": 0,
"tweet_count": 0,
"listed_count": 0,
"like_count": 0
}
}
}
実行してみて、書き込みの確認が取れたら完了です。あとは、トリガーで一日おきに実行するように設定を行えば完了です。
終わりです
お疲れ様でした。最初は全然できなくて、久々に悩んでしまう内容でした。OAuthにちょっと入門しておいてよかったです。全部、Bearer で行けると思うやんと思ってましたけど、公式リファレンスはちゃんと読もうという結論が出ましたね。
にしても、API利用申請がめっちゃ時間かかるというイメージだったんですけど、申請してすぐ使えたのは制限が厳しくなったおかげでアクセスが容易になったんですかね。
まぁChatGPTに作文してもらったんであんまり関係ないんですけどね。
さて!泣きながらまとめたので、もう十分でしょう!今回の参考資料です。