2008-02-17
■[はてな][Ruby]はてなスターの星の数を数える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が行っている。だいたい、こんな処理をしている。
- Hatena.Star.EntryLoader.getStarEntries
- Hatena.Star.EntryLoader.receiveStarEntries
- Hatena.Star.Entry.bindStarEntry
はてなスターの情報をJSONPで取得するURIの入出力
次に、実際にリクエストを投げてみたりして、はてなスターの情報をJSONPで取得できる http://s.hatena.ne.jp/entries.json の入出力を調べてみた。このURIの入出力については既に調べられた方がいます(下記のエントリ)が、HatenaStar.js のコードを読むと、追記できる部分もあった*1ので、あらためて書いてみます。
何かつまらなかったのでHatenaStar.jsが利用しているAPIを調べてみた。 - つれずれなるままに…
入力(HTTPリクエストのパラメーター)
出力(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を解析する処理は、下記で公開されているRuby用JSONパーサーを利用させて頂きました。ソースコードをファイル"simple-json.rb"に保存して利用しています。
- 23 http://d.hatena.ne.jp/keyword/はてなスターカウントAPI?kid=217860
- 22 http://d.hatena.ne.jp/rubynews/20080226/1204040969
- 16 http://webos-goodies.jp/archives/51071565.html
- 15 http://d.hatena.ne.jp/jt_noSke/20101230/1293720512
- 9 http://b.hatena.ne.jp/entry/d.hatena.ne.jp/NAT_programming/20080217/1203259026
- 7 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja-JP-mac:official&hs=V2X&q=はてなスター json&btnG=検索&lr=lang_ja
- 6 http://www.google.co.jp/search?q=はてな スター 数 取得&lr=lang_ja&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&client=firefox
- 5 http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/NAT_programming/20080217/1203259026
- 5 http://htn.to/ji4fRF
- 5 http://zerobase.grouptube.jp/diary/user/dotimpact/5107