如何使用.each进行迭代并在Ruby中抓取数据?

时间:2019-04-13 03:55:23

标签: arrays ruby iteration nokogiri scrape

我对编程很陌生,需要一些帮助/反馈我的代码。我的目标是刮取位置及其详细信息,然后在编号列表中向我的用户显示该数据。我只是很难显示此数据。我在使用.each方法进行迭代时遇到麻烦。我尝试使用travel_details进行迭代,但是它不起作用。有什么建议么?在此先感谢您的帮助/反馈!

我想要的输出将如下所示:

Which location you would like to know more about?
 1. Nairobi, Kenya
2. Juneau, United States
3. Hong Kong
4. Litchfield National Park, Australia
5. Patagonia, Chile
6. Yukon, Canada
7. San Juan, Puerto Rico
8. Panama
9. Matera, Italy
10. Yokohama, Japan

----更新---

我能够更新我的代码。以下是输入。我想要有关show_selection的帮助,现在获取选择方法。用户输入要查看的地点的数字后,代码应查看Travel_Cli :: Place.all类数组,并放置适当的名称和摘要。然后,应在show_selection方法中显示它。我认为我应该使用.find索引来查看它是否等于输入,但不确定如何。在编码中,我放置了所需的输出。 这将使用户可以决定他们想了解更多的位置。

# CLI Controller
class TravelCli::Cli

  attr_accessor :locale

def call
  welcome
  list_places
  input = nil
  while input != "exit"
    input = gets.chomp.downcase
  if input == "list"
      list_places
  elsif !(0..10).include?(input.to_i)
      puts "You have not selected a valid option."
  elsif input != "exit"
      @locale = input
      show_selection
    end
    menu
  end
  #goodbye
end


def get_selection
   #Place instance that you will get from Place.all
    #TravelCli::Place.all.each {|place| puts "#{place.summary}"}
    #TravelCli::Place.all.find_index { |p| place.summary == locale } #have to define input
    #TravelCli::Place.find_index {|place| place == @locale }
    TravelCli::Place.all.each_with_index do |place, i|
    if locale == place.name[i+1]
        return true
    end
   #binding.pry
end

def show_selection
  get_selection
  puts "Here is more information about  #{locale}."
  puts
  puts " display details from get_selection"


  #outputs the summary of the input from the place.all array
end

def menu
puts "Type 'exit' to quit"
puts "Type 'list' to list places"
end


def welcome
  puts " Feel Like Traveling? "
  puts "     "
  puts "----10 Of The Best Travel Destinations You Should Visit In 2019-----"
  puts "     "
end

def get_places
  TravelCli::Scrape.scrape_places
end

def list_places
  get_places
  TravelCli::Place.all.each.with_index(1) {|place, i| puts "#{i}. #{place.name}"}
  puts
  puts " Which Location would you like to learn more about?:   "
end


 def goodbye
   puts "Happy Travels!"
 end

end

class TravelCli::Scrape

  URL = 'https://www.buzzfeed.com/louisekhong/bring-me-2019-best-travel-destinations'

    def self.scrape_places
        Nokogiri::HTML(open(URL)).css('.subbuzz').each do |place|
          TravelCli::Place.new(
            place.css('.js-subbuzz__title-text').text.strip,
            place.css('.subbuzz__description').text.strip)
        end
    end
  end
class TravelCli::Place
  attr_accessor :name, :summary, :place

  @@all = []


def initialize(name, summary)
    @name = name
    @summary = summary
    @@all << self
 end

 def self.all
   @@all
 end



end

2 个答案:

答案 0 :(得分:1)

您非常接近。您想弄清楚每个位置的容器是什么,并在其上循环。在这种情况下,它是.subbuzz。每个.subbuzz都有一个.js-subbuzz__title-text(位置名称)和.subbuzz__description(描述文本)。另外,我使用单个对象数组表示每个位置,而不是尝试维护多个数组并使值保持同步。

您的代码中确实有一个重要的错字。您初始化了@travel_details = [],但使用@@travel_details << ele....进行了填充。 @travel_details是一个实例变量。 @@travel_details是一个类变量。他们是完全不同的。我想您因此而在运行代码时会收到Undefined method << for nil:NilClass

如果对此有任何疑问,请随时提问!

代码:

# frozen_string_literal: true

require 'nokogiri'
require 'open-uri'

module TravelCli
  Place = Struct.new(:title, :description, :image_url) do
    def to_s
      <<~TEXT
        Title: #{title}
        Description: #{description}
      TEXT
    end
  end

  class Places
    URL = 'https://www.buzzfeed.com/louisekhong/bring-me-2019-best-travel-destinations'

    def self.print
      places = new
      places.scrape

      puts places.list.map(&:to_s).join("\n")
    end

    attr_reader :list

    def scrape
      @list = Nokogiri::HTML(open(URL)).css('.subbuzz').map do |place|
        Place.new(
          place.css('.js-subbuzz__title-text').text.strip,
          place.css('.subbuzz__description').text.strip,
        )
      end
    end

  end
end

TravelCli::Places.print

输出:

Title: Nairobi, Kenya
Description: Who'll love it: animal loversWhy go in 2019: Thanks to the recent launch of a direct flight route between Nairobi and New York City, spotting elusive lions and leopards on safari is now just that liiiiitttle bit easier. As both Africa's safari capital and one of the continent's fastest growing cities, Nairobi offers a unique contrast between the city and the wild.

Title: Juneau, United States
Description: Who’ll love it: foodiesWhy go in 2019: Juneau, Alaska, is having a foodie moment (I mean, why else would it be hosting the 2019 International Food Blogger Conference?). Focusing on fresh, local seafood and wild fruits, the food scene here is understated, delicious, and eco-friendly by nature. Be sure to check out Salt, an up-and-coming modern Alaskan restaurant that serves food foraged by the chef himself.

Title: Hong Kong
Description: Who’ll love it: solo travelers Why go in 2019: Hong Kong may be a small island, but it's bursting with culture! New and exciting attractions, including museums and a huge cultural center, make it the perfect city to explore solo. M+ Museum is slated to open this year and at 17,000 square meters, it'll be one of the largest museums of modern visual culture in the world. It's also one of the world's safest cities, which is comforting to know if you’re traveling on your own.

Title: Litchfield National Park, Australia
Description: Who'll love it: escapistsWhy go in 2019: With hiking trails through striking landscapes, epic 4WD tracks, and stunning waterfalls that lead to glistening natural pools, a visit to Litchfield National Park will make you forget that the rest of the world exists. Located ~90 minutes south of Darwin, it's smaller than the popular Kakadu National Park (and has fewer tourists!), and it's currently undergoing improvements that'll see new campgrounds and swimming spots open this year.

Title: Patagonia, Chile
Description: Who’ll love it: adventure seekersWhy go in 2019: Any serious adventurer will love the new massive hiking trail that connects 17 different national parks. Created as part of a huge conservation effort, the Route of Parks in Patagonian spans 1,740 miles and takes travelers on a scenic journey through parks like Torres del Paine and San Rafael Lagoon. It's the perfect way to experience some of Chile's incredible natural beauty.

Title: Yukon, Canada
Description: Who'll love it: nature loversWhy go in 2019: The Yukon territory is a prime place to catch a glimpse of the northern lights, and soon you'll be able to see them in a whole new way — on board a private jet! The Aurora 360 is taking flight for the first time in February, but if you don't make it in time for that, camping out in a tent is equally as magical. While you're there, make sure you visit Kluane National Park and Reserve to hike up Mount Logan, Canada's tallest peak.

Title: San Juan, Puerto Rico
Description: Who'll love it: conscientious travelers Why go in 2019: Since the devastation of Hurricane Maria in 2017, Puerto Rico has made huge strides in rebuilding the island and tourism is a key way to keep that regrowth underway. With amazing food (visit the famous Pork Highway just outside of San Juan), colorful architecture, and gorgeous natural beauty, traveling to the island this year doesn’t just benefit Puerto Ricans, but will also be a trip of a lifetime.

Title: Panama
Description: Who'll love it: party goers and beach bumsWhy go in 2019: This year marks the 500 year anniversary of Panama City and a celebration you won't want to miss. Special events such as parades, exhibitions, and musical shows are running until mid-August, but you can party with the locals and explore the historic old town year-round. When you're ready for some R&R, head up north to the blindingly white sand and clear waters of Bocas Del Toro.

Title: Matera, Italy
Description: Who’ll love it: history buffsWhy go in 2019: As one of the world’s oldest continuously inhabited cities, Matera has been named one of 2019’s European Capitals of Culture for its cultural importance (and stunning beauty). Its blend of ancient architecture and modern dining and entertainment is absolutely enchanting. Any place where you can spend days learning about 12th-century churches and nights dining on Italian food in an underground grotto restaurant is a winner for us.

Title: Yokohama, Japan
Description: Who'll love it: sports fansWhy go in 2019: Sporting fever is taking over Japan as it gears up for the 2019 Rugby World Cup in September (and let's not forget the Olympics in 2020). Just over 30 minutes south of Tokyo, the colorful harbor city of Yokohama is home to Japan's largest stadium and will play host to seven games — including the final. The food is also incredible: we recommend visiting the Shin-Yokohama Ramen Museum and snacking your way through Chinatown (it's the biggest in Japan!).

答案 1 :(得分:0)

已更新

这是您基于先前答案的程序,其中包括修复刮板中拼凑在一起的句子的错误,只需删除.strip

# frozen_string_literal: true
require 'nokogiri'
require 'open-uri'
require 'pry'

module TravelCli
  Place = Struct.new(:title, :description, :image_url) do
    def to_s
      <<~TEXT
        Title: #{title}
        Description: #{description}
      TEXT
    end
  end

  class Places
    URL = 'https://www.buzzfeed.com/louisekhong/bring-me-2019-best-travel-destinations'

    def self.run
      places = new
      places.scrape
      list = places.list
      output = lambda do
        list.each_with_index{|l, i| puts "#{i+1}. #{l.title}"}
        puts "\nSelect a place by number or type exit: "
      end
      input = ''
      loop do
        output.call
        input = gets.chomp
        break if input == "exit"
        item = list[input.to_i-1]
        puts "\n"
        puts item[:title]
        puts item[:description]
        puts "\n"
      end
    end

    attr_reader :list

    def scrape
      @list = Nokogiri::HTML(open(URL)).css('.subbuzz').map do |place|
        Place.new(
          place.css('.js-subbuzz__title-text').text,
          place.css('.subbuzz__description').text,
        )
      end
    end
  end
end

TravelCli::Places.run