はてブRSSの要素を取得するRubyプログラム
はてブ(はてなブックマーク)のRSSを取得して、要素を抽出するRubyプログラムを作ってみました。
はてブの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(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"
テスト
# 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のブックマーク 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 "", "------" }