Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Ruby TIPS

Ruby TIPS

RSSを扱うには? ― 標準rssライブラリ利用して天気予報を表示する

2017年2月15日

Rubyに標準搭載されているrssライブラリを使って、Webサイトで提供されているRSS/Atomフィードを処理する方法を説明する。例として天気予報情報のRSSフィードを使う。

ローグ・インターナショナル 羽山 博
  • このエントリーをはてなブックマークに追加

 RubyにはRSSを取り扱うためのrssライブラリが標準添付されており、これを使えば、Webサイトで提供されているRSSやAtomのデータが取得できる。今回は、一例としてYahoo!天気・災害で提供されているRSSフィード(=RSSファイル)を取得し、天気予報を表示してみる。また、ブロックの中で現在の繰り返し回数を知る方法についても紹介する。

rssライブラリを利用して天気予報を取得する

 RSSやAtomはWebサイトのコンテンツや更新情報などを配信するための文書フォーマットである。例えば、今回のプログラムで利用するYahoo!天気・災害のRSSフィードの内容は以下のようなものである。文書の構造がXML形式で記述されていることが分かる。

XML
<rss version="2.0">
<channel>
  <title>Yahoo!天気・災害 - 東京(東京)の天気</title>
    ……省略……
  <item>
    <title>【 10日(金) 東京(東京) 】 曇り - 9℃/2℃ - Yahoo!天気・災害</title>
    <description>曇り - 9℃/2℃</description>
    <pubDate>Fri, 10 Feb 2017 17:00:00 +0900</pubDate>
  </item>
  <item>
    <title>【 11日(土) 東京(東京) 】 晴時々曇 - 9℃/0℃ - Yahoo!天気・災害</title>
    <description>晴時々曇 - 9℃/0℃</description>
    <pubDate>Fri, 10 Feb 2017 17:00:00 +0900</pubDate>
  </item>
    ……省略……
</channel>
</rss>
リスト1.1 RSSフィードの例

 Webブラウザーで「https://rss-weather.yahoo.co.jp/rss/days/4410.xml」にアクセスすると、このようなRSSフィードが取得できる。ここでは、特徴をつかむためにごく一部分だけを掲載してある。なお、「http://weather.yahoo.co.jp/weather/rss/」にアクセスすれば、各地のRSSフィードを取得するためのリンク一覧が表示される。

 天気予報を取得するには、<channel>要素の中にある<item>要素の中の<title>要素の内容を取り出せばいい。<item>要素は複数個あることに注意しよう。それが分かればすぐにプログラムが作成できる(リスト1.2)。

sample001.rb
require "rss"
url = "https://rss-weather.yahoo.co.jp/rss/days/4410.xml"
rss = RSS::Parser.parse(url)
rss.channel.items.each do|x|
  puts x.title
end
リスト1.2 天気予報を取得して表示するプログラム

RSS::ParserクラスのparseメソッドはURLの文字列を解析するメソッドで、フィードがRSS 2.0形式であればRSS::Rssオブジェクトへの参照を返す。ここでは変数rssを使ってRSS::Rssオブジェクトが利用できるようにしている。channelメソッドを利用すれば<channel>要素が取得できる。さらにitemsメソッドを利用すれば<channel>要素の中にある複数の<item>要素を扱える。その各要素のtitleメソッドを使って<channel>要素を取得する。

 RSS::Parserクラスのparseメソッドでは、URL文字列として指定されたフィードがRSS 1.0形式であればRSS::RDFオブジェクトへの参照を返し、RSS 0.9xまたは2.0形式であればRSS::Rssオブジェクトへの参照を返す。また、Atom 1.0形式であれば、RSS::Atom::Feedオブジェクトへの参照を返す。

 この例では、フィードがRSS 2.0形式なので、変数rssにはRSS::Rssオブジェクトへの参照が代入される。RSSフィード内の各要素を取得するためには、要素名と同じ名前のメソッドが利用できる。例えば、<channel>要素を取得するためにはchannelメソッドが使える。

 また、複数の<item>要素を取得するためにはitemsメソッドを使う(メソッド名が、XML要素の複数形の名前となっている)。以下、どのようにして、天気予報の文字列を取得するか、RSSフィードとコードを対応させて図解しておこう。

図1.1 RSSフィードの構造と各要素を取り出すためのメソッドの対応

天気予報の文字列は、<channel>要素の下の<item>要素(複数あるのでitemsで参照できる)の下の<title>要素の中にある。複数の要素のうち1つを利用するにはインデックスを指定すればよい。また、ブロックなどの繰り返し処理を利用して全ての要素を利用することもできる。

 このプログラムでは、rss.channel.itemsで参照される複数の<item>要素の各要素をeachメソッドで1つずつ取り出し、ブロックの中の変数xに渡す。ブロックの中では、titleメソッドを使って<title>要素の値を取り出す。<title>要素のように、子要素がない場合は文字列が返されるので、そのままputsメソッドで表示できる。

 実行結果は以下の通りである。

コンソール
$ ruby sample001.rb
【 10日(金) 東京(東京) 】 曇り - 9℃/2℃ - Yahoo!天気・災害
【 11日(土) 東京(東京) 】 晴時々曇 - 9℃/0℃ - Yahoo!天気・災害
【 12日(日) 東京(東京) 】 晴時々曇 - 10℃/1℃ - Yahoo!天気・災害
【 13日(月) 東京(東京) 】 晴時々曇 - 9℃/1℃ - Yahoo!天気・災害
【 14日(火) 東京(東京) 】 晴れ - 10℃/1℃ - Yahoo!天気・災害
【 15日(水) 東京(東京) 】 晴れ - 10℃/2℃ - Yahoo!天気・災害
【 16日(木) 東京(東京) 】 晴れ - 12℃/2℃ - Yahoo!天気・災害
【 17日(金) 東京(東京) 】 晴時々曇 - 18℃/4℃ - Yahoo!天気・災害
【 23区西部 】注意報があります - Yahoo!天気・災害
【 23区東部 】注意報があります - Yahoo!天気・災害
【 多摩北部 】注意報があります - Yahoo!天気・災害
【 多摩西部 】注意報があります - Yahoo!天気・災害
【 多摩南部 】注意報があります - Yahoo!天気・災害
$
実行例1.1 天気予報を表示するプログラムの実行例

複数の<item>要素の下にある<title>要素に含まれる文字列が全て表示された。8日間の天気予報と注意報が表示されている。

実行時に「certificate verify failed (OpenSSL::SSL::SSLError)」というエラーが表示されて実行できない場合は、HTTPSアクセスに必要なSSL証明書が見付からないのが原因の可能性がある。この場合、「http://curl.haxx.se/ca/cacert.pem」などからcacert.pemファイルを取得し、そのファイルへのパスをset SSL_CERT_FILE=/path/to/your/new/cacert.pemコマンドなどにより環境変数に設定すればよい。

ブロックの中で繰り返し回数を数える

 実行例1.1では、8日間の天気予報だけでなく、注意報も表示された。注意報が不要であれば、複数の<item>要素の最初から8つの<title>要素の文字列だけを表示すればよい。ところが、eachメソッドでブロックに渡されるのは各<item>要素を表すオブジェクトだけなので、何個目の要素であるかは分からない。繰り返しの回数を記憶しておくための変数を用意してもいいが、エレガントとは言いづらい。こういうときには、each_with_indexメソッドまたはeach.with_indexメソッドを使うとよい(リスト1.2)。

sample002.rb
require "rss"
url = "https://rss-weather.yahoo.co.jp/rss/days/4410.xml"
rss = RSS::Parser.parse(url)
rss.channel.items.each_with_index do|x,i|
  puts x.title
  if i > 6 then break end
end
リスト1.2 each_with_indexメソッドを使って繰り返し回数を数える

each_with_indexメソッドでは、ブロックに各要素とインデックスが渡される。ここでは変数iに繰り返し回数が渡され、その値が6を超えたら繰り返しを終了するようにしている。変数iの初期値は0であることに注意。

 実行例は以下の通り。

コンソール
$ ruby sample002.rb 
【 10日(金) 東京(東京) 】 曇り - 9℃/2℃ - Yahoo!天気・災害
【 11日(土) 東京(東京) 】 晴時々曇 - 9℃/0℃ - Yahoo!天気・災害
【 12日(日) 東京(東京) 】 晴時々曇 - 10℃/1℃ - Yahoo!天気・災害
【 13日(月) 東京(東京) 】 晴時々曇 - 9℃/1℃ - Yahoo!天気・災害
【 14日(火) 東京(東京) 】 晴れ - 10℃/1℃ - Yahoo!天気・災害
【 15日(水) 東京(東京) 】 晴れ - 10℃/2℃ - Yahoo!天気・災害
【 16日(木) 東京(東京) 】 晴れ - 12℃/2℃ - Yahoo!天気・災害
【 17日(金) 東京(東京) 】 晴時々曇 - 18℃/4℃ - Yahoo!天気・災害
$ 
実行例1.2 8日間の天気予報だけを表示する

変数iの値が6を超えたら(7になったら)繰り返しを終了するので、8日間の天気予報だけが表示されるようになった。

 なお、each.with_indexメソッドでは、引数にオフセットが指定できる。例えば、リスト1.1のeach_with_indexeach.with_index(1)に書き換えると、iの値が1から始まるので7日間の天気予報が表示されることになる。

まとめ

 今回は、RSS::Parserクラスのparseメソッドを使ってRSSやAtomのフィードを取得する方法と、XMLファイルの要素を利用する方法を紹介した。また、ブロックの中で何回目の繰り返しであるかを知るためのeach_with_indexメソッドやeach.with_indexメソッドについても触れた。

処理対象:rssライブラリ カテゴリ:ライブラリ > ファイルフォーマット
API:RSS::Rssクラス|RSS::Parserクラス|RSS::RDFクラス|RSS::Atom::Feedクラス カテゴリ:rssライブラリ
処理対象:オブジェクト.eachメソッド|オブジェクト.each_with_indexメソッド|オブジェクト.each.with_indexメソッド カテゴリ:文法 > 制御構造 > 繰り返し
API:each_with_indexメソッド カテゴリ:Enumerableモジュール
API:with_indexメソッド カテゴリ:Enumeratorクラス

※以下では、本稿の前後を合わせて5回分(第14回~第18回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Ruby TIPS
14. クラスのメソッドをオーバーライドするには?

継承先クラスの新メソッドで元クラスの既存メソッドをオーバーライドして異なる機能に置き換える方法と、新メソッド内から既存メソッドを呼び出すことで既存機能に新機能を追加する方法を説明する。

Ruby TIPS
15. 範囲式や正規表現を使うには? ― 穴埋め問題と株価診断プログラムを作る

範囲式は条件式の中で使うとちょっと面白い動作をする。範囲式を使って簡単な穴埋め問題や株価診断プログラムを作ってみよう。

Ruby TIPS
16. 【現在、表示中】≫ RSSを扱うには? ― 標準rssライブラリ利用して天気予報を表示する

Rubyに標準搭載されているrssライブラリを使って、Webサイトで提供されているRSS/Atomフィードを処理する方法を説明する。例として天気予報情報のRSSフィードを使う。

Ruby TIPS
17. 数値/文字列/配列/範囲式/正規表現の比較を行うには?

Rubyプログラミングでは「等しいかどうか」を調べるための比較はどう行うのか? 比較を行える演算子やメソッドを使って、さまざまな比較を試してみる。

Ruby TIPS
18. 演算子を再定義するには?

Rubyではクラスの二項演算子や単項プラス/マイナス演算子を定義(もしくは再定義)できる。その方法を基礎から説明し、実用的な使い方の例を示す。

サイトからのお知らせ

Twitterでつぶやこう!