Hatena::Diary

asotech このページをアンテナに追加 RSSフィード

2008-02-12

Rubyで楽天APIを使う

id:kajidaiさんが楽天市場非公式ウェブサービスRakuAPI*1をRubyから使うクラスを書いているが、本家版がなかったので書いてみた。


楽天商品検索APIのみ

require "rubygems"
require "rexml/document"
require "open-uri"

class RakutenItemSearch
  attr_reader :search_result

  def initialize(developer_id=nil, affiliate_id=nil)
    if developer_id
      @developer_id_query = "developerId=#{developer_id}"
    else
      puts "Developer IDをセットして下さい"
      exit(1)
    end

    @affiliate_id_query = "&affiliateId=#{affiliate_id}" if affiliate_id
    @request_url = "http://api.rakuten.co.jp/rws/1.11/rest"
  end

  def item_search(options=nil)
    # "type"としてkeyword、genreId、catalogCodeのいずれかを指定
    if ["keyword", "genreId", "catalogCode"].include?options[:type]
      options_query = "&#{options[:type]}=#{options[:query]}"
    else
      puts "keyword, genreId, catalogCodeのいずれかを\"type\"にセットして下さい"
      exit(1)
    end

    options_query += "&shopCode=#{options[:shopCode]}" if options[:shopCode]
    options_query += "&hits=#{options[:hits].to_s}" if options[:hits]
    options_query += "&page=#{options[:page].to_s}" if options[:page]
    options_query += "&minPrice=#{options[:minPrice].to_s}" if options[:minPrice]
    options_query += "&maxPrice=#{options[:maxPrice].to_s}" if options[:maxPrice]
    # 0:wide 1:narrow default:1
    options_query += "&field=#{options[:field].to_s}" if options[:field]
    # 0:PC 1:mobile default:0
    options_query += "&carrier=#{options[:carrier].to_s}" if options[:carrier]
    # イメージなしを含むか 0:含む 1:含まない default:0
    options_query += "&imageFlag=#{options[:imageFlag].to_s}" if options[:imageFlag]
    # orFlag 0:AND 1:OR default:0
    options_query += "&orFlag=#{options[:orFlag].to_s}" if options[:orFlag]
    options_query += "&NGKeyword=#{options[:NGKeyword]}" if options[:NGKeyword]
    options_query += "&genreInformationFlag=#{options[:genreInformationFlag]}" if options[:genreInformationFlag]
    # sorting type
    if options[:sort]
      if ["+affiliateRate","-affiliateRate","+reviewCount","-reviewCount",
        "+itemPrice","-itemPrice","+updateTimestamp","-updateTimestamp","random"].include?options[:sort]
        options_query += "&sort=#{options[:sort]}"
      else
        puts "ソート方式が不正"
        exit(1)
      end
    end

    options_query_encoded = URI.encode(options_query)
    @search_request = "#{@request_url}?#{@developer_id_query}#{@affiliate_id_query}#{options_query_encoded}
    &operation=ItemSearch&version=2007-10-25".gsub!("\n","").gsub!(" ","")

    xml_result = open(@search_request)
    @search_result = xml_to_array(xml_result)
    return @search_result
  end

  def xml_to_array(xml_result)
    doc = REXML::Document.new xml_result
    doc.elements.each("Response/header:Header/Status") do |status|
      unless status.text == "Success"
        puts "取得失敗"
        exit(1)
      end
    end

    result = Hash.new
    doc.elements.each("Response/Body/*") do |ele|
      result[:count] = ele.elements["count"].text.to_i
      result[:page] = ele.elements["page"].text.to_i
      result[:first] = ele.elements["first"].text.to_i
      result[:last] = ele.elements["last"].text.to_i
      result[:hits] = ele.elements["hits"].text.to_i
      result[:carrier] = ele.elements["carrier"].text.to_i
      result[:pageCount] = ele.elements["pageCount"].text.to_i

      result[:item] = Array.new
      ele.elements.each("Items/Item") do |item|
        result[:item].push({:itemName => item.elements["itemName"].text,
          :itemCode => item.elements["itemCode"].text,
          :itemPrice => item.elements["itemPrice"].text.to_i,
          :itemCaption => item.elements["itemCaption"].text,
          :itemUrl => item.elements["itemUrl"].text,
          :affiliateUrl => item.elements["affiliateUrl"].text,
          :imageFlag => item.elements["imageFlag"].text.to_i,
          :smallImageUrl => item.elements["smallImageUrl"].text,
          :mediumImageUrl => item.elements["mediumImageUrl"].text,
          :availability => item.elements["availability"].text,
          :taxFlag => item.elements["taxFlag"].text,
          :postageFlag => item.elements["postageFlag"].text.to_i,
          :creditCardFlag => item.elements["creditCardFlag"].text,
          :shopOfTheYearFlag => item.elements["shopOfTheYearFlag"].text,
          :affiliateRate => item.elements["affiliateRate"].text,
          :startTime => item.elements["startTime"].text,
          :endTime => item.elements["endTime"].text,
          :reviewCount => item.elements["reviewCount"].text,
          :reviewAverage => item.elements["reviewAverage"].text,
          :shopName => item.elements["shopName"].text,
          :shopCode => item.elements["shopCode"].text,
          :shopUrl => item.elements["shopUrl"].text,
          :genreId => item.elements["genreId"].text
          })
      end
    end
    return result
  end
end

使う

search = RakutenItemSearch.new("DEVID","AFFID")
options = {
  :type => "keyword",
  :query => "激安",
  :hits => 10,
  :sort => "-affiliateRate",
  :carrier => 1,
  :imageFlag => 1,
}

result = search.item_search(options)
result[:item].each{|item|puts item[:itemName]}

こんな感じで使う。


必須項目のみinitialize時に渡すとか、いろいろと手直ししたいけどとりあえずはこんな感じで。

トラックバック - http://d.hatena.ne.jp/ikki_j/20080212/1202811398