Fields
Instead of building a hash by hand a handler can declare fields and yield the
collected fields object.
field(name, **options, &block)
- options
Hash- :value
Objectvalue of the field - :service
Booleankeeps the field out of the resulting hash, it's only available asfields.service[:name]in the middleware - :rename
Hashstores the field under another name, e.g.{ "author" => :writer } - :typing
Booleanfalseskips the field type
- :value
- block - called instead of
valuewhen it's given
fields : Vessel::Cargo::Fields
Fields collected in the handler, fields.to_h returns them as a Hash.
class MyScraper < Vessel::Cargo
def parse
field :author, value: at_xpath("span/small").text
field :text, value: at_css("span.text").text
field :html, value: nil, service: true do
raw
end
yield fields
end
end
The middleware gets { author: ..., text: ... } as the hash and the fields
object with fields.service[:html].
Field types
Fields can be normalized in one place by their name. Put such declarations into
config/fields of a generated project:
Vessel::Cargo::FieldType.add(:price) { |value| value.to_s.gsub(/[^\d.]/, "").to_f }
Vessel::Cargo::FieldType.add(:title, :name) { |value| value.to_s.strip }
Every field :price is then passed through that block, typing: false skips
it. The type is looked up by the final name, after rename. The block is
evaluated in the crawler instance, so url, data and the selectors are
available in it.