読者です 読者をやめる 読者になる 読者になる

HTMLからRSSフィードを検出するRubyスクリプトを作ってみた。

ruby

ブラウザのアドレスバーに表示されるRSSフィードはどんな仕組みで検出しているのか疑問に思ったので調べてみました。

HTMLのHEADタグの中にのような形式でRSSフィードを指定すると、ブラウザが検出してくれるらしい。

詳しくは以下を参照。
RSS Autodiscovery Board


nokogiriを使えば実装できそうだったので、Rubyで実装してみました。


・RSSAutoDiscovery.rb

# encoding: utf-8                                                                                                                                      
require 'rubygems'
require 'nokogiri'

class RSSAutoDiscovery
    # xpath for feed
    RSS_xpath  = '//link[@rel="alternate"][@type="application/rss+xml"]'
    Atom_xpath = '//link[@rel="alternate"][@type="application/atom+xml"]'

    public
    def RSSAutoDiscovery.discover(html)

        # create html from string
        html = Nokogiri::HTML(html)

        # discover rss and atom
        @rss_feeds = discoverFeed(html, RSS_xpath)
        @atom_feeds = discoverFeed(html, Atom_xpath)

        return @rss_feeds + @atom_feeds
    end

    private
    def RSSAutoDiscovery.discoverFeed(html, feed_xpath)

        # feed list
        @feeds = Array.new

        # discover feed
        html.xpath(feed_xpath).each do |link|

            # get feed title and url
            @feed_title = link.attribute("title")
            @feed_url = link.attribute("href")

            # push hash to array
            @feeds << {"title" => @feed_title, "url" => @feed_url}
        end

        return @feeds
    end
end


・Sample.rb

# encoding: utf-8                                                                                                                                      
require 'rubygems'
require 'open-uri'
require "./RSSAutoDiscovery.rb"

# HTMLを取得する
def getHTML(url)
    html = nil

    begin
        html = open(url).read
    rescue OpenURI::HTTPError => ex
        if ex.io.status[0] == "304" then
            warn ex.message
        else
            raise ex
        end
    end

    return html
end


# メイン
urls = Array.new
urls << "http://d.hatena.ne.jp/yukihir0/"
urls << "http://www.lifehacker.jp/"

urls.each do |url|
    html = getHTML(url)

    unless html.nil?
        feeds = RSSAutoDiscovery.discover(html)

        puts "--- #{url} ---"
        feeds.each do |feed|
            puts "#{feed['title']} : #{feed['url']}"
        end
        (url.length+8).times {
            print "-"
        }
        puts "\n\n"
    else
        puts "can't get html"
    end

end

・実行結果

%ruby Sample.rb

--- http://d.hatena.ne.jp/yukihir0/ ---
RSS : http://d.hatena.ne.jp/yukihir0/rss
RSS 2.0 : http://d.hatena.ne.jp/yukihir0/rss2
---------------------------------------

--- http://www.lifehacker.jp/ ---
RSS 2.0 : http://www.lifehacker.jp/index.xml
Atom : http://www.lifehacker.jp/atom.xml
---------------------------------


いくつかサイトをピックアップして試したみたけど、type属性にrssじゃなくてatomを指定しているページがあったので両方対応させてみました。

仕様上正しいのかどうかは不明です。

nokogiri便利ー。