はてブRSSの要素を取得するRubyプログラム

はてブはてなブックマーク)のRSSを取得して、要素を抽出するRubyプログラムを作ってみました。

はてブRSS

まずはてブRSSを構成する要素を確認します。


はてブ

  • タイトル (title)
  • リンク (link)
  • 説明 (description)


あとは各ブックマークの

  • タイトル (title)
  • リンク (link)
  • 説明 (description)
  • ブクマした時間 (date)
  • 追加したユーザ名 (creator)
  • タグ (tags)


他に色々要素がありますが、上記の要素を組み合わせると大抵出来上がるモノなので、コアとなる要素はこれぐらいでしょうか*1

データ設計

ここからコーディング。まずはデータ設計です。

はてブの情報を格納するクラスを定義します。

# Hatena Bookmark RSS Data Class
class HatebRSS
        attr_accessor :title, :link, :description, :items
        def initialize
                @title = @link = @description = nil
                @items = Array.new
        end
end

ここでitemsはブクマしたそれぞれのサイト情報を格納する配列とします。


インスタンス変数を定義するとgetterとかsetterとかのアクセスメソッドの定義が面倒ですが、

Rubyは内部的に定義してくれる「attr_***」って修飾子があって便利です。

インタプリタ実行時にこの修飾子が付けられたインスタンス変数へのアクセスメソッドが自動で定義されます(きっと…)。

getterのみの定義はattr_reader、setterのみの定義はattr_writerで両方を定義したい場合はattr_accessorです。


話がそれました。次に、その配列の要素となるブクマの情報を格納するクラスを定義します。

# Hatena Bookmark Data Class
class HatebItem
        attr_accessor :title, :link, :description, :date, :creator, :tags
        def initialize
                @title = @link = @description = @date = @creator = nil
                @tags = Array.new
        end
end

tagsが唯一複数出現する可能性があるので配列にします。

データ取得と構築

あとは、RSSを取得しHatebItemオブジェクトを構築して、それをHatebRSSのitems配列に詰め込んでいくだけです。

ここがメインの処理です。

require 'open-uri'
require 'rss/1.0'
require 'rss/dublincore'

# Open XML(RSS) and Make RSS Object
bookmark = "http://b.hatena.ne.jp/jkondo/rss" #jkondoのはてブRSS
rss = open(bookmark){ |file| RSS::Parser.parse(file.read) }

# Set Output Encoding
rss.output_encoding = "EUC-JP"

# Set HatebRSS instance field
hateb = HatebRSS.new
hateb.title = rss.channel.title
hateb.link = rss.channel.link
hateb.description = rss.channel.description

# Set HatebItem instance field
rss.items.each{ |item|
        hi = HatebItem.new
        hi.title = item.title
        hi.link = item.link
        hi.description = item.description
        hi.date = item.dc_date
        hi.creator = item.dc_creator
        item.dc_subjects.each{ |tag|
                hi.tags << tag.content
        }
        hateb.items << hi
}

open-uriでシンプルにRSSの取得。

open(bookmark){ |file| ... }


はてブはブクマのタグがdublincoreのsubject要素なので、読込むライブラリに注意します。

require 'rss/1.0'
require 'rss/dublincore'


RSSの各要素へのアクセスにはRSS Parser標準ライブラリを利用します。

RSS::Parser.parse(file.read)

デフォルトではparseの第二引数はtrueがセットされ、RSSのバリデーション(構文チェック)が実行されます。

怪しいRSSでも取得したい場合はバリデーションをfalseにすると良いです。

少しでも高速にしたい場合も役に立つのかも?(パフォーマンス比較をしていないので分かりませんが…)

RSS::Parser.parse(file.read, false)


私の作業環境に依存して、出力文字エンコードEUC-JPにしています。

rss.output_encoding = "EUC-JP"


これではてブRSSの内容を全てコントロールできます。

テスト

試しに、はてブRSSの全要素を出力してみます。

# Test output
puts hateb.title
puts hateb.link
puts hateb.description
puts "------"
hateb.items.each { |hi|
        puts hi.title
        puts hi.link
        puts hi.description
        puts hi.date
        puts hi.creator
        hi.tags.each{ |tag|
                print tag, ", "
        }
        puts "", "------"
}

jkondoのブクマRSSの結果はこうなります。

jkondoのブックマーク
http://b.hatena.ne.jp/jkondo/
jkondoのブックマーク

------
NHKスペシャル|グーグル革命の衝撃 〜あなたの人生を“検索”が変える〜
http://www.nhk.or.jp/special/onair/070121.html

2007-01-14T17:29:12+09:00
jkondo

------
The Apple iPhone - Engadget
http://www.engadget.com/2007/01/09/the-apple-iphone/

2007-01-10T04:24:38+09:00
jkondo

------
CYCLINGTIME.com : 神宮外苑でクリテリウム開催 学連70周年記念行事
http://www.cyclingtime.com/modules/ctnews/view.php?p=3784

2006-12-28T01:09:07+09:00
jkondo
これはすごい, 
------

(略)

意外とコメントもタグも付けてないブクマが多いんですね…。


ということで、今回ははてブRSSの各要素にフルアクセスするRubyプログラムを作ってみましたというエントリでした。

全プログラムを提示しておきます。

全プログラム

require 'open-uri'
require 'rss/1.0'
require 'rss/dublincore'

# Hatena Bookmark RSS Data Class
class HatebRSS
        attr_accessor :title, :link, :description, :items
        def initialize
                @title = @link = @description = nil
                @items = Array.new
        end
end

# Hatena Bookmark Data Class
class HatebItem
        attr_accessor :title, :link, :description, :date, :creator, :tags
        def initialize
                @title = @link = @description = @date = @creator = nil
                @tags = Array.new
        end
end

# Open XML(RSS) and Make RSS Object
bookmark = "http://b.hatena.ne.jp/jkondo/rss"
rss = open(bookmark){ |file| RSS::Parser.parse(file.read, false) }

# Set Output Encoding
rss.output_encoding = "EUC-JP"

hateb = HatebRSS.new
hateb.title = rss.channel.title
hateb.link = rss.channel.link
hateb.description = rss.channel.description

# Set HatebItem instance field
rss.items.each{ |item|
        hi = HatebItem.new
        hi.title = item.title
        hi.link = item.link
        hi.description = item.description
        hi.date = item.dc_date
        hi.creator = item.dc_creator
        item.dc_subjects.each{ |tag|
                hi.tags << tag.content
        }
        hateb.items << hi
}

# Test output
puts hateb.title
puts hateb.link
puts hateb.description
puts "------"
hateb.items.each { |hi|
        puts hi.title
        puts hi.link
        puts hi.description
        puts hi.date
        puts hi.creator
        hi.tags.each{ |tag|
                print tag, ", "
        }
        puts "", "------"
}

*1:ブックマーク数というのがchannel要素の中にあるんですが、RubyRSS Parserライブラリではアクセスできないようなのでペンディング