使用MetaInspector(Rails)从用户输入URL刮取图像

时间:2015-02-15 07:54:37

标签: ruby-on-rails paperclip screen-scraping

我尝试创建一个用户可以提交网址链接,标题和说明的应用,然后创建一个包含标题,说明和图片的帖子。我希望能够直接从用户提交的URL路径中抓取最佳或主要图像,并使用MetaInspector在显示页面上显示它。 (我没有使用Nokogiri或Mechanize的原因是因为我并没有完全理解这一点,并且MetaInspector似乎不那么令人生畏)

问题是我对rails非常陌生,而且我很难完成大多数教程。

是否有人能够一步一步向我解释如何做到这一点或向我展示一个非常详细且非常友好的来源?

我有一个包含该链接的Post模型,还应该将抓取的图片保存为Paperclip附件:

class Post < ActiveRecord::Base
  belongs_to :user
  has_attached_file :image
end

# == Schema Information
#
# Table name: posts
#
# id                  :integer          not null, primary key
# title               :string
# link                :string
# description         :text
# created_at          :datetime
# updated_at          :datetime
# user_id             :integer
# image_file_name     :string
# image_content_type  :string
# image_file_size     :integer
# image_updated_at    :datetime

我的应用的完整代码可在github.com/johnnyji/wanderful处找到。

我非常感谢任何帮助!谢谢

1 个答案:

答案 0 :(得分:0)

让我们一步一步地完成这一过程。

首先,将MetaInspector gem添加到Gemfile

gem 'metainspector'

并运行bundle命令。

我们需要另外一些代码:open-uri。有了它,我们可以从URL读取远程文件,就像它们是本地文件一样。它是Rubys标准库的一部分,因此它已经内置,但我们仍然需要{post}顶部的require .rb:

require 'open-uri'

class Post < ActiveRecord::Base
  belongs_to :user
  has_attached_file :image
end

我们希望每当帖子link发生变化时都会抓取图片,因此我们会在发生这种情况时进行before_save回调:

class Post < ActiveRecord::Base
  belongs_to :user
  has_attached_file :image

  before_save :get_image_from_link,
              if: ->(post) { post.link_changed? }

end
  • 您可以在ActiveRecord::Callbacks guide中找到有关before_save和其他回调的更多信息。
  • link_changed?方法是&#34;脏跟踪&#34;的一部分功能ActiveModel::Dirty提供
  • if: ->(post)被称为&#34; stabby lambda&#34; - 它基本上只是一个以当前post作为参数调用的Ruby函数。如果它返回true,则运行before_action。它也可以写成if: Proc.new { |post| post.link_changed? }

现在我们需要get_image_from_link方法。由于它只应该从Post模型本身而不是从外部(例如Post.find(5).get_image_from_link)调用,因此我们将其设为私有方法:

class Post < ActiveRecord::Base
  belongs_to :user
  has_attached_file :image

  before_save :get_image_from_link,
              if: ->(post) { post.link_changed? }

    private

  def get_image_from_link
  end
end

阅读MetaInspectors自述文件时,它有一个名为page.images.best的酷方法,可以帮助我们从该页面选择正确的图像。所以我们要去

  1. 使用MetaInspector解析链接
  2. 以“open-uri作为File对象
  3. 打开最佳选择的图片
  4. File - 类似对象提供给Paperclip以保存为附件
  5. 所以:

    def get_image_from_link
      # `link` here is `self.link` = the current post.
      # At least when reading attributes, `self` is implicit
      # in Ruby
      page = MetaInspector.new(link)
    
      # maybe the page didn't have images?
      return unless page.images.best.present?
    
      # when you use IO resources such as files, you need
      # to take care that you `.close` everything you open.
      # Using the block form takes care of that automatically.
      open(page.images.best) do |file|
    
        # when writing/assigning a value, `self` is not
        # implicit, because when you write `something = 5`, 
        # Ruby cannot know whether you want to assign to 
        # `self.something` or create a new local variable 
        # called `something`
        self.image = file
      end
    end
    

    这远非完美,因为它缺少一些错误处理(如果MetaInspector无法打开页面怎么办?或者open-uri无法读取图像URL?)。此外,这具有以下缺点:所有解析,下载等都在用户提交或更新其帖子时发生,因此当她点击保存按钮时,她必须等待所有这些完成。

    对于下一次迭代,请考虑异步执行这些操作,例如使用作业队列。轨道&#39;新的Active Job系统可能是一个很好的起点。