Как правильно написать время l oop - PullRequest
0 голосов
/ 11 января 2020

Я пытаюсь почистить веб-сайт, но, похоже, я не могу заставить мой while-l oop вспыхнуть, как только он попадет на страницу без дополнительной информации:

def scrape_verse_items(keyword)

  pg = 1

  while pg < 1000
    puts "page #{pg}"
    url = "https://www.bible.com/search/bible?page=#{pg}&q=#{keyword}&version_id=1"

    doc = Nokogiri::HTML(open(url))
    items = doc.css("ul.search-result li.reference")
    error = doc.css('div#noresults')

    until error.any? do
      if keyword != '' 
        item_hash = {}
        items.each do |item|
          title = item.css("h3").text.strip
          content = item.css("p").text.strip
          item_hash[title] = content

        end
      else
        puts "Please enter a valid search"
      end 

      if error.any? 
        break
      end
    end
    pg += 1
  end
  item_hash
end

puts scrape_verse_items('joy')

1 Ответ

0 голосов
/ 12 января 2020

Я знаю, что это не совсем отвечает на ваш вопрос, но, возможно, вы могли бы рассмотреть возможность использования другого подхода в целом. Использование циклов while и until может немного сбить с толку, и, как правило, это не самый эффективный способ работы.

Возможно, вы бы вместо этого решили использовать рекурсию. Я написал небольшой скрипт, который, кажется, работает:

class MyScrapper

  def initialize;end

  def call(keyword)
    puts "Please enter a valid search" && return unless keyword

    scrape({}, keyword, 1)
  end

  private

  def scrape(results, keyword, page)
    doc = load_page(keyword, page)

    return results if doc.css('div#noresults').any?

    build_new_items(doc).merge(scrape(results, keyword, page+1))
  end

  def load_page(keyword, page)
    url = "https://www.bible.com/search/bible?page=#{page}&q=#{keyword}&version_id=1"
    Nokogiri::HTML(open(url))
  end

  def build_new_items(doc)
    items = doc.css("ul.search-result li.reference")

    items.reduce({}) do |list, item|
      title = item.css("h3").text.strip
      content = item.css("p").text.strip

      list[title] = content
      list
    end
  end
end

Вы вызываете его, выполняя MyScrapper.new.call("Keyword") (Возможно, имеет смысл иметь это как модуль, который вы включаете, или даже иметь его как методы класса чтобы избежать необходимости создания экземпляра класса.

Для этого нужно вызвать метод с именем scrape и дать ему начальные результаты, ключевое слово и страницу. Он загружает страницу, если результатов нет он возвращает существующие результаты, которые он нашел.В противном случае он строит ха sh из загруженной страницы, а затем метод вызывает сам себя и объединяет результаты с новым ха sh, который он только что построил. больше нет результатов.

Если вы хотите ограничить результаты страницы, вы можете просто изменить это как:

return results if doc.css('div#noresults').any?

на это:

return results if doc.css('div#noresults').any? || page > 999

Примечание: вы Возможно, вы захотите перепроверить, что возвращаемые результаты верны. Я думаю, что так и должно быть, но я написал это довольно быстро, так что где-то там всегда может быть небольшая ошибка.

...