

我将分享有关如何创建Libri并将其发布在RubyGems.org上的基于过程的方法,以及在开发阶段遇到的一些技术障碍。 该项目专门针对抓取,该术语用于描述从网站页面检索基于HTML和CSS的数据的行为。 以下是有关Libri工作原理的演示视频:
在仔细研究了一些刮除想法(包括刮除Noti.st或80,000 Hours的问题简介或Adafruit的Raspberry Pi项目)之后,我决定回到一个可以简单,有意义且可供许多人使用的主题:书籍。 在搜索要从哪个网站刮取时,我有几种选择:Man Booker网站,Goodreads奖项部分以及Penguin的获奖者列表。
我选择了Barnes&Noble的奖项网页,因为它似乎是最全面的,而且也是最新的。
为了使用Bundler构建gem,我首先在Libri工作目录的终端中运行bundle gem libri 。 这将为我们的gem创建文件结构(称为scaffold目录),因此我们可以立即开始编码。
我确保我的计算机还安装了以下依赖项:
- Rake ,用于构建我们的gem的本地副本,我们将使用该副本将其推送并发布到RubyGems.org
- OpenURI ,用于像打开HTML文件一样打开URL
- Nokogiri ,用于解析网页中的HTML和XML值
- Pry ,用作本地沙箱和调试工具
- Colorize ,用于在终端中使用不同颜色设置文本样式
现在,对于Libri,我想在我的终端上执行以下三项操作:
- 显示各种奖项
- 显示属于所选奖项的书籍
- 显示所选书籍的信息
为此,我以这种方式构造了我的lib文件夹,分隔了CLI , scraper , awards , books和book类。


每个类负责宝石的不同部分:
-
CLI类负责与用户交互的终端接口 -
scraper类将基于文本的内容从网页上刮下来 -
awards类根据Scraper.scrape_barnes_noble方法返回的哈希值创建Awards对象的新实例。 -
books类从Scraper.scrape_award(award)方法返回的哈希值创建Books对象的新实例。 -
book类从Scraper.scrape_book(book)方法返回的哈希值创建Books对象的新实例。
这个阶段花费了最长的时间,但总的来说,这是成功的,我要注意以下几点:
- 我通过
HEREDOC学会了使用多行字符串,它本身具有多种方法来实现相同的目的(例如%{...},%Q{...},<<-EOS...EOS) - 最初,每当调用
exit命令时,Please try again.消息也会显示。 这是通过使用单级if/else...end条件而不是while input != 'exit'...end循环时解决的。 - 我知道我想访问多个级别的信息,从各种URL进行抓取,并能够根据用户的输入传递不同的URL(例如,如果用户输入了普利策奖,则
Scraper.scrape_award()方法必须返回信息) (根据普立兹奖的URL)。如果用户输入“ Man Booker奖”,则预期收益应来自“ Man Booker” URL)。 那时我知道我需要传入URL作为Scraper.scrape_award()方法的参数。 知道这一点后,我在顶级awards哈希中包含了:url键,其值将传递给Scraper.scrape_award()。 然后,第二级books哈希可以从传入的URL中抓取和访问-与我们从第三级URL中抓取单个书籍信息的概念相同。 我不确定这是否可行,因为我之前从事的实验并未使用多级实时更新的网站,因此不需要此流程。 但这是! 这是我在构建该项目时所学到的最好的启示,因为我知道可以在代码中构建多功能性。 - 我无法访问非
href属性的HTML值。 B&N网站上的评分值存储在aria-label属性中,当我尝试访问该属性时,该属性不会返回任何值。 我也无法访问“ 同时购买了此物品的客户”部分下列出的书籍,该书也未返回任何内容。 我仍在寻找答案。 - 最初,在抓取时,我意识到即使不实例化新对象并为其分配参数/属性,也可以使用
Hash[:key]从CLI类访问哈希值并显示它们。 这导致了一个疏忽,在这里我没有实践Ruby对象关系方法(例如has-many)就发布了工作的gem。 通过相应地修改awards,books和book类别来解决此问题。 现在,我们可以使用book.title访问哈希值,例如book.title和book.author。 - 某一时刻,当终端显示一本图书清单,然后返回选择另一个奖项时,所显示的图书清单被累积起来,从而产生了20–40–60…册图书。 这是一场灾难,我几乎放弃了。 但是,很快就意识到该错误是由每次调用
CLI#menu_award都调用CLI#make_book(award)方法引起的,这在Books.all上添加了新的书籍数组。#make_book(award)需要实例化Book对象并访问Book的各种属性,而我们需要这样做。 为了解决这个问题,在#make_book(award)之前,包含了一种清除先前实例化对象的方法,从而为每个菜单调用重置Books.all返回值。
总而言之,如Dakota所建议的那样,如果不逐行,逐组件,逐流地讨论我的代码,我将无法克服这些挑战。
通过这个粗略的流程说出我的思考过程:
- 我想做什么?
- 露比在做我期望她做的事情吗? (Yn)
- 如果没有,那是怎么回事,为什么我们认为它在发生?
- 如果它是由于X发生的,那么,如果我们更改Y,我们期望Z发生。
- 我们通过更改Y来检验假设,然后查看Z是否发生。
- 如果Z发生了,根据我们对X的理解,我们应该知道如何解决它并实现我们试图做的事情。
- 如果Z没有发生,请不要放弃! 阅读并寻求帮助,并测试不同的理解以找到适用于Ruby的知识。
这是一个简单的项目,但是有几个不同的组件相互交互,很快就很容易失去对其中一个组件的跟踪(例如,如何最好地访问和显示每条信息,在该阶段实例化了对象以及在哪个阶段还没有,等等。)当我丢掉那一张时,我很快就失去了对全局的关注,我不得不重新开始。 因此,这里要记住继续练习,并正确地进行练习!
最后,为了首次发布gem,我遵循以下简单步骤:
- 编辑Gemspec文件,并更新“
Summary”和“Description规范。 确保已重写文件上的所有todo,以防止发布时出现任何潜在的错误。 接下来,注释掉“Prevent pushing this gem to RubyGems.org的整个代码块,否则我们将无法推送我们的gem。 - 更改
spec.bindir和spec.executables。 - 通过
spec.add_development_dependency和spec.add_dependency添加依赖spec.add_dependency。 - 遵循语义版本控制标准,如有必要,更新
version.rb文件。 有很多指南,包括这个和这个。 - 也更新
README.md文件。 这是为了帮助用户概览gem,以及如何安装和运行gem。 - 确保您的GitHub存储库已更新所有文件(最新的提交和推送)。
- 确保已安装
rake,以便我们可以先运行rake build,再运行rake buildrake release,这会将我们最新的gem版本推送到RubyGems.org上,供其他人使用! 另外,我也尝试使用gem build和gem push libri-0.xxgem实现类似效果。 另一种选择是安装gem-releasegem,它提供了几种有助于宝石开发的方法,我将在进一步的项目中进行探讨。
希望您喜欢这篇文章,希望对您有意义! 提出关于宝石的任何建议,我会继续努力。 编码愉快!