Rubyでどう書く?:Rubyで特定URLの画像パス一覧を表示する

牧野裕之(KBMJ)
2008-05-30 14:36:01
  • このエントリーをはてなブックマークに追加

問題

 あるWebサイトをブックマークする際に、そのURLで表示されている画像の一覧から1つの画像を選択した上でブックマークしたいという要望を受け取ったとします。

 そこで、画像選択用のサムネイル表示のために、URL上に表示されている画像URLの一覧を配列として提供したいのですが、どのようなメソッドで提供すべきでしょうか?

 ここでは、ごく簡単ではありますが正規表現を使って画像URL一覧の取得を行ってみます。

仕様

  • 画像ファイルは「jpg, jpeg, gif, bmp, png」を取得する
  • URIスキームが「http」の場合のみ画像を取得する

回答例

require 'open-uri'
require 'resolv-replace'
require 'timeout'

class ImageUrl
  # 特定のURL上の画像パス一覧を取得する
  def self.get_image_urls(url)
    begin
      timeout(1) {
        begin
          uri = URI(url)
          if uri.scheme == "http" #httpsでは画像を取ってこない。
            tmp_images = uri.read.scan(/img.+src=[\"|\']?([\-_\.\!\~\*\'\(\)a-zA-Z0-9\;\/\?\:@&=\$\,\%\#]+\.(jpg|jpeg|png|gif|bmp))/i)
            images = []
            tmp_images.each { |img| images << URI.join(url, img[0]) }
            images.uniq
          end
        rescue => exception
          case exception
          when OpenURI::HTTPError # 404エラー
            puts "ページが見つかりません。"
          when URI::InvalidURIError # 入力エラー
            puts "URLが入力されていません。"
            # 他にもエラークラス別に処理を加えるなら以下のように追加
            # when エラークラス名
            #   エラー時の処理
          else # その他のエラー
            puts exception.to_s + "(#{exception.class})"
          end
        end
      }
    rescue TimeoutError
      # Timeout時の処理
      puts "読み込みに時間がかかりすぎたため、処理を終了しました。"
    end
  end
end

image_urls = ImageUrl.get_image_urls(ARGV[0])
puts image_urls

 試しにYahoo!JAPANから画像URL一覧を取得してみましょう。

ruby image_url.rb "http://yahoo.co.jp/"

 本記事を執筆時点では、実行結果は以下のようになります。

http://k.yimg.jp/images/clear.gif
http://k.yimg.jp/images/top/sp/cgrade/logo.gif
http://k.yimg.jp/images/top/searchbox/s_p.gif
http://k.yimg.jp/images/new2.gif
http://k.yimg.jp/images/top/calender2.gif
http://k.yimg.jp/images/top/sp/cgrade/icon_point.gif
http://k.yimg.jp/images/top/sp/cgrade/icon_login.gif
http://k.yimg.jp/images/premium/top2/cam_searchpoint_50x50_01.gif
http://k.yimg.jp/images/top/sp/qr.gif
http://k.yimg.jp/images/top/sp/cgrade/dot.gif
http://k.yimg.jp/images/mlb/y_top/matsuzaka_02.jpg

解説

 本サンプルプログラムでは、以下の順序で処理を実行しています。

1.URL読み込み

 ruby1.8.2からは、URI.parse("http://...")をURI("http://...")と書けるようになっているため、後者の書き方に合わせました。

2.URIスキーム判定

 URIスキームがhttpの場合のみ画像を抽出したいので、判定文を加えました。open-uriはSSLで自己証明証を使用しているURLにはアクセスできないため、残念ながらhttpsは該当URIスキームからは外しました。

3.読み込んだソースから正規表現で画像URI抽出

 正規表現により正しい画像URLのみを抽出します。

4.重複削除し、値を返す

 URLによっては同じ画像を何度も呼んでいる場合があるので、Array#uniqで画像パスの重複したものを削除した後に、値を返します。

 また、本プログラム作成時に以下の二点に気を付けました。

1.正規表現にオプション「i」をつける

 読み込むソースによっては、タグ・属性・拡張子が大文字で記述されている可能性があるので、大文字小文字を無視するオプションが必要になります。

2.エラー(URL未入力、404、タイムアウト)への対処

 例として、URLの入力が無かった場合、404レスポンスが返ってきた場合、タイムアウトの場合の三通りについて、個別の対応ができるように記述しました。ここでは、TimeoutErrorはStandardErrorのサブクラスではないため、rescueの際にはクラス名を明記しておく必要があることに注意してください。

 個人的な感想ですが、以下の点について工夫を加えれば本プログラムが改善できそうだと思いました。

1.画像URL取得に用いる正規表現

 よりスマートな正規表現に書き換えれば、理解しやすく変更も加えやすくなると思います(正直なところ、あまりきれいな正規表現では無いと思っています。申し訳ありません)。

2.CSS(スタイルシート)に記述されている画像URLの取得

 本サンプルプログラムでは、CSSに記述されている画像URLの取得までは網羅していません。

3.エラー処理

 本プログラムではエラーの種類による分岐までに留めていて、実際の処理に関しては記述しませんでした。要件によって、処理を書き加えるとよいでしょう。

4.httpsへの対応

 httpsのページであっても画像が取得できるように変えたほうが、本プログラムをより多くのページで利用できるでしょう。net/httpsを用いれば実現可能なようです。

最後に――

 簡単な問題・例文ではありましたが、いかがでしたでしょうか。

 本記事では、あるWebサイト上で用いられている画像のURL一覧を取得するという題目でご説明させていただきました。拙作ではありますが、少しでも皆さんのRubyへの理解の助けになれば幸いです。

 もっと良い書き方・方法があれば、コメントやbuilderブログなどで教えていただきたいと思います。

  • 新着記事
  • 特集
  • ブログ