今回は、Google Apps Script(GAS)とGoogleスプレッドシートを用いて、Twitterに定期自動投稿をする方法を解説します。
コピペ用のソースコードを記事の最後に載せますので、本記事の手順通りに設定すれば無料で自動投稿ができるようになります。(↓こんなかんじ)
全体像
過去に投稿したブログ記事を、ランダムに投稿する
今回は、こちらを実現したいと思います。全体像は以下のとおりです。
Googleスプレッドシートに記載してあるブログ記事リストを、GASでランダムで取得します。その内容をTwitter APIでツイッターに自動投稿するという流れです。
事前準備
まず、Google Apps Script(GAS)を使ってTwitterに自動投稿を行うには、GAS・Twitterそれぞれの設定が必要です。
これについては、以下記事で初心者の方でも分かるよう詳しく説明していますので、参考にしながら設定していただければと思います。うまくいかない、記事読んだけどやり方が分からないという場合はお気軽にコメントください!
以下のように、GASから実行してツイッターに投稿が追加されるような状態になればいったんOKです。
スプレッドシートに投稿したい内容を記載する
ツイッターに自動投稿する内容を、あらかじめGoogleスプレッドシートに記載しておきます。このとき、シートIDをメモしておいてください。GASのスクリプトに記載します。
Googleスプレッドシートの基本的な使い方については以下記事をにて解説しています。
A列にブログタイトル、B列に記事のURLを記載していきます。
wordpressの場合はプラグインで一括エクスポートが可能です。プラグインを使わない場合は記事一覧で全選択→スプレッドシートにそのまま貼り付けして成形という形になります。
GASでスプシの内容を成形&ツイート
では、ここからはGASの実装です。
スプレッドシートの内容を取得して投稿用の文面を作成
スプレッドシートの内容を取得し、投稿用の文面を作成するソースコードは以下のようになります。
// 投稿メッセージの作成
function autoTweetFromSheet() {
// 同じ内容のツイートはできないので日付を付加する
let today = new Date();
let todayStr = Utilities.formatDate(today, 'JST', 'yy-MM-dd');
// 対象のシートを取得
let sheet = SpreadsheetApp.openById(SHEET_ID).getSheets()[1];
// 記事の総数を取得
let lastRow = sheet.getLastRow();
// ツイートする記事をランダムに選択
let targetRow = randomNum(lastRow);
// タイトルとURLを取得
let title = sheet.getRange(targetRow, 1).getValue();
let link = sheet.getRange(targetRow, 2).getValue();
// ツイート文面の作成
let msg = '【prtn-blogおすすめ記事紹介 '+ todayStr + '】\n\n' + title + '\n\n' + '詳細は以下をチェック♪' + '\n\n' + link + '\n';
return msg;
}
上記では、シートを「.getSheets()[1]」のように数字を引数に取得しています。この場合、2番目のシートを取得することができます。「.getSheetByName(“sheet1”)」のように、シート名で取得することも可能です。
getLastRow()でスプレッドシートに書かれている内容の最終行を取得し、その数値を乱数作成メソッドへ渡します(乱数作成メソッドについては後述)。
乱数を対象行として、タイトル、URLそれぞれをgetRange()で取得します。それをもとに、ツイート文面を作ります。上記の例では以下のようになります。
上記ではタイトルとURLの2つを取得するようにしましたが、列を増やしてハッシュタグや本文などを入れるなどご自身の目的に合わせてアレンジしていただければと思います。
乱数を作成
ランダムに投稿するための乱数作成は、以下のようなコードで行います。
function makeRundom(count) {
// 0.0以上1.0未満のランダムな数値を取得
let random = Math.random();
// 1からcountまでの整数の乱数を作成
random = Math.floor(random * count) + 1;
return random
}
count変数には「.getLastRow()」で取得した、シート内の内容の総数が入ってきます。例えば100件の場合はcount=100となります。
乱数の作成は「Math.random()」で行えますが、このままだと小数点がついた形となっているので、整数に直します。この際、1からcountまでの数で乱数の整数を作るようにします。例えば100件の場合は、1~100までのランダムな数が生成されます。
今回の例ではランダムに投稿することが目的なので乱数を作りましたが、このへんはどんな風に投稿したいかによって変わってきます。もし、「こんな運用がしたいけど、やり方が分からない」という場合は、コメントや問い合わせ等をいただければと思います。
作成した文面をツイートする
こちらの記事にあるソースコードをベースに実装していきます。
ツイート処理(sendTweet())を変更します。現状のソースコードでは、固定の文字列をツイートするようになっています。
上記のうち、固定の文字の部分に先ほど作成した関数を入れてあげます。
これで完了です。
ソースコードの一部分だけ変えるとかちょっと自身ない、、という場合は、コピペ用のソースコードを以下に載せますのでそちらをそのまま貼り付けてみてください。
コピペ用ソースコード
以下にコピペ用のソースコードを載せます。
const CLIENT_ID = '[ツイッターのクライアント識別子]'
const CLIENT_SECRET = '[ツイッターのClient Secret]'
const SHEET_ID = "[スプレッドシートのID]";
var twitter = TwitterWebService.getInstance(CLIENT_ID, CLIENT_SECRET);
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);
}
}
// スプレッドシートからツイッターに投稿する記事をランダムに取得しツイート
function autoTweetFromSheet() {
let today = new Date();
let todayStr = Utilities.formatDate(today, 'JST', 'yy-MM-dd');
let sheet = SpreadsheetApp.openById(SHEET_ID).getSheets()[1];
let lastRow = sheet.getLastRow();
let targetRow = makeRundom(lastRow);
let title = sheet.getRange(targetRow, 1).getValue();
let link = sheet.getRange(targetRow, 2).getValue();
let msg = '【prtn-blogおすすめ記事紹介 '+ todayStr + '】\n\n' + title + '\n\n' + '詳細は以下をチェック♪' + '\n\n' + link + '\n';
return msg;
}
// 乱数作成
function makeRundom(count) {
let random = Math.random();
random = Math.floor(random * count) + 1;
return random
}
function getService() {
pkceChallengeVerifier();
const userProps = PropertiesService.getUserProperties();
const scriptProps = PropertiesService.getScriptProperties();
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(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.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(CLIENT_ID + ':' + CLIENT_SECRET),
'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 sendTweet() {
var payload = {
text: autoTweetFromSheet()
}
var service = getService();
if (service.hasAccess()) {
var url = `https://api.twitter.com/2/tweets`;
var response = UrlFetchApp.fetch(url, {
method: 'POST',
'contentType': 'application/json',
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
},
muteHttpExceptions: true,
payload: JSON.stringify(payload)
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
var sheet = SpreadsheetApp.openById(SHEET_ID).getSheets()[0];
var lastRow = sheet.getLastRow();
let now = new Date();
sheet.getRange(lastRow + 1, 1).setValue(result['data']['id']);
sheet.getRange(lastRow + 1, 2).setValue(result['data']['text']);
sheet.getRange(lastRow + 1, 3).setValue(now);
} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s', authorizationUrl);
}
}
上記ソースコードのうち、以下をご自身の環境に合わせて変更してください。
変数名 | 設定内容 |
---|---|
CLIENT_ID | ツイッターのクライアント識別子 |
CLIENT_SECRET | ツイッターのClient Secret |
SHEET_ID | スプレッドシートのID |
CLIENT_ID 、CLIENT_SECRETについての詳細はこちらの記事をご参照ください。
トリガーによる定期自動投稿の設定
GASで定期自動投稿を行うには、「トリガー」機能を使います。左側メニューにある時計のアイコンを押下します。
「トリガーを追加」を押して、トリガーを設定します。このとき、実行する関数を「sendTweet」に設定するのを忘れずに。
実行する間隔は、〇時間おき、毎日〇時、毎週〇曜日など選択できます。詳しくは以下記事にて解説しています。
8時、12時、19時みたいに時間指定したいとき
GASのトリガー機能で時間指定する際、「毎日〇時」みたいにピンポイントで時刻指定することはできません。代わりに、「午前8時~9時」のように1時間刻みで指定することは可能です。
例えば、
- 6~7時
- 11~12時
- 18~19時
に自動でツイートする場合は、以下のように3つのトリガーを設定しておきます。
こちらは実際に私が使っている自動投稿用のトリガーですが、「前回の実行」が指定した時間帯になっていることが分かります。(1時間ってけっこう幅が広いですけどね・・・)
まとめ
今回は、スプレッドシート×GASでTwitterに定期自動実行する方法を解説しました。
これ、実際に使ってみてとても便利だなーと感じています。スプレッドシートにほうも自動で更新できるようにできたら更に便利そうです。
自動投稿に関連する記事として、Webサイトのスクレイピング結果を成形してツイートするという記事も投稿していますので、合わせてご覧ください。
ツイッターAPIは、v2になってから無料アカウントだと実質投稿くらいしかできなくなっているので、使えるうちに活用しておきたいです。
コメント
参考にさせていただいております。
事前準備は問題なくいったのですが、下記エラーはなぜか分かりますでしょうか?
ReferenceError: TwitterWebService is not defined
ブログを閲覧いただきまして、ありがとうございます。
Google Apps Scriptの編集画面内に、「TwitterWebService」ライブラリは読み込んでありますでしょうか?
ライブラリID:1rgo8rXsxi1DxI_5Xgo_t3irTw1Y5cxl2mGSkbozKsSXf2E_KBBPC3xTF
こちらをGASの編集画面の左側にある「ライブラリ」に追加して、再度試していただけますでしょうか?
説明が不足しており申し訳ございませんでした。
よろしくお願いいたします。
ご親切にありがとうございました!