Перебор нескольких URL-адресов для анализа HTML с помощью Nokogori

То, что я пытаюсь сделать, это очистить названия и цены предметов от нескольких поставщиков, используя Nokogiri. Я передаю селекторы CSS (для поиска имен и цен) в Nokogiri с аргументами метода.

Любое руководство о том, как передать несколько URL-адресов методу «очистить», а также передать другие аргументы (например, поставщик, путь к элементу)? Или я иду об этом совершенно неправильно?

Вот код:

require 'rubygems' # Load Ruby Gems
require 'nokogiri' # Load Nokogiri
require 'open-uri' # Load Open-URI

@@collection = Array.new # Array to hold meta hash

def scrape(url, vendor, item_path, name_path, price_path)
    doc = Nokogiri::HTML(open(url)) # Opens URL
    items = doc.css(item_path) # Sets items
    items.each do |item| # Iterates through each item on grid
        @@collection << meta = Hash.new # Creates a new hash then add to global array
        meta[:vendor] = vendor
        meta[:name] = item.css(name_path).text.strip
        meta[:price] = item.css(price_path).to_s.scan(/\d+[.]\d+/).join 
    end
end

scrape( "page_a.html", "Sample Vendor A", "#products", ".title", ".prices")
scrape( ["page_a.html", "page_b.html"], "Sample Vendor B",  "#items", ".productname", ".price")

person matcha_pat    schedule 16.03.2013    source источник


Ответы (2)


Вы можете передать несколько url's так же, как вы уже делаете это во втором примере:

scrape( ["page_a.html", "page_b.html"], "Sample Vendor B",  "#items", ".productname", ".price")

Ваш метод scrape должен будет перебирать эти urls, например:

def scrape(urls, vendor, item_path, name_path, price_path)
  urls.each do |url|
    doc = Nokogiri::HTML(open(url)) # Opens URL
    items = doc.css(item_path) # Sets items
    items.each do |item| # Iterates through each item on grid
        @@collection << meta = Hash.new # Creates a new hash then add to global array
        meta[:vendor] = vendor
        meta[:name] = item.css(name_path).text.strip
        meta[:price] = item.css(price_path).to_s.scan(/\d+[.]\d+/).join 
    end 
  end   
end

Это также означает, что первый пример также нужно передать как массив:

scrape( ["page_a.html"], "Sample Vendor A", "#products", ".title", ".prices")
person fmendez    schedule 16.03.2013
comment
Благодарю вас! Это отлично работает. Я не знал, что мне нужно было также передать первый пример как массив. - person matcha_pat; 16.03.2013

К вашему сведению, использование @@collection неуместно. Вместо этого напишите свой метод для возврата значения:

def scrape(urls, vendor, item_path, name_path, price_path)
  collection = []
  urls.each do |url|
    doc = Nokogiri::HTML(open(url)) # Opens URL
    items = doc.css(item_path) # Sets items
    items.each do |item| # Iterates through each item on grid
      collection << {
        :vendor => vendor,
        :name   => item.css(name_path).text.strip,
        :price  => item.css(price_path).to_s.scan(/\d+[.]\d+/).join
      }
    end 
  end   

  collection
end

Что можно сократить до:

def scrape(urls, vendor, item_path, name_path, price_path)
  urls.map { |url|
    doc = Nokogiri::HTML(open(url)) # Opens URL
    items = doc.css(item_path) # Sets items
    items.map { |item| # Iterates through each item on grid
      {
        :vendor => vendor,
        :name   => item.css(name_path).text.strip,
        :price  => item.css(price_path).to_s.scan(/\d+[.]\d+/).join
      }
    } 
  }
end
person the Tin Man    schedule 17.03.2013
comment
Использование второго метода, который вы предложили, просто сократило мое реальное время выполнения вдвое. С моим исходным кодом я использовал это для печати данных: def list_matches @@collection.each do |k| puts "Vendor: #{k[:vendor]}" puts "Name: #{k[:name]}" puts "Price: $#{k[:price]}" end end Как я могу сделать то же самое с вашим методом? Спасибо за помощь. - person matcha_pat; 17.03.2013
comment
Хех, чудеса никогда не прекратятся? Могу только сказать, что иногда мне везет. :-) На самом деле, есть шаблоны, которые мы снова и снова используем в нашем коде, и со временем мы должны научиться распознавать определенные варианты использования/приложения кода и сразу же переходить к ним. Второй является сокращением первого и является результатом слишком многих лет написания кода на множестве разных языков. Хорошо, что я смог помочь. - person the Tin Man; 18.03.2013