Как назначить элемент Nokogiri хэш-ключу - PullRequest
0 голосов
/ 24 октября 2019

Я перебираю Techcrunch.com и беру заголовок, URL и текст предварительного просмотра каждой статьи.

У меня есть:

require 'nokogiri'
require 'open-uri'

class TestScraper::Scraper
@doc = Nokogiri::HTML(open("https://techcrunch.com")

  def scrape_tech_crunch
    articles = @doc.css("h2.post-block__title").css("a")
    top_stories = articles.each do |story|
      stories = {
        :title => story.children.text.strip,
        :url => story.attribute("href").value,
        :preview => @doc.css("div.post-block__content").children.first.text
      }
      TestScraper::Article.new(stories)
    end
  end
end

TestScraper::Article.new(stories) принимает хеш в качестве аргументаи использует его для инициализации класса Article:

class TestScraper::Article
  attr_accessor :title, :url, :preview 

  @@all = []

  def initialize(hash)
    hash.each do |k, v|
      self.send "#{k}=", v
    end
    @@all << self
  end

  def self.all
    @@all
  end
end

Когда я запускаю TestScraper::Scraper.new("https://techcrunch.com").scrape_tech_crunch, я получаю:

[#<TestScraper::Article:0x00000000015f69e0
  @preview=
   "\n\t\tSecurity researchers have found dozens of Android apps in the Google Play store serving ads to unsuspecting victims as part of a money-making scheme. ESET researchers found 42 apps conta
ining adware, \t",
  @title=
   "Millions downloaded dozens of Android apps on Google Play infected with adware",
  @url=
   "https://techcrunch.com/2019/10/24/millions-dozens-android-apps-adware/">,
 #<TestScraper::Article:0x00000000015f5658
  @preview=
   "\n\t\tSecurity researchers have found dozens of Android apps in the Google Play store serving ads to unsuspecting victims as part of a money-making scheme. ESET researchers found 42 apps conta
ining adware, \t",
  @title="Netflix launches $4 mobile-only monthly plan in Malaysia",
  @url=
   "https://techcrunch.com/2019/10/24/netflix-malaysia-mobile-only-cheap-plan/">

Создает объект с соответствующим заголовком и URL для каждого экземпляракласс article, но он продолжает присваивать один и тот же текст предварительного просмотра каждому экземпляру статьи. Должно быть 20 статей, каждая со своим «предварительным просмотром» (небольшой образец статьи, который вы получите перед тем, как щелкнуть ссылку, чтобы прочитать статью полностью).

1 Ответ

2 голосов
/ 24 октября 2019

Проблема, с которой вы столкнулись, связана с тем, что

@doc.css("div.post-block__content").children.first.text

выбирает один и тот же узел для каждой истории, поскольку вы вызываете его на @doc, который является глобальным документом.

Вместо этого попробуйте найти самый верхний наиболее распространенный узел и отправляйтесь вниз оттуда:

@doc.css('.post-block').map do |story|
  # navigate down from the selected node
  title   = story.at_css('h2.post-block__title a')
  preview = story.at_css('div.post-block__content')

  TestScraper::Article.new(
    title:   title.content.strip,
    href:    title['href'],
    preview: preview.content.strip
  )
end

Если какой-либо из использованных методов поднимает вопросы, взгляните на Шпаргалку Nokogiri . Если после этого у вас есть какие-либо вопросы, не стесняйтесь спрашивать об этом в комментариях.

...