Edited at

「ふぁぼった人に○○します!」の代替をGoogleAppsScriptで作った

More than 1 year has passed since last update.


ことのはじまり


  • TwitterAPIには「いいね!」した人をリストする機能が無い。

  • favstarとかもあるけど鍵付きの人は認識できないっぽいし一部有料。

  • むしろ「いいね!」でなくていい。欲しい人のTwitterアカウントが認識できればいい

  • 後で集計しやすい形が良い。.csvとか.xlsxとか.jsonとかとか…

  • Googleフォームなららくちん! ……でもTwitterID書いて投稿だったら簡単に偽装できる。

  • お、コレ行けるんじゃね?→[GAS] Google Apps Script でTwitter複数アカウントを使い分ける

  • GoogleAppsScriptならGoogleスプレッドシートに書きだせる!

というわけで作成した時にハマリ所をいくつかピックアップ。

詳しい使い方とかはココで紹介しませんので、各自でQiitってください。

「ええい御託は良い、はやくコードを写さんか!」って人はこちら


ハマり所とテクニック


コールバック

--- コード.gs ---

OAuth1.getCallbackUrl = function(scriptId) {
return Utilities.formatString(
'https://script.google.com/macros/s/%s/exec', scriptId);
}

// getServiceを上書き、スクリプトIDを手動設定に変更
twitter.getService = function() {

.setScriptId(PropertiesService.getScriptProperties().getProperty("OPENED_SCRIPT_ID"))

function doGet(e) {
if (e && e.parameter.oauth_verifier)

--- プロジェクトのプロパティ ---
OPENED_SCRIPT_ID : ********************************************************

一番悩んだところ。

デフォルトのプロパティではhttps://script.google.com/macros/s/スクリプトID/usercallbackに飛ぶのだが、このページに飛べるのはGoogleの認証ができる人のみ。

既に公開しているhttps://script.google.com/macros/s/スクリプトID/execにはGoogleの認証無しで見れるので、こっちに飛ばしてパラメータでコールバック前か後かを判断する。


認証前のページ

--- Oath.html ---

<a target="_top" href=<?=auth_url?>Twitterで認証</a>

クリックで飛ばす仕組み。

というのも、GAS上で表示するページは自動遷移ができない らしい。

metaタグやJavaScriptは書いても無効化されてしまう。セキュリティの関係上であろうし、コレは仕方ない。

(自動で別ページへ飛んで勝手にアヤシイサイトに入会させられて○○万円振り込め。 なんてよくある手口ですからね…)


スクリプトのプロパティ

--- コード.gs ---

var twitter = TwitterWebService.getInstance(
PropertiesService.getScriptProperties().getProperty("TWITTER_CONSUMER_KEY"),
PropertiesService.getScriptProperties().getProperty("TWITTER_CONSUMER_SECRET")
);

コード内でグローバル変数的なもの、マジックナンバーのようなものを格納できるGASの機能。

setPropertyもある。

QiitaやGitHubにコードを投稿した時にAWSのキーを消し忘れて大変なことに… って事が無くなる効果もある。

これからも積極的に使っていきたくなる機能。(グローバル変数の乱立には注意)

良い設定方法の記事無かったので書きました ↓

GoogleAppsScript スクリプトのプロパティの超簡単な使い方


HTMLの作成

--- コード.gs ---

var html_template = HtmlService.createTemplateFromFile('Comp');
html_template.name=user_info[3];
return html_template.evaluate();

--- Comp.html ---
<body>
<br /><?=name?>さんの受付が完了しました。</center>
</body>

HtmlService.createTemplateFromFile(拡張子なしファイル名)で生成したテンプレートファイルに値を突っ込むだけでHTMLから参照できる。

最後にテンプレートをevaluate()して、出てきたオブジェクトをreturnで返してあげればページがユーザーに表示される仕組み。

プログラムでゴニョゴニョしてできた値を簡単にHTMLとして表示できる。


実装

以下のライブラリを追加。

* TwitterWebService: MFE2ytR_vQqYfZ9VodecRE0qO0XQ_ydfb

* OAuth1: 1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s


コード.gs

'use strict';

// OAuth1認証用インスタンス
var twitter = TwitterWebService.getInstance(
PropertiesService.getScriptProperties().getProperty("TWITTER_CONSUMER_KEY"),
PropertiesService.getScriptProperties().getProperty("TWITTER_CONSUMER_SECRET")
);

// コールバック先をexecに変更
// デフォルトのusercallbackだとGoogleでの認証が必要になってしまう。
OAuth1.getCallbackUrl = function(scriptId) {
return Utilities.formatString(
'https://script.google.com/macros/s/%s/exec', scriptId);
}

// getServiceを上書き、スクリプトIDを手動設定に変更
twitter.getService = function() {
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(twitter.consumer_key)
.setConsumerSecret(twitter.consumer_secret)
.setCallbackFunction('exec')
.setPropertyStore(PropertiesService.getUserProperties())
.setScriptId(PropertiesService.getScriptProperties().getProperty("OPENED_SCRIPT_ID"))
}

// 認証時にURLを返すように変更
twitter.authorize = function() {
var service = this.getService();
if (service.hasAccess()) {
Logger.log('Already authorized');
} else {
var authorizationUrl = service.authorize();
return authorizationUrl;
}
}

// 認証をリセット
function reset() {
twitter.reset();
}

// 認証を行う
function authorize() {
return twitter.authorize();
}

// スプレッドシートに追記
function addSpreadSheet(value){
var id = PropertiesService.getScriptProperties().getProperty("SPREADSHEET_ID");
var spreadSheet = SpreadsheetApp.openById(id);
// 既に受付済の人は追記せずに帰る
var idlst = spreadSheet.getSheetValues(2,3,spreadSheet.getSheetByName('data').getMaxRows(),1);
for(var idv in idlst){
if(idlst[idv][0]==value[2]){
return;
}
}
spreadSheet.getSheetByName('data').appendRow(value);
}

// ユーザ情報を取得
function getUserInfo() {
var service = twitter.getService();
var response = service.fetch('https://api.twitter.com/1.1/account/verify_credentials.json');
var response_list = JSON.parse(response)

return [
Date(),
response_list["id_str"],
'@'+response_list["screen_name"],
response_list["name"],
]
}

function doGet(e) {
//test_code
// Comp.htmlをテストするときに此方を使う
// var html_template = HtmlService.createTemplateFromFile('Comp');
// html_template.name="テスト";
// return html_template.evaluate();
//test_code
// 初回、コールバック共に此方の関数を使う。
// OAuthのパラメタ有無で認証前か後を判断する
if (e && e.parameter.oauth_verifier){
twitter.authCallback(e);
var user_info = getUserInfo();
addSpreadSheet(user_info);
var html_template = HtmlService.createTemplateFromFile('Comp');
html_template.name=user_info[3]; //name
return html_template.evaluate();
}else{
reset();
var html_template = HtmlService.createTemplateFromFile('Oath');
html_template.auth_url=authorize();
return html_template.evaluate();
}
}


Oath.html

<!DOCTYPE html>

<html>
<head>
<base target="_top">
<title>「ふぁぼった人に○○します!」の代替をGoogleAppsScriptで作った</title>
</head>
<body><center>
<a target="_top" href=<?=auth_url?>Twitterで認証</a>
</center></body>
</html>


Comp.html

<!DOCTYPE html>

<html>
<head>
<base target="_top">
<title>認証完了</title>
</head>
<body>
<br /><?=name?>さんの受付が完了しました。</center>
</body>
</html>


プロジェクトのプロパティ -> スクリプトのプロパティ

TWITTER_CONSUMER_SECRET : **************************************************

TWITTER_CONSUMER_KEY : *************************
SPREADSHEET_ID : ********************************************
OPENED_SCRIPT_ID : ********************************************************



  • TWITTER_CONSUMER_SECRETTWITTER_CONSUMER_KEY の二つはTwitterのアプリキー



  • SPREADSHEET_IDは書き込み先スプレッドシートID


  • OPENED_SCRIPT_IDは、アプリを公開した時のID(一度Webに公開してキーをコピってから再公開)