如何从结构不良的 Nokogiri 中获取特定项目 HTML

How to get specific items with Nokogiri from poorly structured HTML

我正在使用 Nokogiri 抓取“The Broadway Bookshop”事件列表,但该页面或多或少都是一个内容块。我似乎无法使用 class="news" 访问特定的 h3 项目:

def scrape_broadway_books
  base_url = "https://broadwaybookshophackney.com"
  slug = "/events/?event=archive"
  url = base_url + slug
  unparsed_page = HTTParty.get(url)
  parsed_page = Nokogiri::HTML(unparsed_page)
  events_list = parsed_page.at_css("div#content")
  # binding.pry
  events = Array.new
  events_list.each do |item|
    puts item.css("h3.news").text
  end
end

这给了我错误:

undefined method `css' for ["id", "content"]:Array (NoMethodError)

如果我尝试遍历 events_list 我仍然只会将一个事件写入我的数据文件:

events_list = parsed_page.css("div#content")
events = Array.new
events_list.each_with_index do |event, index|
  event = {
    index: index,
    title: event.css("h3.news").text
  }
  events << event
end
File.open("./_data/events.json", "w") do |file|
  file.write(JSON.pretty_generate(events))
end

为什么我不能遍历内容div?

at_cssreturns a single element。它不会是可迭代的;当您尝试迭代它时,您将获得 div 的属性。如果您想获取要迭代的元素列表,请改用 parsed_page.css("div#content")

或者,更简洁:

events = parsed_page.css("div#content h3.news").map(&:text)

完成那部分重构后,您还可以考虑稍微重构该方法,以便您的 URL 提取和文档解析可重用,从而将您的 scrape_broadway_books 清理为单一职责:

def scrape_broadway_books
  doc = doc_from_url("https://broadwaybookshophackney.com",
    "/events/?event=archive")
  doc.css("div#content h3.news").map(&:text)
end

def doc_from_url(*parts)
  uri = URI.join(*parts)
  Nokogiri::HTML(HTTParty.get(uri))
end