问题描述
我正在编写一个抓取genius.com的应用,以向用户显示前十首歌曲。然后,用户可以选择一首歌以查看歌词。
我想知道如何在scraper类的方法中使用在cli类中收集的用户输入。
现在,我有一部分刮板发生在刮板类之外,但我希望明确划分责任。
这是我的代码的一部分:
Class CLI
def get_user_song
chosen_song = gets.strip.to_i
if chosen_song > 10 || chosen_song < 1
puts "Only the hits! Choose a number from 1-10."
end
我希望能够执行以下操作。
Class Scraper
def self.scrape_lyrics
page = Nokogiri::HTML(open("https://genius.com/#top-songs"))
@url = page.css('div#top-songs a').map {|link| link['href']}
user_selection = #input_from_cli #<---this is where I'd like to use the output
# of the 'gets' method above.
@print_lyrics = @url[user_selection - 1]
scrape_2 = Nokogiri::HTML(open(@print_lyrics))
puts scrape_2.css(".lyrics").text
end
我基本上想知道如何将所选的歌曲变量传递到Scraper类中。我尝试过一种编写类的方法,但是在编写该类方法时遇到了麻烦,不会破坏程序的其余部分。
感谢您的帮助!
解决方法
我看到了两种解决您问题的方法。哪一种适合此取决于您的设计目标。我将尝试使用每个选项进行解释:
-
从对代码的简单阅读中,用户输入了数字而没有看到页面的内容(通过您的程序)。在这种情况下,简单的方法是将所选数字作为参数传递给
scrape_lyrics
方法:def self.scrape_lyrics(user_selection) page = Nokogiri::HTML(open("https://genius.com/#top-songs")) @url = page.css('div#top-songs a').map {|link| link['href']} @print_lyrics = @url[user_selection -1] scrape_2 = Nokogiri::HTML(open(@print_lyrics)) puts scrape_2.css(".lyrics").text end
所有排序都发生在CLI类中,并且在开始时使用所有必需的数据调用刮板。
-
当以更具交互性的方式想象您的工具时,我想让刮板下载当前的前10名并将列表呈现给用户以供选择可能会很有用。在这种情况下,交互作用要来回多一些。 如果仍然需要严格分开,可以将
scrape_lyrics
分为scrape_top_ten
和scrape_lyrics_by_number(song_number)
并在CLI类中对其进行排序。 如果您希望交互流程非常动态,那么最好将交互方法注入刮板中并反转依赖关系:def self.scrape_lyrics(cli) page = Nokogiri::HTML(open("https://genius.com/#top-songs")) titles = page.css('div#top-songs h3:first-child').map {|t| t.text} user_selection = cli.choose(titles) # presents a choice to the user,returning the selected number @url = page.css('div#top-songs a').map {|link| link['href']} @print_lyrics = @url[user_selection - 1] scrape_2 = Nokogiri::HTML(open(@print_lyrics)) puts scrape_2.css(".lyrics").text end
有关后一种方法的示例实现,请参见
tty-prompt
gem。