2017.4.4
2017.4.17

AmazonベストセラーのRSSを読み込んでJSONファイルに出力する

RubyでRSSを読み込んでJSONファイルに出力する方法です。

読み込むのはAmazonベストセラーのRSSです。毎回RSSを読み込むと時間がかかるのでDBやファイルとしてローカルに保存するのが普通だと思いますが、今回はJSONファイルに読み込んだデータを格納します。

流れとしてはopen-uriを使って指定したURLへアクセスし、読み込んだXMLをNokogiriで解析します。

また、「https」でアクセスする場合、上記だけでは証明書の検証に失敗してファイルを読み込めないようなので、opensslの「ssl_verify_mode」を切り替えて実行します。詳しくはこちら([Ruby] open-uri の HTTPS リクエストで certificate verify failed | mofu犬blog)を参照。

目次

  • Nokogiriのインストール
  • コード
  • 実際に出力されるデータ
  • 参考リンク

Nokogiriのインストール

opne-uriとopnesslは標準ライブラリに含まれているので、Nokogiriだけインストールします。

gem install nokogiri

コード

以下は、Amazonベストセラーの「バイクヘルメット」と「バイクウェア、プロテクション」の2つのRSSを読み込んで、それぞれを別のJSONファイルとして出力するコードです。


require 'nokogiri'
require 'open-uri'
require 'openssl'
require 'json'

rss_list = [
    {:category => 'helm', :url => 'https://www.amazon.co.jp/gp/rss/bestsellers/automotive/2045145051/ref=zg_bs_2045145051_rsslink'},		# バイクヘルメット
    {:category => 'wear', :url => 'https://www.amazon.co.jp/gp/rss/bestsellers/automotive/2045156051/ref=zg_bs_2045156051_rsslink'},		# バイクウェア、プロテクション
]

rss_list.each do |rss|
    # RSSの読み込み
    rss_xml = Nokogiri::XML(open(rss[:url], :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE).read)

    data = {}

    channel = rss_xml.xpath('/rss/channel')
    data[:title] = channel.xpath('title').text
    data[:link] = channel.xpath('link').text
    data[:public_date] = channel.xpath('pubDate').text
    data[:last_build_date] = channel.xpath('lastBuildDate').text

    products = []
    rss_xml.xpath('//item').each do |item|
        product = {}
        content = item.xpath('description').text

        # 商品URL
        product[:url] = item.xpath('link').text.strip

        # 商品名
        product[:name] = ''
        matches = content.match(/<span class\=\"riRssTitle\"><a href\=\".*?\">(.*?)<\/a><\/span>/);
        if (matches && matches.size > 1)
            product[:name] = matches[1]
        end

        # 投稿者
        product[:contributor] = ''
        matches = content.match(/<span class\=\"riRssContributor\">(.*?)<\/span>/);
        if (matches && matches.size > 1)
            product[:contributor] = matches[1].strip
        end

        # レビュースコア、件数
        product[:review_score_url] = ''
        product[:review_count] = ''
        matches = content.match(/<span class\=\"riRssContributor\">.*?<\/span>.*?<img src\=\"(.*?)\".*?\/>(.*?)<br \/>/);
        if (matches && matches.size > 2)
            product[:review_score_url] = matches[1]
            product[:review_count] = matches[2]
        end

        # 元々の価格
        product[:price_org] = ''
        matches = content.match(/<strike>(.*?)<\/strike>/);
        if (matches && matches.size > 1)
            product[:price_org] = matches[1]
        end

        # 実際の価格
        product[:price_act] = ''
        matches = content.match(/<font.*?><b>(.*?)<\/b><\/font>/);
        if (matches && matches.size > 1)
            product[:price_act] = matches[1]
        end

        # イメージURL
        matches = content.match(/<a class\=\"url\".*?<img src=\"(.*?)\"/)
        if(matches && matches.size > 1)
            product[:image_url] = matches[1]
        end

        products.push(product)
    end

    data[:products] = products

    # JSONファイルの作成
    file_path = "/var/www/example/bestseller/" + rss[:category] + ".json"
    File.open(file_path, "w") do |file|
      file.puts(data.to_json(:root => false))
    end		
end

実際に出力されるデータ

上記のコードを実行すると以下のようなJSONファイル(helm.json)が作成されます。


{
    "title": "Amazon.co.jp: 車&バイク > ヘルメットのベストセラー",
    "link": "https://www.amazon.co.jp/gp/bestsellers/automotive/2045145051/ref=pd_zg_rss_ts_auto_2045145051_c",
    "public_date": "Tue, 4 Apr 2017 05:48:58 GMT",
    "last_build_date": "Tue, 4 Apr 2017 05:48:58 GMT",
    "products": [{
            "url": "https://www.amazon.co.jp/%E3%83%AA%E3%83%BC%E3%83%89%E5%B7%A5%E6%A5%AD-%E3%83%90%E3%82%A4%E3%82%AF%E3%83%98%E3%83%AB%E3%83%A1%E3%83%83%E3%83%88-%E3%83%9E%E3%83%83%E3%83%88%E3%83%96%E3%83%A9%E3%83%83%E3%82%AF-61~62cm%E6%9C%AA%E6%BA%80-RE41/dp/B00LAQ76R8/ref=pd_zg_rss_ts_auto_2045145051_1",
            "name": "リード工業 バイクヘルメット ハーフ シールド付 マットブラック LLサイズ 61~62cm未満 RE41",
            "contributor": "LEAD",
            "review_score_url": "https://images-fe.ssl-images-amazon.com/images/G/09/detail/stars-4-0._CB192252995_.gif",
            "review_count": "(56)",
            "price_org": "¥ 6,804",
            "price_act": "¥ 3,790",
            "image_url": "https://images-fe.ssl-images-amazon.com/images/I/41AUvMsye-L._SL160_.jpg"
        },
        ...
    ]
}

参考リンク

Ruby】関連記事