新しいfollowerやremoveした人のBioやFollowing/Followersを表示する

以前新しいfollowerやremoveした人を表示するRubyスクリプトというものを書いた。
しかし最近よくわからない外人のfollowerが増えてきていることもあり、名前だけ表示するだけではなくBioやFollowing, Followers数などがわかれば、いちいちその人のページを確認する必要もないよね、ということでBioとFollwing, Followers数も表示するRubyスクリプトを書いた。


follotter.rb

require 'rubygems'
require 'mechanize'
require 'kconv'

class Follotter
  def initialize(user, pass)
    @agent = WWW::Mechanize.new
    @agent.user_agent_alias = 'Mac Safari'
    @agent.max_history = 1
    login_form = @agent.get('http://twitter.com/').forms.action('https://twitter.com/sessions').first
    login_form['username_or_email'] = user
    login_form['password'] = pass
    @agent.submit(login_form)
  end

  def get_followers(command = 'check')
    case command
    when 'update'
      File.open("followers.txt", "w") do |io|
        (1..lastpage_index).each do |n|
          io.puts((@agent.get("http://twitter.com/followers?page=#{n}")/"a.url").map {|i| i.inner_text})
        end
      end
    when 'check'
      followers = (1..lastpage_index).inject([]) {|memo, n|
        memo + (@agent.get("http://twitter.com/followers?page=#{n}")/"a.url").map {|fr| fr.inner_text}
      }
      older_followers = File.open("followers.txt", "r") {|io| io.readlines}.map {|l| l.chomp}
      (older_followers - followers).each do |i|
        info = get_followers_info(i)
        puts "-----------------------------------------"
        puts "#{i} has removed you."
        puts "Bio: #{info[0]}"
        #sjisでしか表示できない場合は info[0].tosjis のようにする
        puts "Following : Followers = #{info[1]} : #{info[2]}"
      end
      (followers - older_followers).each do |i|
        info = get_followers_info(i)
        puts "-----------------------------------------"
        puts "#{i} has started to follow you."
        puts "Bio: #{info[0]}"
        #sjisでしか表示できない場合は info[0].tosjis のようにする
        puts "Following : Followers = #{info[1]} : #{info[2]}"
      end
    else
      raise 'invalid arguments'
    end
  end

  private
  def lastpage_index
    num = (@agent.get('http://twitter.com/followers')/:h2).inner_text.match(/\d+/).to_s.to_i
    puts "Your #{num} Followers"
    (num%20 != 0) ? (num/20 + 1) : (num/20)
  end

  def get_followers_info(follower_name)
    user_page = @agent.get("http://twitter.com/#{follower_name}")
    bio = (user_page/"span.bio").inner_text
    following = (user_page/"ul.stats"/"li[1]/span").inner_text
    followers = (user_page/"ul.stats"/"li[2]/span").inner_text
    [bio, following, followers]
  end
end

if __FILE__ == $0
  user = 'username' #自分のusernameに変更
  pass = 'password' #自分のpasswordに変更
  Follotter.new(user, pass).get_followers(*ARGV)
end

基本的には前回自分が書いたものを、ujihisaが添削してくれた記事を大いに参考にしながら修正するようにした。
今まであまりArray#mapやArray#injectを使ってこなかったのだが、このように使えるんだと大変勉強になった。
あともう一つ気をつけたところは要素を指定する際にXPathをあまり使わないようにしたこと。
XPathは簡単に要素指定できるのですごく便利である一方、ページ構造に強く依存しているためページ構造の変化に弱いという欠点がある。そのあたりをタグ名やクラス名を指定するようにしてみた。
formも単純に何番目のフォームとするのではなくて、action名を元に決めることにした。(前回からログインフォームの位置が変わっていたりしたので)


Bioを表示する際に、Windowsコマンドプロンプトを使っている人は、日本語を表示するために出力する文字の文字コードsjisにしなくてはならない点に注意してください。
UTF-8で表示できる場合はプログラム冒頭の require 'kconv' は不要。


実行方法は前回と同じで

ruby follotter.rb update

で、比較対象となるfollowerをfollowers.txtに書き込み、

ruby follotter.rb

で、followers.txtとの差分を出力する。実行結果はたとえば下のようになる。


実行日時ごとにfollowersファイルを作成して、follower履歴みたいのをわかるようにした方がいいかなあ、と思いつつもそこまではやれてないです。