RSSを取得して自社サイトに埋め込みたい？それ、簡単ですよ。Railsならね。


Hey Say、RSS使ってるかい？

普段、FeedlyとかFeedlyとかFeedlyとかでRSSを読んでいるエンジニア諸君、**「自分でRSSリーダーを作ろうと思ったことはないかね？」。**僕はありません。

でもお仕事でこういう内容を実装することはあると思います。

ということで本日は、Rails(Ruby)で使えるParserやらgemやらを通じてココらへんの処理について見ていきます。

## そもそもRSSって一種類じゃないよね
僕らが普段何気に使っているRSS(ここでは広義にサイトの更新情報をフィードで提供するものとする)ですが、実はこれには規格が幾つか存在します。

- RSS 1.0
- RSS 2.0
- Atom

RSSは他にもいくつか0.9x系も存在するみたいだけど、とりあえず上記の3つを抑えておけば問題ないと思われる。（多分ね

### RSS1.0のサンプル
[RDF Site Summary (RSS) 1.0 日本語訳](http://www.futomi.com/lecture/japanese/rss10.html)より拝借。

実際に欲しいフィード情報は、`rdf>item`内に含まれている。実際に取れそうな情報は、`title`、`link`、`description`辺りか。

```
<?xml version="1.0"?>

<rdf:RDF 
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://purl.org/rss/1.0/"
>

  <channel rdf:about="http://www.xml.com/xml/news.rss">
    <title>XML.com</title>
    <link>http://xml.com/pub</link>
    <description>
      XML.com features a rich mix of information and services 
      for the XML community.
    </description>

    <image rdf:resource="http://xml.com/universal/images/xml_tiny.gif" />

    <items>
      <rdf:Seq>
        <rdf:li resource="http://xml.com/pub/2000/08/09/xslt/xslt.html" />
        <rdf:li resource="http://xml.com/pub/2000/08/09/rdfdb/index.html" />
      </rdf:Seq>
    </items>

    <textinput rdf:resource="http://search.xml.com" />

  </channel>
  
  <image rdf:about="http://xml.com/universal/images/xml_tiny.gif">
    <title>XML.com</title>
    <link>http://www.xml.com</link>
    <url>http://xml.com/universal/images/xml_tiny.gif</url>
  </image>
  
  <item rdf:about="http://xml.com/pub/2000/08/09/xslt/xslt.html">
    <title>Processing Inclusions with XSLT</title>
    <link>http://xml.com/pub/2000/08/09/xslt/xslt.html</link>
    <description>
     Processing document inclusions with general XML tools can be 
     problematic. This article proposes a way of preserving inclusion 
     information through SAX-based processing.
    </description>
  </item>
  
  <item rdf:about="http://xml.com/pub/2000/08/09/rdfdb/index.html">
    <title>Putting RDF to Work</title>
    <link>http://xml.com/pub/2000/08/09/rdfdb/index.html</link>
    <description>
     Tool and API support for the Resource Description Framework 
     is slowly coming of age. Edd Dumbill takes a look at RDFDB, 
     one of the most exciting new RDF toolkits.
    </description>
  </item>

  <textinput rdf:about="http://search.xml.com">
    <title>Search XML.com</title>
    <description>Search XML.com's XML collection</description>
    <name>s</name>
    <link>http://search.xml.com</link>
  </textinput>

</rdf:RDF>
```

### RSS2.0のサンプル
[RSS 2.0 Specification 日本語訳](http://www.futomi.com/lecture/japanese/rss20.html)より拝借。

こちらは`rss>channel>item`内に含まれてる。実際に取れそうな情報は、`title`、`link`、`description`、`pubDate`あたり。

```
<?xml version="1.0"?>
<rss version="2.0">
   <channel>
      <title>Liftoff News</title>
      <link>http://liftoff.msfc.nasa.gov/</link>
      <description>Liftoff to Space Exploration.</description>
      <language>en-us</language>
      <pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
      <lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
      <generator>Weblog Editor 2.0</generator>
      <managingEditor>editor@example.com</managingEditor>
      <webMaster>webmaster@example.com</webMaster>
      <item>
         <title>Star City</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
         <description>How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's &lt;a href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm"&gt;Star City&lt;/a&gt;.</description>
         <pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
      </item>
      <item>
         <description>Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a &lt;a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm"&gt;partial eclipse of the Sun&lt;/a&gt; on Saturday, May 31st.</description>
         <pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
      </item>
      <item>
         <title>The Engine That Does More</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
         <description>Before man travels to Mars, NASA hopes to design new engines that will let us fly through the Solar System more quickly.  The proposed VASIMR engine would do that.</description>
         <pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid>
      </item>
      <item>
         <title>Astronauts' Dirty Laundry</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link>
         <description>Compared to earlier spacecraft, the International Space Station has many luxuries, but laundry facilities are not one of them.  Instead, astronauts have other options.</description>
         <pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid>
      </item>
   </channel>
</rss>
```

### Atomのサンプル
[RFC 4287 The Atom Syndication Format 日本語訳](http://www.futomi.com/lecture/japanese/rfc4287.html)より拝借。

こちらは`feed>entry`内に含まれてる。実際に取れそうな情報は、`title`、`link`、`summary`、`updated`あたり。

```
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Example Feed</title>
  <link href="http://example.org/"/>
  <updated>2003-12-13T18:30:02Z</updated>
  <author>
    <name>John Doe</name>
  </author>
  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>

  <entry>
    <title>Atom-Powered Robots Run Amok</title>
    <link href="http://example.org/2003/12/13/atom03"/>
    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
    <updated>2003-12-13T18:30:02Z</updated>
    <summary>Some text.</summary>
  </entry>
 
</feed>
```

それぞれ構造、使えそうな情報に差があるようだ。

## 実データを見てみる
ちょうどいいことに、[技術評論社](http://gihyo.jp/feed)が3パターンでの配信を行っているので、確認してみる。

[RSS1.0](http://gihyo.jp/feed/rss1)

[RSS2.0](http://gihyo.jp/feed/rss2)

[Atom](http://gihyo.jp/feed/atom)

まぁ大体上記のサンプルと同等の構造をとってますね。ここまではわかった。じゃあ本題に移ろう。

## 取得してパースしてみる
今回の目的は、「サクッとRSS(Atom)をパースする」ことである。便利なことに、`to_feed`で好きなfeedに変換でき(そうな)メソッドが定義されているようで、RSS1.0でもRSS2.0でもAtomでも、なんでもかんでもいい感じによろしくしてくれそうである。

ものは試しに、こんな感じのコードを走らせてみる。

```ruby
require 'rss'
 
sites = [
	"http://gihyo.jp/feed/rss1",
	"http://gihyo.jp/feed/rss2",
	"http://gihyo.jp/feed/atom"
]

sites.each do |site|
	rss = RSS::Parser.parse(site, false).to_feed('atom1.0')
	rss.items.each do |item|
		puts item.title
		puts item.link
		puts item.description
		puts
	end
end
```

**ダメだった。**

やっぱり定義されてないタグがあると、怒られるようだ。`to_feed`の意味よ。

自前で各仕様ごとにパラメータを分けた処理を書いてもいいのだが、やっぱり凡人の僕は楽をしたいもんである。車輪の再発明はしたくない。

## gemを試してみる
世の中そううまくはいかないことがわかったので、今度は`gem`を頼ってみる。

[Ruby Toolbox](https://www.ruby-toolbox.com/)とGoogle先生の情報を頼りに、[feedjira/feedjira](https://github.com/feedjira/feedjira)が良さそうだったので、試してみる。

gemを入れて、
```
gem 'feedjira'
```

ざっくりこんな感じで書いてみる。ソースが汚いのはご愛嬌。

```ruby
sites = [
    "http://gihyo.jp/feed/rss1",
    "http://gihyo.jp/feed/rss2",
    "http://gihyo.jp/feed/atom"
]

@list = []
sites.each do |site|
  rss = Feedjira::Feed.fetch_and_parse site
  rss.entries.each do |item|
    @list += [:title => item.title,
              :url => item.url,
              :summary => item.summary,
              :published => item.published.to_time.strftime("%Y-%m-%d %H:%M:%S")]
  end
end
@list
```

出力はこうなる。

```
[60]
0:  {
	"title": "第440回　LibreOffice Writerの日本語レイアウト ── Ubuntu Weekly Recipe"
	"url": "http://gihyo.jp/admin/serial/01/ubuntu-recipe/0440"
	"summary": "今回は，LibreOffice Writerを日本語ワードプロセッサとして使用する場合に，知っておきたい日本語レイアウトの設定について解説します。"
	"published": "2016-10-05 10:36:00"
	}-
1:  {
	"title": "第2回　トラブルに備える ── Javaでなぜ問題が起きるのか 〜システムをきちんと運用するための基礎知識"
	"url": "http://gihyo.jp/dev/serial/01/java-system-operation/0002"
	"summary": "本連載のテーマである「運用」は，システムがリリースしてからおこなわれるものです。では，開発者には運用の知識は必要ないでしょうか？"
	"published": "2016-10-05 10:20:00"
	}-
2:  {
	"title": "2016年10月5日 「最初の設計がダメすぎる」― systemdをめぐる終わりなき論争 ── Linux Daily Topics"
	"url": "http://gihyo.jp/admin/clip/01/linux_dt/201610/05"
	"summary": "Fedora，Ubuntu，Debianなど，いまやほとんどのメジャーなLinuxディストリビューションではsystemdが最初の起動処理システムとして採用されている。"
	"published": "2016-10-05 09:30:00"
	}-
(以下略)
```

RSS1.0、RSS2.0、Atom、同じプロパティ名で取得できました！

ソースを見ると、いい感じにラップしてくれていて、同じプロパティ名で取得できるようにしてくれているようです。これこれ、こういうのを待っていました。

表示だけならリアルタイムで出せばいいし、アプリ側に保存したいなら`find_or_create_by`みたいなんをいい感じに使えばいいんじゃないかな（まだ考えきれてない。

ご意見ご要望承ります。