Как проанализировать данные и сохранить их в переменных, используя Nokogiri и Ruby - PullRequest
0 голосов
/ 16 октября 2019

Когда я присваиваю имена переменных, такие как service_names и name_array, они равны нулю, и ничего не передается в переменную класса @@product_names.

Я использовал Pry, чтобы попробовать код, не сохраняя его в переменнойи это работает. У него есть ценности, которые мне нужны.

Я разбил это на несколько переменных, прежде чем создавать более чистый код, например:

require 'pry'
require 'rubygems'
require 'open-uri'
require 'nokogiri'


  class KefotoScraper::CLI
      @@product_names =[]
      PAGE_URL = "https://kefotos.mx/"


    def call
binding.pry
    puts "These are the services that Kefoto offers:"
    #list_products
    puts "which service would you like to select?"
    @selection = gets.chomp
    view_price_range
    puts "Would you like to go back to the service menu? y/n"
    answer = gets.chomp
      if answer == "y"
      call
      end
    end

    private

    def home_html
        # @home_html ||=
        #     HTTParty.get root_path

        Nokogiri::HTML(open(PAGE_URL))


    end
    #
    # # TODO: read about ruby memoization
    # def home_node
    #
    #     @home_node ||=
    #      Nokogiri::HTML(PAGE_URL)
    # end

def service_names
      @service_names = home_html.css(".nav-link").map do
        |link| link['href'].to_s.gsub(/.php/, "")
      end
      @service_names.each do |pr|
        @@product_names << pr
      end
    end

     def list_products
       i = 1
       n = 0

       while @@product_names.length < n
        @@product_names.each do |list_item|

         puts "#{i} #{list_item[n]}"
       i += 1
       n += 1
       end
      end
   end

     def view_price_range
       price_range = []
       @service_links.each do |link|
         if @service = link
           link.css(".row").map {|price| price["p"].value}
            price_range << p
         end
         price_range
     end


    def service_links
        @service_links ||=
        home_html.css(".nav-item").map { |link| link['href'] }
    end

end
end

@@product_names должен содержать код, который получается из

home_html.css(".nav-link").map { |link| link['href'] }.to_s.gsub(/.php/, "")

, который позже я возвращаюсь к массиву.

Вот как это выглядит в Pry:

9] pry(#<KefotoScraper::CLI>)> home_html.css(".nav-link").map { |link| link['href'] }.to_s.gsub(/.php/, "").split(",")
=> ["[\"foto-enmarcada\"", " \"impresion-fotografica\"", " \"photobooks\"", " \"impresion-directa-canvas\"", " \"impresion-acrilico\"", " \"fotoregalos\"]"]
[10] pry(#<KefotoScraper::CLI>)> home_html.css(".nav-link").map { |link| link['href'] }.to_s.gsub(/.php/, "").split(",")[0]
=> "[\"foto-enmarcada\""

1 Ответ

1 голос
/ 21 октября 2019

Командная строка Nokogiri IRB - твой друг. Для запуска используйте nokogiri "https://kefotos.mx/" в оболочке:

irb(main):006:0> @doc.css('.nav-link[href]').map { |l| l['href'].sub(/\.php$/, '') }
=> ["foto-enmarcada", "impresion-fotografica", "photobooks", "impresion-directa-canvas", "impresion-acrilico", "fotoregalos"]

Это говорит нам, что это не динамический HTML, и показывает, как я получу эти значения. Поскольку тег a не должен содержать href параметров, которые я защищал от случайного извлечения любых таких тегов.

У вас есть ошибки, потенциальные ошибки и плохие методы. Вот несколько непроверенных, но, вероятно, найдут способы их исправить:

Запуск кода приводит к:

uninitialized constant KefotoScraper (NameError)

В вашем коде есть @service и @service_links, которые никогда не инициализируютсятак ...?

Не делайте этого, потому что это жестоко:

def home_html
  Nokogiri::HTML(open(PAGE_URL))
end

Каждый раз, когда вы звоните home_html, вы (заново) открываете и (пере) читаете страницу судаленный сайт и тратить ваше и их процессорное и сетевое время. Вместо этого кэшируйте проанализированный документ в переменном виде, как вы делали в закомментированной строке, используя HTTParty. Гораздо удобнее не посещать сайты несколько раз, и это помогает избежать забанения.

Двигаемся дальше:

def service_names
  @service_names = home_html.css(".nav-link").map do
    |link| link['href'].to_s.gsub(/.php/, "")
  end
  @service_names.each do |pr|
    @@product_names << pr
  end
end

Я бы использовал что-то вроде get_product_names и вернул бы массив, как я делал вNokogiri выше:

def get_product_names
  get_html.css('.nav-link[href]').map { |l|
    l['href'].sub(/\.php$/, '')
  }
end
:
:
@@product_names = get_product_names()

Вот почему я бы сделал это по-другому. Вы использовали:

link['href'].to_s.gsub(/.php/, "")
  1. to_s является избыточным, поскольку link['href'] уже возвращает строку. Струнизация строки тратит впустую мозговые циклы при перечитывании / отладке кода. Будьте добры к себе и не делайте этого.

    require 'nokogiri'
    html = '<a href="foo">'
    doc = Nokogiri::HTML(html)
    doc.at('a')['href'] # => "foo"
    doc.at('a')['href'].class # => String
    
  2. gsub Ew. Сколько вхождений целевой строки вы ожидаете найти и заменить? Если только один, что очень вероятно в URL "href", вместо этого используйте sub, потому что это более эффективно;Он запускается только один раз и движется дальше, тогда как gsub просматривает строку хотя бы еще один раз, чтобы узнать, нужно ли ей снова запускаться.

  3. /.php/ не означает, что выдумаю, что это так, и это очень тонкая ошибка в ожидании. /.php/ означает «некоторый символ, за которым следует« php », но вы, скорее всего, имели в виду« период, за которым следует «php» ». Это то, что я привык видеть все время, потому что другие программисты, с которыми я работал, не удосужились понятьиз того, что они делали, и, будучи старшим парнем, моя работа заключалась в том, чтобы разбирать их код и находить ошибки. Вместо этого вы должны использовать /\.php/, который удаляет специальное значение ., в результате чего вы получаете желаемый шаблон, который не будетсрабатывать, если встречается "aphp" или что-то подобное. Для получения дополнительной информации см. « Метасимволы и побеги » и следующий раздел на этой странице.

  4. Вверхувыше, шаблон должен быть закреплен, чтобы не тратить больше ресурсов ЦП. /\.php/ заставит механизм регулярных выражений запускаться в начале строки и проходить по ней до конца. По мере увеличения длины строк этот процесс замедляетсяи в рабочем коде, который обрабатывает ГБ данных, это может заметно замедлить работу системы. такой якорь, как /\.php$/ или /\.php\z/, дает подсказку двигателю о том, где он должен начать смотреть, и может привести к большим ускорениям. У меня есть некоторые ответы на SO, которые входят в это, и включенные тесты показывают, как они помогают. См. " Якоря " для получения дополнительной информации.

Это должно помочь вам, но я не пытался изменить ваш код, чтобы увидеть, если это так. При задании вопросов об ошибках в вашем коде нам необходим минимальный код, необходимый для воспроизведения проблемы. Это позволяет нам помочь вам быстрее и эффективнее. Пожалуйста, смотрите " ask " и связанные страницы и " mcve ".

...