Help us understand the problem. What is going on with this article?

Google Apps ScriptでTwitter botを作ってみた

More than 3 years have passed since last update.

Google Apps Scriptだけで、Twitterのbotを作れないかなと思案してたら、作れてしまったので、記載

どんなbotか

なんてことはない、好きなサイトの更新してる記事をランダムでつぶやいてくれるbot

こういうbotが欲しいと思った経緯としては、
- feedlyで記事の更新を全て取り込んでも、結局一括で削除しちゃって読まない
- Twitterを見ている時に、ふとつぶやかれている記事なら読んじゃう
- じゃあ、Twitterで適当に記事が目につく状況作れば、読んじゃうじゃないか

実際のスクリプト

今回作ったものは、「RSSをスクレイピングして、スプレッドシートに記事のリンクをExportして、そのリンクを定期的につぶやく」という仕組みです。

この仕組みは3つの役割から構成されています。
1.スプレッドシートのデータを削除する
2.RSSをスクレイピングし、スプレッドシートにExportする
3.スプレッドシートの値をランダムに取得し、それをツイートする

それでは、それぞれについて説明します。

1.スプレッドシートのデータを削除する

こちらは、すでにスプレッドシートに記事のURLがある場合、それを削除するためのスクリプトです。
これを用意する意図としては、過去の記事URLを全て削除することで、スプレッドシートには常に最新記事のURLが存在する状態を作り出すためです。

実際のクエリ

clear.gs
function clear() {
    # シートを扱う準備
    var myActiveSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
    var myActiveSheet = myActiveSpreadSheet.getSheets()[0];

    # 取得したurlを全てクリアする
    myActiveSheet.clear();
}

2.RSSをスクレイピングし、スプレッドシートにExportする

こちらは、RSSをスクレイピングし、スプレッドシートに取得してきた記事URLをExportするためのスクリプトです。

実際のクエリ

scraping.gs
function scraiping() {
  # シートを扱う準備
  var myActiveSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var myActiveSheet = myActiveSpreadSheet.getSheets()[0];

  # RSSからscraipingでurlを取得。今回は、筆者がヨーロッパのサッカーが好きなので、ゲキサカのRSS( http://web.gekisaka.jp/rsspage )を利用させていただいております。
  var response = UrlFetchApp.fetch("http://web.gekisaka.jp/feed?category=foreign");
  var myRegexp = /<guid isPermaLink=\"true\">([\s\S]*?)<\/guid>/gi;
  var match = response.getContentText().match(myRegexp);

  # 不必要な文字を置換し、ドライブシートに貼り付け
  for(var i in match) {
    var amount = match[i]
    amount = amount.replace("<guid isPermaLink=\"true\">", "");
    amount = amount.replace("<\/guid>", "");
    myActiveSheet.getRange(myActiveSheet.getLastRow()+1, 1).setValue(amount);
  }
}

3.スプレッドシートの値をランダムに取得し、それをツイートする

こちらは、スプレッドシート内の記事URLを取得し、それをランダムに取得し、定期的にツイートするためのスクリプトです。

実際のクエリ

tweet.gs
var CONSUMER_KEY = 'Your_CONSUMER_KEY';                    # 取得したCONSUMER_KEYを入力してください
var CONSUMER_SECRET = 'Your_CONSUMER_SECRET';                 # 取得したCONSUMER_SECRETを入力してください

/**
 * Authorizes and makes a request to the Twitter API.
 */
function run(text) {                         
  var service = getService();
  if (service.hasAccess()) {
    var url = 'https://api.twitter.com/1.1/statuses/update.json';
    var payload = {
      status: text                           
    };
    payload = Object.keys(payload).map(function(key) {
      return encodeRfc3986(key) + '=' + encodeRfc3986(payload[key]);
    }).join('&');
    var response = service.fetch(url, {
      method: 'post',
      payload: payload,
      escaping: false
    });
    var result = JSON.parse(response.getContentText());
    Logger.log(JSON.stringify(result, null, 2));
  } else {
    var authorizationUrl = service.authorize();
    Logger.log('Open the following URL and re-run the script: %s',
        authorizationUrl);
  }
}

/**
 * Encodes a string using the RFC 3986 spec.
 */
function encodeRfc3986(str) {
  return encodeURIComponent(str).replace(/[!'()]/g, function(char) {
    return escape(char);
  }).replace(/\*/g, "%2A");
}

/**
 * Reset the authorization state, so that it can be re-tested.
 */
function reset() {
  var service = getService();
  service.reset();
}

/**
 * Configures the service.
 */
function getService() {
  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(CONSUMER_KEY)
      .setConsumerSecret(CONSUMER_SECRET)

      // 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());
}

/**
 * Handles the OAuth2 callback.
 */
function authCallback(request) {
  var service = getService();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success!');
  } else {
    return HtmlService.createHtmlOutput('Denied');
  }
}

function bot_news_link() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var sheet = ss.getSheets()[0];
 var cell = sheet.getRange("A1");

 all_urls = cell.offset(0, 0, sheet.getLastRow()-1);
 var urls = all_urls.getValues();

 # ランダム関数で取得。コンテンツのあるRowの最後までを範囲に指定
 var rand = Math.ceil(Math.random() * sheet.getLastRow() - 1);

 # ランダムurl
 var url = urls[rand][0];

 run("あなたにオススメの記事は" + url + "なんだな!!");
}

実際の運用

筆者の場合、以下のようなクローンスケジュールで設定している
1.削除は、朝の7 ~ 8時で1回行う
2.記事のURL取得は、朝の8 ~ 9時で1回行う
3.記事のツイートは、2時間おきに1回行う

参考記事

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away