Reputation: 55
I am pretty new to programming and need some help/feedback on my code. My goal is to scrape the location, its details and then display that data to my user in a numbered list. I am simply having difficulty displaying this data. I'm having trouble with the iteration using the .each method. I tried to do the iteration with the travel_details but its not working. Any suggestions? Thanks in advance for any help/feedback!
The output I want will look like this:
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
---- UPDATE ---
I was able to update my code. Below is the input. I would like help on the show_selection and get selection methods now. Once the user enters a number for the place they want to see, the code should look at the Travel_Cli::Place.all class array and put the appropriate name and summary. It should then display it in the show_selection method. I think that I should use the .find index to see if it equals the input but not sure how. In the coding, I placed my desired output. This will allow the user to decide which location they would like to learn more about.
# 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
Upvotes: 0
Views: 405
Reputation: 11226
Here is your program based on the previous answer including the fix to smashed together sentences bug in scraper , just remove 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
Run program and you will get this output:
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
Select a place by number or type exit:
Upvotes: 0
Reputation: 2404
You were pretty close. You want to figure out what the container for each individual location is, and loop over that. In this case, it's .subbuzz
. Each .subbuzz
has a .js-subbuzz__title-text
(the location name) and .subbuzz__description
(the description text). Also, I used a single array of objects to represent each location, instead of trying to maintain multiple arrays and keep the values in sync.
You did have an important typo in your code as well. You initialized @travel_details = []
, but filled it using @@travel_details << ele....
. @travel_details
is an instance variable. @@travel_details
is a class variable. They're quite different. I imagine you received Undefined method << for nil:NilClass
when you ran your code because of that.
If you have any questions about this, definitely feel free to ask!
Code:
# 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
Output:
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!).
Upvotes: 1