はてなスターの星の数を数えるRubyスクリプトを書いてみた

ちょっとやりたいことがあって、エントリに付けられたはてなスターの数を数えるRubyスクリプトを書いてみようと思った。はてなスターカウントAPIというのもあるけど、これはブログに付けられた☆の総数を数えるので、エントリごとの☆の数を数えるのには使えない。
そこで、まずはてなスターの処理を行う、下記のスクリプトを読んでみることにした。

http://s.hatena.ne.jp/js/HatenaStar.js

HatenaStar.jsの はてなスターの情報をJSONPで取得する処理

HatenaStar.jsは、大きく2つの部分から構成されている。

Ten
クラス、XmlHttpRequest、イベント処理、DOMなど、基礎となる機能を提供するクラス(Ten.*)の定義
Hatena
はてなスターの処理を行なうクラス(Hatena.Star.*)の定義

このうち、はてなスターの情報をはてなのサーバから取ってくる処理は、Hatena.Star.EntryLoaderが行っている。だいたい、こんな処理をしている。

  1. Hatena.Star.EntryLoader.getStarEntries
  2. Hatena.Star.EntryLoader.receiveStarEntries
    • JSONPのコールバックで呼ばれる。エントリに対応するHatena.Star.Entryにはてなスターの情報(JSON形式)を渡す
  3. Hatena.Star.Entry.bindStarEntry
    • 渡されたはてなスターの情報を参照し、対応するオブジェクトを作ったり、変数に格納したりする

はてなスターの情報をJSONPで取得するURIの入出力

次に、実際にリクエストを投げてみたりして、はてなスターの情報をJSONPで取得できる http://s.hatena.ne.jp/entries.json の入出力を調べてみた。このURIの入出力については既に調べられた方がいます(下記のエントリ)が、HatenaStar.js のコードを読むと、追記できる部分もあった*1ので、あらためて書いてみます。

http://d.hatena.ne.jp/Yuichirou/20070802/1186070862

入力(HTTPリクエストのパラメーター)
uri
はてなスターの情報を取得するエントリのURI。複数指定可能
callback
JSONPでコールバックする関数名。省略可能
出力(HTTPレスポンスのコンテンツ)
{
  /* 閲覧者を識別するためのトークン。閲覧者ごとに異なり、閲覧者が同じなら別のページでも同じ値が返る */
  "rks":"****************************************",

  "can_comment" : 0, /* そのサイトでコメントが書けるなら 1 */
  "entries" : [ /* 各エントリについての情報が入ったオブジェクトの配列 */
    { /* ☆の個数が15個未満の場合 */
      "stars" : [ /* ☆の情報 */
        {
          "name" : "***", /* ☆をつけたユーザー名 */
          "quote" : "***" /* ☆をつけたユーザーが引用した箇所 */
        },
        { "name" : "***", "quote" : "***" },
        /* ☆の個数だけ繰り返し */
      ],
      "can_comment" : 0, /* そのエントリーにコメントが書けるなら 1 */
      "uri" : "http://***" /* エントリーのURI */
    },
    { /* ☆の個数が15個以上の場合 */
      "stars" : [
        { "name" : "***", "quote" : "***" }, /* 最初につけられた☆の情報 */
        25,                 /* 間に含まれる☆の数(全体 - 2) */
        { "name" : "***", "quote" : "***" }, /* 最後につけられた☆の情報 */
      ],
      "can_comment" : 0, /* そのエントリーにコメントが書けるなら 1 */
      "uri" : "http://***" /* エントリーのURI */
    },
    /* 以下、エントリの数だけ繰り返し */
  ]
}

入力パラメーターcallbackを指定した場合は、上記を引数にしてコールバック関数を呼ぶJavaScriptコードが返ってきます。

はてなスターの☆の数を数えるRubyスクリプト

はてなスターの情報をJSONPで取得するURIの入出力形式が分かったので、これを利用して、はてなスターの☆の数を数えるRubyスクリプトを書いてみました。URIを標準入力から入力すると、そのURIにつけられた☆の数を標準出力にします。

require 'uri'
require 'net/http'
require 'simple-json'

Net::HTTP.version_1_2

class HatenaStar
  ADDRESS = 's.hatena.ne.jp'
  ENTRIES_PATH = '/entries.json'
  
  def self.getNumberOfStars(uri)
    entries = getEntriesJson(uri)['entries']
    raise 'no entries' if entries.size == 0
    raise 'unexpected number of entries' if entries.size > 1
    number = 0
    entries[0]['stars'].each do |e|
      if e.is_a? Integer
        number += e
      else
        number += 1
      end
    end
    number
  end

  def self.getEntriesJson(uri)
    res = Net::HTTP.get(ADDRESS,
                        ENTRIES_PATH + '?uri=' + URI.encode(uri))
    JsonParser.new.parse(res)
  end
end

uri = gets.chomp
puts HatenaStar.getNumberOfStars(uri)

JSONを解析する処理は、下記で公開されているRubyJSONパーサーを利用させて頂きました。ソースコードをファイル"simple-json.rb"に保存して利用しています。
Ruby 用 JSON パーサーを更新、 JSON への変換も追加 - WebOS Goodies

*1:具体的には入力パラメーターcallbackと、出力のquoteプロパティ。以前は無かったのかな?