четверг, 29 июля 2010 г.

Персер товаров из Amazon

Встала задача получить все товары с амазона (http://amazon.com) у определенной фирмы - Firma Title.
На сайте амазона есть возможность поиска товаров также и у определенной фирмы.
Все бы ничего - бери парсер - парси результаты поиска товаров и в свою базу, но не тут то было...
Оказывается у амазона жестко прописано ограничение на кол-во страниц результатов поиска - 400 страниц, даже если мы видим, что товаров более 27000 физически мы не можем просмотреть далее 400-ой страницы.
сначала был написан небольшой парсер с помощью средств jruby и celerity - но тако решение оказалось слишком долгим в эксплуатации - 2000 товаров заливались примерно за 5 часов - очень долго. Было найдено более быстрое решение - использовать готовое решение для получения результатов поиска товаров - gem ruby-aws.
Напрмер в этой вариации: http://github.com/res0nat0r/ruby-aws

Отрывок из кода:

is = ItemSearch.new( 'Tools', { 'Title' => "Firma title #{keyword}" } )
req = Request.new
req.locale = 'us'
resp = req.search(is, :ALL_PAGES)

Тут мы делаем запрос на получение товаров из категории Tools, содержащих в названии слова CRL и ключевое слово для сужение результатов поиска (помним про злополучные 400 страниц)

items = resp.collect { |r| r.item_search_response[0].items[0].item }.flatten rescue resp.item_search_response[0].items[0].item
puts "Найдено #{items.size} товаров"
И получаем массив товаров.

items.each do |item|
limit += 1
#return "Загрузка окончена" if limit > 5
attribs = item.item_attributes[0]
title = attribs.title.to_s
asin = item.asin.to_s
price = item.offer_summary[0].lowest_new_price.formatted_price.to_s.gsub('$', '') rescue "Не указано"
url = item.detail_page_url.to_s
description = item.editorial_reviews[0].editorial_review.content.to_s
unless Product.find_by_catalogn(asin)
Product.create!(:name => title,
:description => description,
:price_orig => price,
:price => AmazonPrice.calculate(price),
:url => url,
:catalogn => asin,
:status => 'new')
puts "Новый товар: #{title}"
end
end
puts "После запроса CRL #{keyword} в базе #{Product.all.size} товар(ов)"

Для корректного сужение результатов поиска как варианнт можно составить список ключевых слов в виде массива и записать:

keywords = ["rail", "door", "pack", "tool", "security", "bar", "push", "rod", "aluminium", "storm", "screen", "panel", "package", "automatic", "mirror", "pull", "indicator", "window", "glass", "display", "system", "sliding", "trailer", "box", "bronze", "nickel", "toyota", "mazda", "isuzu", "jeep"]

keywords.each do |keyword|
puts start = Time.now
is = ItemSearch.new( 'Tools', { 'Title' => "CRL #{keyword}" } )
.......

На моем слабом компе товары в кол-ве 3985 шт залились примерно за 25 минут - что ж - уже лучше.

воскресенье, 4 июля 2010 г.

undefined method `each' Fixnum

Ошибка в passenger

Exception NoMethodError in application (undefined method `each' for 417322:Fixnum) (process 13490):
from /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/passenger-2.2.15/lib/phusion_passenger/rack/request_handler.rb:100:in `process_request'
from /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/passenger-2.2.15/lib/phusion_passenger/rack/request_handler.rb:96:in `each'
from /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/passenger-2.2.15/lib/phusion_passenger/rack/request_handler.rb:96:in `process_request'
from /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/passenger-2.2.15/lib/phusion_passenger/abstract_request_handler.rb:207:in `main_loop'


Оказывается число пассажир не может обработать
решается таким патчем


diff --git a/lib/phusion_passenger/rack/request_handler.rb b/lib/phusion_passenger/rack/request_handler.rb
index ad22dfa..2b6e60a 100644
--- a/lib/phusion_passenger/rack/request_handler.rb
+++ b/lib/phusion_passenger/rack/request_handler.rb
@@ -96,6 +96,8 @@ protected
headers.each do |key, values|
if values.is_a?(String)
values = values.split("\n")
+ elsif values.is_a?(Fixnum)
+ values = values.to_a
end
values.each do |value|
output.write("#{key}: #{value}#{CRLF}")