# # Author: IKARASHI Yoshinori # License: GPLv2 # $Id: amazon-a2s.rb 4 2008-03-25 01:55:23Z yoosee $ # =begin This module wraps Amazon A2S (aka ECS4.0). About Amazon A2S, see http://www.amazon.com/gp/browse.html?node=3435361 http://www.ajaxtower.jp/ecs/responsegroup/index.html (japanese) Sample: aws = AmazonA2S.new item = aws.lookup "B0012M1BRG" puts "#{item.title}" items = aws.search "Ruby" items.each do |item| ... =end require 'open-uri' require 'uri' require 'timeout' require 'net/http' require 'zlib' require 'rexml/document' require 'fileutils' require 'md5' class AmazonItem attr_accessor :title, :uri, :image_uri, :manufacture, :author, :rexml end class AmazonA2S attr_accessor :associate_tag, :cache_dir, :cache_life, :xml AwsParameters = { :AWSAccessKeyId => "1X7MZVP4YBE35YP64PG2", :AssociateTag => "yooseenet-22", :Operation => "ItemSearch", :SearchIndex => nil, :Keywords => nil, :ItemId => nil, :ResponseGroup => "Request,Small,Images", # default :ItemPage => 1, :Version => "2007-10-29", } Host = "webservices.amazon.co.jp" URIBase="http://" + Host + "/onca/xml?Service=AWSECommerceService" def initialize @associate_tag = nil @cache_dir = "/tmp/amazon/" @cache_life = 3600 * 6 # 6 hours end def cache uri digest = Digest::MD5.hexdigest(uri) file = @cache_dir + "/" + digest if !File.exist? file || (File.mtime file - Time.now) > @cache_life return nil else page = '' File.open(file) do |f| page = f.read end return page end return nil end def write_cache uri, page digest = Digest::MD5.hexdigest(uri) FileUtils.mkdir_p @cache_dir unless File.directory? @cache_dir file = (@cache_dir + "/" + digest).gsub(/\/+/, '/') begin File.open file, 'w' do |f| f.puts page end rescue end return page end def fetch uri opts = { "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>'Mozilla/6.0 AWSBot' } page, meta, content_type, status, message = nil, nil, nil, nil, nil begin page = timeout(10) { URI.parse(uri).open(opts) {|f| content_type = f.content_type f.read } } rescue OpenURI::HTTPError STDERR.puts "HTTP Error #{$!}" return '' rescue StandardError, TimeoutError STDERR.puts "Error #{$!}" return '' end if /\A\x1f\x8b/ =~ page begin page = Zlib::GzipReader.new(StringIO.new(page)).read || '' rescue Zlib::Error page = '(zlib decode error)' end end return page end def build_uri aws_parameters uri = URIBase aws_parameters[:AssociateTag] = @associate_tag if @associate_tag aws_parameters.each do |key, value| uri += "&" + key.to_s + "=" + value.to_s if value end return uri end def item_search keyword, category="Blended", response_group = "Request,Small,Images" aws_parameters = AwsParameters aws_parameters[:Operation] = "ItemSearch" aws_parameters[:Keywords] = URI.encode(keyword) aws_parameters[:SearchIndex] = category aws_parameters[:ResponseGroup] = response_group uri = build_uri aws_parameters puts uri if (page = cache uri) return page end page = fetch uri write_cache uri, page return page end def item_lookup asin aws_parameters = AwsParameters aws_parameters[:Operation] = "ItemLookup" aws_parameters[:ItemId] = asin uri = build_uri aws_parameters if (page = cache uri) return page end page = fetch uri write_cache uri, page return page end def items key, type=:lookup # or search items = Array.new case type when :search page = item_search key when :lookup page = item_lookup key else return end @xml = page rexml = REXML::Document.new page rexml.elements.each("*/Items/Item") do |item| amazonitem = AmazonItem.new amazonitem.rexml = item begin amazonitem.title = item.elements["ItemAttributes/Title"].text amazonitem.uri = item.elements["DetailPageURL"].text amazonitem.image_uri = item.elements["MediumImage/URL"].text if item.elements["MediumImage/URL"] if item.elements["ItemAttributes/Actor"] amazonitem.author = item.elements["ItemAttributes/Actor"].text end items.push amazonitem rescue puts "#{$!}:#{$@}" end end return items end def lookup asin return items(asin, :lookup).first end def search keyword return items(keyword, :search) end end if __FILE__ == $0 aws = AmazonA2S.new asin = "B0012M1BRG" item = aws.lookup asin puts "#{item.title}" items = aws.search "ぼのぼの" items.each do |item| puts "#{item.title}" end end