【GAS、Google Spreadsheet】Twitterにランダムなツイートを投稿するBotを作る

1865 語
9 分
【GAS、Google Spreadsheet】Twitterにランダムなツイートを投稿するBotを作る

はじまり#

リサちゃん avatar
リサちゃん
ねえねえ、一つお願いがあるんだけどさあ
135ml avatar
135ml
お? どうした?
リサちゃん avatar
リサちゃん
「カーディナル・ジョージ」ってTwitterで呟くBotを作って欲しいんだよね。
135ml avatar
135ml
・・・へ? どういうこと?
リサちゃん avatar
リサちゃん
だから、「カーディナル・ジョージ」ってTwitterで呟くBotを作って欲しいんだよね。
135ml avatar
135ml
・・・??????
リサちゃん avatar
リサちゃん
だめだな。埒が明かん。下に紹介したものがあります! それでは、行ってみよ〜!
135ml avatar
135ml
・・・え? 俺が悪かったの?

ソース全体#

main.gs:

// 方法A: TwitterWebServiceを使った認証およびコールバック: Start ----------------------------------------------
// 方法Aの日本語アカウント用: Start ----------------------------------------
// //認証用インスタンスの生成
// const twitter = TwitterWebService.getInstance(
// apiKeyTwitterAccountJp, //API Key
// apiKeySecretTwitterAccountJp //API secret key
// );
// //アプリを連携認証する
// function authorize() {
// twitter.authorize();
// }
// //認証を解除する
// function reset() {
// twitter.reset();
// }
// //認証後のコールバック
// function authCallback(request) {
// return twitter.authCallback(request);
// }
// 方法Aの日本語アカウント用: End ----------------------------------------
// 方法Aの英語アカウント用: Start ----------------------------------------
// //認証用インスタンスの生成
// const twitter = TwitterWebService.getInstance(
// apiKeyTwitterAccountEn, //API Key
// apiKeySecretTwitterAccountEn //API secret key
// );
// //アプリを連携認証する
// function authorize() {
// twitter.authorize();
// }
// //認証を解除する
// function reset() {
// twitter.reset();
// }
// //認証後のコールバック
// function authCallback(request) {
// return twitter.authCallback(request);
// }
// 方法Aの英語アカウント用: End ----------------------------------------
// 方法A: TwitterWebServiceを使った認証およびコールバック: End ----------------------------------------------
// 方法B: OAuth1.createServiceを使った認証およびコールバック: Start ----------------------------------------------
// 方法Bの日本語アカウント用: Start ----------------------------------------
// function getTwitterServiceJp() {
// // Create a new service with the given name. The name will be used when
// // persisting the authorized token, so ensure it is unique within the
// // scope of the property store.
// return OAuth1.createService('twitter')
// // Set the endpoint URLs.
// .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
// .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
// .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
// // Set the consumer key and secret.
// .setConsumerKey(apiKeyTwitterAccountJp)
// .setConsumerSecret(apiKeySecretTwitterAccountJp)
// // Set the name of the callback function in the script referenced
// // above that should be invoked to complete the OAuth flow.
// .setCallbackFunction('authCallback')
// // Set the property store where authorized tokens should be persisted.
// .setPropertyStore(PropertiesService.getUserProperties());
// }
function getTwitterServiceJp() {
return OAuth1.createService("Twitter")
.setAccessTokenUrl("https://api.twitter.com/oauth/access_token")
.setRequestTokenUrl("https://api.twitter.com/oauth/request_token")
.setAuthorizationUrl("https://api.twitter.com/oauth/authorize")
.setConsumerKey(apiKeyTwitterAccountJp)
.setConsumerSecret(apiKeySecretTwitterAccountJp)
.setAccessToken(accessTokenTwitterAccountJp, accessTokenSecretTwitterAccountJp);
};
function showSidebarToAuthJp() {
let twitterService = getTwitterServiceJp();
if (!twitterService.hasAccess()) {
let authorizationUrl = twitterService.authorize();
let template = HtmlService.createTemplate(
'<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
let page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
} else {
//
}
}
function authCallbackJp(request) {
let twitterService = getTwitterServiceJp();
let isAuthorized = twitterService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
// 方法Bの日本語アカウント用: End ----------------------------------------
// 方法Bの英語アカウント用: Start ----------------------------------------
// function getTwitterServiceEn() {
// // Create a new service with the given name. The name will be used when
// // persisting the authorized token, so ensure it is unique within the
// // scope of the property store.
// return OAuth1.createService('twitter')
// // Set the endpoint URLs.
// .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
// .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
// .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
// // Set the consumer key and secret.
// .setConsumerKey(apiKeyTwitterAccountEn)
// .setConsumerSecret(apiKeySecretTwitterAccountEn)
// // Set the name of the callback function in the script referenced
// // above that should be invoked to complete the OAuth flow.
// .setCallbackFunction('authCallback')
// // Set the property store where authorized tokens should be persisted.
// .setPropertyStore(PropertiesService.getUserProperties());
// }
function getTwitterServiceEn() {
return OAuth1.createService("Twitter")
.setAccessTokenUrl("https://api.twitter.com/oauth/access_token")
.setRequestTokenUrl("https://api.twitter.com/oauth/request_token")
.setAuthorizationUrl("https://api.twitter.com/oauth/authorize")
.setConsumerKey(apiKeyTwitterAccountEn)
.setConsumerSecret(apiKeySecretTwitterAccountEn)
.setAccessToken(accessTokenTwitterAccountEn, accessTokenSecretTwitterAccountEn);
};
function showSidebarToAuthEn() {
let twitterService = getTwitterServiceEn();
if (!twitterService.hasAccess()) {
let authorizationUrl = twitterService.authorize();
let template = HtmlService.createTemplate(
'<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
let page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
} else {
//
}
}
function authCallbackEn(request) {
let twitterService = getTwitterServiceEn();
let isAuthorized = twitterService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
// 方法Bの英語アカウント用: End ----------------------------------------
// 方法B: OAuth1.createServiceを使った認証およびコールバック: End ----------------------------------------------
function postTweet(sentence, language) {
// const service = twitter.getService(); // 方法Aによるサービス
let service;
let bearerTokenTwitterAccount;
if(language === 'JP'){
service = getTwitterServiceJp(); // 方法Bによるサービス
bearerTokenTwitterAccount = bearerTokenTwitterAccountJp;
}else if(language === 'EN'){
service = getTwitterServiceEn(); // 方法Bによるサービス
bearerTokenTwitterAccount = bearerTokenTwitterAccountEn;
}
const endPointUrl = 'https://api.twitter.com/1.1/statuses/update.json';
const options = {
'method': 'post',
// 'headers' : {Authorization: 'Bearer ' + bearerTokenTwitterAccount},
// "muteHttpExceptions" : true,
"payload": {
status: sentence
}
}
try {
let response = service.fetch(endPointUrl, options);
console.log(response);
} catch(e) {
// 例外エラー処理
console.log('Error:')
console.log(e)
}
}
function decideSentenceToTweet(wordArray, language){
const funcName = 'decideSentenceToTweet';
let sentenceToTweet = ''
if(wordArray.length === 1){
sentenceToTweet = wordArray[0];
console.log(`${funcName}:${getStrRepeatedToMark('a')}: `);
return sentenceToTweet;
}
if(language === 'JP'){
sentenceToTweet = `${wordArray[0]}${wordArray[1]}`;
}
if(language === 'EN'){
sentenceToTweet = `${wordArray[0]}${wordArray[1]}`;
}
console.log(`${funcName}:${getStrRepeatedToMark('b')}: `);
console.log(`sentenceToTweet:${sentenceToTweet}`);
return sentenceToTweet;
}
function selectRowAtRandom(amountOfRow, offsetAmountOfRow){
let randomFloat = 0;
while(randomFloat === 0){
randomFloat = Math.random();
}
return Math.floor(randomFloat * (amountOfRow)) + offsetAmountOfRow;
}
function selectWordsToTweet(language) {
const funcName = 'selectWordsToTweet';
const defaultRatio = 0.3;
const irregularRatio = 0.2;
let isIrregular = false;
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let sheet = spreadsheet.getSheetByName(sheetNameDisseminating1st);
let irregularIndex;
let amountOfWords;
let selectedRow;
let wordArrayToTweet = [];
// decide regular or irregular.
irregularIndex = Math.random();
console.log(`${funcName}:${getStrRepeatedToMark('a')}: irregularIndex is${irregularIndex}`);
if(irregularIndex < irregularRatio){
isIrregular = true;
}
console.log(`${funcName}:${getStrRepeatedToMark('b')}: isIrregular is${isIrregular}`);
if(isIrregular === true){
// irregular process.
let cell_amount_of_word_language;
let column_word_language;
if(language === 'JP'){
cell_amount_of_word_language = cell_amount_of_word_jp_for_irregular_1st;
column_word_language = column_word_jp_for_irregular_1st;
}
if(language === 'EN'){
cell_amount_of_word_language = cell_amount_of_word_en_for_irregular_1st;
column_word_language = column_word_en_for_irregular_1st;
}
amountOfWords = Number(sheet.getRange(cell_amount_of_word_language).getValue());
selectedRow = selectRowAtRandom(amountOfWords, row_start_of_word_list);
const irregularWord = String(sheet.getRange(selectedRow, column_word_language, 1, 1).getValue());
console.log(`${funcName}:${getStrRepeatedToMark('c')}: irregularWord is${irregularWord}`);
wordArrayToTweet.push(irregularWord);
console.log(`${funcName}:${getStrRepeatedToMark('d')}: `);
console.log(wordArrayToTweet);
return wordArrayToTweet;
}
console.log(`${funcName}:${getStrRepeatedToMark('e')}: `);
// regular process.
let cell_amount_of_word_cardinal,
column_word_cardinal,
cell_amount_of_word_george,
column_word_george;
if(language === 'JP'){
cell_amount_of_word_cardinal = String(cell_amount_of_word_jp_for_cardinal_1st);
column_word_cardinal = Number(column_word_jp_for_cardinal_1st);
cell_amount_of_word_george = String(cell_amount_of_word_jp_for_george_1st);
column_word_george = Number(column_word_jp_for_george_1st);
}
if(language === 'EN'){
cell_amount_of_word_cardinal = String(cell_amount_of_word_en_for_cardinal_1st);
column_word_cardinal = Number(column_word_en_for_cardinal_1st);
cell_amount_of_word_george = String(cell_amount_of_word_en_for_george_1st);
column_word_george = Number(column_word_en_for_george_1st);
}
console.log(`${funcName}:${getStrRepeatedToMark('e')}: `);
console.log(`cell_amount_of_word_cardinal:${cell_amount_of_word_cardinal}`);
console.log(`column_word_cardinal:${column_word_cardinal}`);
console.log(`cell_amount_of_word_george:${cell_amount_of_word_george}`);
console.log(`column_word_george:${column_word_george}`);
const amountOfWordsCardinal = Number(sheet.getRange(cell_amount_of_word_cardinal).getValue());
selectedRow = selectRowAtRandom(amountOfWordsCardinal, row_start_of_word_list);
const wordCardinal = String(sheet.getRange(selectedRow, column_word_cardinal, 1, 1).getValue());
const amountOfWordsGeorge = Number(sheet.getRange(cell_amount_of_word_george).getValue());
selectedRow = selectRowAtRandom(amountOfWordsGeorge, row_start_of_word_list);
const wordGeorge = String(sheet.getRange(selectedRow, column_word_george, 1, 1).getValue());
console.log(`${funcName}:${getStrRepeatedToMark('e')}: `);
console.log(`amountOfWordsCardinal:${amountOfWordsCardinal}`);
console.log(`wordCardinal:${wordCardinal}`);
console.log(`amountOfWordsGeorge:${amountOfWordsGeorge}`);
console.log(`wordGeorge:${wordGeorge}`);
wordArrayToTweet = [wordCardinal, wordGeorge];
console.log(`${funcName}:${getStrRepeatedToMark('f')}: `);
console.log(wordArrayToTweet)
return wordArrayToTweet;
}
function main() {
// Japanese mode.
let wordArray = selectWordsToTweet('JP');
let sentence = decideSentenceToTweet(wordArray, 'JP');
postTweet(sentence, 'JP');
// English mode.
wordArray = selectWordsToTweet('EN');
sentence = decideSentenceToTweet(wordArray, 'EN');
postTweet(sentence, 'EN');
}

constants.gs:

const sheetNameDisseminating1st = 'tweet';
const sheetNameDisseminating2nd = 'tweetメモ書き';
const sheetNameDisseminating3rd = 'replyRecord';
const sheetNameOthers1st = '';
const cell_amount_of_word_jp_for_cardinal_1st = 'A1';
const column_word_jp_for_cardinal_1st = 2;
const cell_amount_of_word_jp_for_george_1st = 'C1';
const column_word_jp_for_george_1st = 4;
const cell_amount_of_word_jp_for_irregular_1st = 'E1';
const column_word_jp_for_irregular_1st = 6;
const cell_amount_of_word_en_for_cardinal_1st = 'G1';
const column_word_en_for_cardinal_1st = 8;
const cell_amount_of_word_en_for_george_1st = 'I1';
const column_word_en_for_george_1st = 10;
const cell_amount_of_word_en_for_irregular_1st = 'K1';
const column_word_en_for_irregular_1st = 12;
const row_start_of_word_list = 3;
const defaultWord_jp_cardinal_1st = 'カーディナル';
const defaultWord_jp_george_1st = 'ジョージ';
const defaultWord_en_cardinal_1st = 'Cardinal';
const defaultWord_en_george_1st = 'George';
const bearerTokenTwitterAccountJp = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const accessTokenTwitterAccountJp = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const accessTokenSecretTwitterAccountJp = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const apiKeyTwitterAccountJp = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const apiKeySecretTwitterAccountJp = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const bearerTokenTwitterAccountEn = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const accessTokenTwitterAccountEn = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const accessTokenSecretTwitterAccountEn = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const apiKeyTwitterAccountEn = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const apiKeySecretTwitterAccountEn = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

lib.gs:

function getStrRepeatedToMark(repeatStr, repeatNumberToMark=15){
return repeatStr.repeat(repeatNumberToMark);
};

ツイートを投稿する部分#

今回作ったTwitter用のBotに、ツイートを投稿するためにAPI keyやOAuthで認証する設定の部分は、以下の記事でまとめています。

投稿する内容を決定する部分#

今回の本題に入ります。

本ツールに使用するスプレッドシートの中身はこんな感じになっています。

処理の流れとしては、以下になります。

  1. ツイートに使う単語を選ぶ
  2. 実際にツイートする文言を決定する。
  3. ツイートする。

以下に実際に解説します。

1. ツイートに使う単語を選ぶ#

ツイートに使う単語を選ぶ流れは以下のとおりです。

  1. 日本語アカウントか英語アカウントのどちらで呟くかを決める。
  2. 「カーディナル」な部分と「ジョージ」な部分を、まとめて選ぶか、それぞれ分けて選ぶかを決める。
  3. まとめて選ぶ場合は、イレギュラー列から単語を選んで返す。
  4. それぞれ分けて選ぶ場合は、「カーディナル」列および「ジョージ」列からそれぞれ単語を選んで返す。

2.で、まとめて選ぶ場合になると、3.で「秋道チョウジ」や「枕草子」が選ばれます。

それぞれ分けて選ぶ場合になると、3.は行われず、4.で「カーニバル」と「お家」や「グーを出す」と「上司」などが返り値として選ばれます。

2. 実際にツイートする文言を決定する。#

ツイートに使う単語が選ばれたら、実際にどのように呟くかどうかを整形する処理になります。

日本語の場合だと「・」を間に入れて、英語の場合だとスペースを入れる仕様としています。

3. ツイートする。#

実際にツイートする文言が決まったため、ツイートします。引数が”JP”か”EN”かで日本語アカウントか英語アカウントで呟くかどうかを区別しています。

実際につぶやきに成功すると、以下のようになります。

トリガーを設置する#

ツイートを自動で行うために、GAS上でトリガーを設定します。

以下の画面でトリガーが発火する時間を設定できます。

おしまい#

リサちゃん avatar
リサちゃん
やった〜、「カーディナル・ジョージ」って呟くbotが出来た〜!
135ml avatar
135ml
おお、良かったな・・・。

ちなみに、カーディナル・ジョージのアカウントのURLは、ここです。Cardinal GeorgeのアカウントのURLは、ここです。

以上になります!

記事を共有

この記事が役に立ったなら、ぜひ他の人と共有してください!

【GAS、Google Spreadsheet】Twitterにランダムなツイートを投稿するBotを作る
https://endorphinbath.com/posts/gas-twitter-bot-random-tweet/
著者
kinkinbeer135ml
公開日
2021-12-30
ライセンス
CC BY-NC-SA 4.0
関連記事 スマート
1
【GAS、Google Spreadsheet】TwitterのBotを作成するために認証を行う。
Code Googleスプレッドシートを利用したGASから実行するTwitterのBotを作りました。今回は、そのTwitterに投稿するための認証周りの設定に関する紹介記事になります。
2
【GAS】Googleカレンダーに曜日を指定してスケジュールを登録するスプレッドシートの構築
Code Google Apps Scriptを使い、スプレッドシートからGoogleカレンダーに曜日指定でスケジュールを追加するシステムを作りました。繰り返し入力する版と個別に入力する版があります。
3
【GAS、Google Spreadsheet】Googleドキュメントで日記を付けるために毎日Docファイルを作ってくれるスクリプトです
Code GoogleDriveにあるファイルを毎日決まった時間にコピーしてくれるスクリプトを書きました。日記をつける場合に毎回ファイルをコピーしてレイアウトを変えて・・・といった作業を効率化してしまいましょう!
4
【GAS、Google Spreadsheet】Googleカレンダーにスケジュールを登録するためのスクリプトです
Code GoogleCalendarにスケジュールを登録する時にSpreadsheetから入力できるスクリプトを造りました。カレンダーからも連続した予定を入力できますが、それを何度も繰り返すのも大変なので、このツールで時短してみて下さい。
5
【Google Apps Script】自分がGASで使うIDとかトークンを1つのシートで管理するライブラリを作ろうとしたけど、断念した話
Code Google Apps Scriptで使うフォルダIDやスプレッドシートIDなどを一括管理するライブラリをスプレッドシート上で作ろうと思ったのですが、とある理由により頓挫しました。貴方もお気を付け下さい。
ランダム記事 ランダム
Profile Image of the Author
kinkinbeer135ml
SIerをやめて、プログラミングを勉強しています。※Amazonアソシエイトに参加しています。
お知らせ
私のブログへようこそ!これはサンプルのお知らせです。
音楽
カバー

音楽

再生中なし

0:00 0:00
歌詞なし
カテゴリ
タグ
サイト統計
記事
287
カテゴリー
8
タグ
93
総文字数
486,174
運用日数
0
最終活動
0 日前

目次