使用 MetaInspector (Rails) 从用户输入 URL 抓取图像
Scraping images from user input URL using MetaInspector (Rails)
我正在尝试创建一个应用程序,用户可以在其中提交 URL link、标题和说明,它会创建一个带有标题的 post,描述和图像。我希望能够直接从用户提交的 URL 路径中抓取最佳或主要图像,并使用 MetaInspector 将其显示在显示页面上。 (我没有使用 Nokogiri 或 Mechanize 的原因是因为我不太了解它,而 MetaInspector 似乎不那么令人生畏)
问题是我是 rails 的新手,我很难理解大多数教程。
有谁能一步一步地向我解释如何做到这一点,或者向我展示一个非常详细且新手友好的资源?
我有一个包含 link 的 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 获得。
非常感谢任何帮助!谢谢
让我们一步一步来完成。
首先,将 MetaInspector gem 添加到您的 Gemfile
gem 'metainspector'
和 运行 bundle
命令。
我们还需要一点代码:open-uri
。有了它,我们就可以像读取本地文件一样从 URLs 读取远程文件。它是 Ruby 标准库的一部分,所以它已经内置,但我们仍然需要 require
它在你的 post.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?
方法是 "dirty tracking" 功能的一部分 ActiveModel::Dirty 提供
- 那个
if: ->(post)
东西叫做 "stabby lambda" - 它基本上只是一个 Ruby 函数,用当前的 post
作为参数调用。如果是returnstrue
,那么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 README,它有一个很酷的方法,叫做 page.images.best
,它为我们从该页面选择正确的图像做了艰苦的工作。所以我们要
- 使用 MetaInspector
解析 link
- 用
open-uri
打开它选择的最佳图像作为File
类对象
- 将类似
File
的对象提供给 Paperclip
以另存为附件
所以:
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?)。此外,这还有一个缺点,即所有解析、下载等操作都在用户提交或更新她 post 时发生,因此当她单击保存按钮时,她将不得不等待所有这些操作完成完成。
对于下一次迭代,研究异步执行这些操作,例如使用作业队列。 Rails' 新的 Active Job 系统可能是一个很好的起点。
我正在尝试创建一个应用程序,用户可以在其中提交 URL link、标题和说明,它会创建一个带有标题的 post,描述和图像。我希望能够直接从用户提交的 URL 路径中抓取最佳或主要图像,并使用 MetaInspector 将其显示在显示页面上。 (我没有使用 Nokogiri 或 Mechanize 的原因是因为我不太了解它,而 MetaInspector 似乎不那么令人生畏)
问题是我是 rails 的新手,我很难理解大多数教程。
有谁能一步一步地向我解释如何做到这一点,或者向我展示一个非常详细且新手友好的资源?
我有一个包含 link 的 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 获得。
非常感谢任何帮助!谢谢
让我们一步一步来完成。
首先,将 MetaInspector gem 添加到您的 Gemfile
gem 'metainspector'
和 运行 bundle
命令。
我们还需要一点代码:open-uri
。有了它,我们就可以像读取本地文件一样从 URLs 读取远程文件。它是 Ruby 标准库的一部分,所以它已经内置,但我们仍然需要 require
它在你的 post.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. 中找到有关
link_changed?
方法是 "dirty tracking" 功能的一部分 ActiveModel::Dirty 提供- 那个
if: ->(post)
东西叫做 "stabby lambda" - 它基本上只是一个 Ruby 函数,用当前的post
作为参数调用。如果是returnstrue
,那么before_action
就是运行。也可以写成if: Proc.new { |post| post.link_changed? }
before_save
和其他回调的更多信息
现在我们需要 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 README,它有一个很酷的方法,叫做 page.images.best
,它为我们从该页面选择正确的图像做了艰苦的工作。所以我们要
- 使用 MetaInspector 解析 link
- 用
open-uri
打开它选择的最佳图像作为File
类对象 - 将类似
File
的对象提供给Paperclip
以另存为附件
所以:
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?)。此外,这还有一个缺点,即所有解析、下载等操作都在用户提交或更新她 post 时发生,因此当她单击保存按钮时,她将不得不等待所有这些操作完成完成。
对于下一次迭代,研究异步执行这些操作,例如使用作业队列。 Rails' 新的 Active Job 系统可能是一个很好的起点。