Я знаю, что это не совсем отвечает на ваш вопрос, но, возможно, вы могли бы рассмотреть возможность использования другого подхода в целом. Использование циклов 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
Примечание: вы Возможно, вы захотите перепроверить, что возвращаемые результаты верны. Я думаю, что так и должно быть, но я написал это довольно быстро, так что где-то там всегда может быть небольшая ошибка.