名古屋の人たちが参加しているオフ会や勉強会を捕捉する(1)

日々、TLを見ると周りの人達はいろんなイベントに参加していたりする。
自分もそれらのイベントに参加したいが、事前に開催情報を知ることが出来ていないので参加のしようがない。


といっても方法がまったく無いわけではなくて、勉強会であれば、IT勉強会カレンダー( http://bit.ly/qpPgrS ) とかを見るという方法はある。しかし、IT勉強会カレンダーは大量にイベントがありすぎて、自分の場合どれに参加すれば良いか決められないし、そもそも日々開催されているイベントのうちどれだけが網羅されているのか良く分からず、これに頼って良いのかか不安。能動的にチェックするというのも面倒くさくて、自分の場合は続かない。
# Googleカレンダーを使っている人は自分のにインポートすれば良いかもだけど、あの量をそのままインポートしても辛いものがある


そこで、自分のTLや、自分で作成したlistの中で発言されたイベントの情報を収集するスクリプトを書いてみたので紹介する。

動作概要

指定したリストのTweetsから、指定したキーワードのいずれかを含む Tweet を抽出し指定したディレクトリへテキストファイル形式で書き出す。
ファイルは日毎で作成される。

コード ( collect.rb )

# -*- coding: euc-jp -*-
require 'rubygems'
require 'pp'
# for Twitter
require 'twitter'
# for Userstream
require 'userstream'

require 'kconv'

CONSUMER_KEY = "<取得した値を設定>"
CONSUMER_SECRET = "<取得した値を設定>"
OAUTH_TOKEN = "<取得した値を設定>"
OAUTH_TOKEN_SECRET = "<取得した値を設定>"

LIST_NAME = "<自分で作ったリスト名を設定>"

FILE_OUT_PATH_BASE = "./"

KEYWORDS = ["オフ","勉強会"]

# @brief 指定されたリストのメンバを返す
# @param [in] list_name 取得するリスト名 ( String )
# @param [in,out]
# @param [out]
# @retval 所属するユーザ screen_nameリスト( Array <String> )
# @note Twitterクラスの初期化(認証)が完了した後で呼び出すこと
def get_list_members(list_name)
  if list_name == ""
    return nil
  end

  list_names_arr = Array.new()

  cursor_num = -1
  loop do
    result = Twitter.list_members(list_name, {:cursor => cursor_num})
    result[:users].each{ |elem|
      list_names_arr << elem.screen_name
    }
    cursor_num = result[:next_cursor]

    break if cursor_num == 0
  end

  return list_names_arr
end

class TweetAnalyzer

  def initialize()
  end

  # @brief 文字列がキーワード群を含むか判定する
  # @param [in] str 検索対象文字列 ( String )
  # @param [in] keyword_arr キーワード群 ( String )
  # @param [in,out]
  # @param [out]
  # @retval true いずれかのキーワードが含まれた
  # @retval false どのキーワードも含まれない
  # @note Twitterクラスの初期化(認証)が完了した後で呼び出すこと
  def is_contain_keyword(str, keyword_arr)
    keyword_arr.each{ |keyword|
      if str.index(keyword) != nil
        return true
      end
    }

    return false
  end

  # @brief 与えられたテキストを処理する
  # @param [in] tweet_text tweetテキスト ( String )
  # @param [in,out]
  # @param [out]
  # @retval 無し
  # @note Twitterクラスの初期化(認証)が完了した後で呼び出すこと
  def process_tweet(tweet_text)
    # キーワードを含んでいるようであれば保持
    if is_contain_keyword(tweet_text, KEYWORDS) == true
      ofile_path = FILE_OUT_PATH_BASE + Time.now().strftime("%Y-%m-%d") + ".txt"
      `echo "#{tweet_text.tosjis()}" >> #{ofile_path}`
    end
  end
end

# ログイン(1)
Twitter.configure do |config|
  config.consumer_key = CONSUMER_KEY
  config.consumer_secret = CONSUMER_SECRET
  config.oauth_token = OAUTH_TOKEN
  config.oauth_token_secret = OAUTH_TOKEN_SECRET
end

# ログイン(2)
consumer = OAuth::Consumer.new(
  CONSUMER_KEY,
  CONSUMER_SECRET,
  {:site => 'https://userstream.twitter.com/'}
)
access_token = OAuth::AccessToken.new(
  consumer,
  OAUTH_TOKEN,
  OAUTH_TOKEN_SECRET
)

list_members = get_list_members(LIST_NAME)

analyzer = TweetAnalyzer.new()

userstream = Userstream.new(consumer, access_token)
userstream.user do |status|
  begin
    # 指定されたリストに含まれるユーザの発言のみ抽出
    if status[:text] && ( list_members == nil || list_members.include?(status[:user][:screen_name]))
      analyzer.process_tweet(status[:text].toeuc())
    end
  rescue => e
    p e
  end
end

使い方

必要なgemをインストールする

gem install userstream twitter


1.APIの認証キーを設定する。
まず、以下の4つを取得する。取得方法はコチラ ( http://bit.ly/qDrJtM ) を参照。
取得できたらコードの同名の定数に設定。

  • ・CONSUMER_KEY
  • ・CONSUMER_SECRET
  • ・OAUTH_TOKEN
  • ・OAUTH_TOKEN_SECRET


2.キーワードを集めるリスト名をLIST_NAME定数に設定する。
リストを指定しない(TLのtweets全てを指定)する場合は空文字("")を設定。上のコードでは私が作ったnagoyaリスト ( http://twitter.com/#!/list/ryo_grid/nagoya ) になっている。
# ちなみに、このリストは名古屋近辺在住(とおぼしき)方々のリストで、コレ ( http://bit.ly/nCM7Pp ) を使って芋づる方式で作成。ソーシャルハックおいしいです^p^


3.フィルタをかけるキーワードをKEYWORDS定数に設定する。
上のコードでは"オフ"と"勉強会"の2つが設定されている。
他にも足したい方はどうぞ。


4.あとは以下で起動するだけ。

ruby collect.rb

バックグラウンドで実行するならこんな感じ?

nohup ruby collect.rb 2>&1 > /dev/null &

自分は以下に作成して、Webからアクセスできるようにしている。


http://ryogrid.net/~ryo/dist/nagoya_evt_tweets/


能動的にチェックしようとするとうまくいかないので、自分は作成されたファイルのURLをケイタイ(スマートフォン)にメールするようcronを設定している。

% crontab -l
55 23 * * * /bin/sh /home/ryo/cron_script/mail_evt_txt.sh

% less /home/ryo/cron_script/mail_evt_txt.sh
#! /bin/sh

echo "http://ryogrid.net/~ryo/dist/nagoya_evt_tweets/"`date +%Y-%m-%d.txt` | mail -s "nagoya_evt_tweets "`date +%Y-%m-%d` xxxxxxxxxxxxxxxxx@xxx.xxx -c ""

これから

Tweetの選別方法が単純すぎるのでもう少し賢くするつもり。
例えば、"オフ"というキーワードを設定した場合、"オフィス"とか"オフライン"なんてのも引っかかってしまう。これはあんまり。
ひとまず、正規表現でも使うのかな。


あと、Tweet全文はいらないのでキーワードだけ抜き出してカウント数でランキングするとかしたい。
これをやるためには、形態素解析とか必要な気がするけどRubyで出来るのだろうか。
複数文字列から一致するキーワードを抽出することができれば形態素解析しないで済むだろうが、処理コストはリーズナブルな範囲に収まるだろうか。Rubyだとアルゴリズムが賢くても厳しいかな。

先に言っておく

Twitterクライアントでフィルタかければ良いじゃんとか思った人もいるかもしれない。
しかし、それだと自発的にチェックしないとダメで続かないのである。
その点、今回のスクリプトを使えば、メールで強制的に読ませるとかできるので良い。