YAMAGUCHI::weblog

土足で窓から失礼いたします。今日からあなたの息子になります。 当年とって92歳、下町の発明王、エジソンです。

Twitter日本語ハッシュタグだっていうんでSpreadSheetにログ保存しようぜ

はじめに

こんにちは、Python界の情弱です。最近はGoogle Apps Scriptが便利すぎるだろってことでちょっと諸用からTwitterの発言を集めてきてGoogle DocsのSpreadSheetにログを残すっていう感じのGASを書いてみました。JavaScriptも情弱すぎてやべえ...

こんな感じ

とりあえずハッシュタグ「#しみずかわ」で引っ張ってきた発言をひたすら保存してます。5分ごとにcron回してます。いじりたいと思った奇特な方は「ファイル > コピーを作成...」でどうぞ。

スクリプト

JSONの扱いは普通にJS書くときと違ってGASの中にあるUtilities.jsonParse()使ったほうがよさげ。

var TWITTER_BASE_URL = "http://search.twitter.com/search.json?q=";

// テスト用関数 -> 単独実行できます
function test() {
  var query = Browser.inputBox("Query");
  var results = fetchSearchResult(query);
  if (results) {
    appendTweetsToBottom(results);
  }
}

// cron用関数
function batchDumpTweets() {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = doc.getSheetByName("config");
  var query = sheet.getRange("B1").getValue();
  var results = fetchSearchResult(query);
  if (results) {
    appendTweetsToBottom(results);
  }
}

// Twitter Search APIへのリクエスト
function fetchSearchResult(query) {
  var encodedQuery = encodeURIComponent(query);
  var last_id = getLastId().toString();
  var url = TWITTER_BASE_URL + encodedQuery + "&rpp=100";
  if (last_id !== "-1") {
    url += "&since_id=" + last_id;
  }
  
  var response = UrlFetchApp.fetch(url);
  var results = null;
  if (response.getResponseCode() == 200) {
    var data = Utilities.jsonParse(response.getContentText());
    results = data["results"];
  }
  return results
}

// tweetsシートに検索結果を追記
function appendTweetsToBottom(tweets) {
  // tweetsシートの取得と最後尾IDの取得
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = doc.getSheetByName("tweets");
  var start_row = sheet.getLastRow() + 1;
  var last_id = getLastId().toString();
  
  // データ初期化
  var tweet_data = new Array();
  var cur_last_id = "0";
  
  // 取得したtweetを昇順にし、シートに書き込む形式にする
  tweets.sort(function(t1, t2) {
    return t1.id - t2.id;
  });
  
  for (var i in tweets) {
    var t = new Array();
    t.push(tweets[i].id,
           tweets[i].created_at,
           tweets[i].from_user,
           tweets[i].text);
    tweet_data.push(t);
    
    if (tweets[i].id.toString() > cur_last_id) {
      cur_last_id = tweets[i].id.toString();
    }
  }
  
  // tweetsシートに結果書き込み
  if (tweet_data.length > 0) {
    sheet.getRange(start_row, 1, tweet_data.length, tweet_data[0].length).setValues(tweet_data);

    // configシートの最後尾IDを更新
    if (last_id !== "-1" && (last_id < cur_last_id || last_id.length < cur_last_id.length)) {
      updateLastId(cur_last_id);
    }
  }
}

// configシートからIDを取得
function getLastId() {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = doc.getSheetByName("config");
  return sheet.getRange("B2").getValue();
}

// configシートのIDを上書き
function updateLastId(id) {
  var doc = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = doc.getSheetByName("config");
  sheet.getRange(2,2).setValue(id);
}

こんな感じ

ほらほら、「#しみずかわ」のtweetが大漁だよ。
f:id:ymotongpoo:20110715001104p:image

設定

cronで回したい関数をトリガー設定するだけです。スクリプトエディターの「トリガー」メニューから「現在のスクリプトのトリガー...」を選んで、
f:id:ymotongpoo:20110715001105p:image
「時間主導型」で動かしたい関数を選択するだけです。
f:id:ymotongpoo:20110715001516p:image

注意

SpreadSheetの行数には上限があるんで、そこんところ気をつけてください。
あと、このスクリプトの場合、原因がSpreadSheetかJavaScriptかそれとも両方かまだ見極めてないですが*1、セルに最後尾IDの値を入れたときに数字になってしまって、それが2^53を超えてしまってるんで大変という問題があります。なんとか回避しないといけないんですが... (今は文字列比較にしてますが、それでもsetValue()したあとセルの中で数字になってしまっています)

*1:たぶんSpreadSheet側のAPIの仕様。要確認。