Headless Chrome Ruby API
It is Ruby clean and high-level API to Chrome. Runs headless by default, but you
can configure it to run in a headful mode. All you need is Ruby and
Chrome or
Chromium. Ferrum connects to the browser by CDP
protocol and there’s no
Selenium/WebDriver/ChromeDriver dependency. The emphasis was made on a raw CDP
protocol because Chrome allows you to do so many things that are barely
supported by WebDriver because it should have consistent design with other
browsers.
Cuprite is a pure Ruby driver for
Capybara based on Ferrum. If you are
going to crawl sites you better use Ferrum or
Vessel because you crawl, not test.
Vessel high-level web crawling framework
based on Ferrum and Mechanize.
The development is done in
provided by OSS license.
There’s no official Chrome or Chromium package for Linux don’t install it this
way because it’s either outdated or unofficial, both are bad. Download it from
official source for Chrome or
Chromium.
Chrome binary should be in the PATH
or BROWSER_PATH
and you can pass it as an
option to browser instance see :browser_path
in
Customization.
Add this to your Gemfile
and run bundle install
.
gem "ferrum"
Navigate to a website and save a screenshot:
browser = Ferrum::Browser.new
browser.go_to("https://google.com")
browser.screenshot(path: "google.png")
browser.quit
When you work with browser instance Ferrum creates and maintains a default page for you, in fact all the methods above
are sent to the page
instance that is created in the default_context
of the browser
instance. You can interact
with a page created manually and this is preferred:
browser = Ferrum::Browser.new
page = browser.create_page
page.go_to("https://google.com")
input = page.at_xpath("//input[@name='q']")
input.focus.type("Ruby headless driver for Chrome", :Enter)
page.at_css("a > h3").text # => "rubycdp/ferrum: Ruby Chrome/Chromium driver - GitHub"
browser.quit
Evaluate some JavaScript and get full width/height:
browser = Ferrum::Browser.new
page = browser.create_page
page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
width, height = page.evaluate <<~JS
[document.documentElement.offsetWidth,
document.documentElement.offsetHeight]
JS
# => [1024, 1931]
browser.quit
Do any mouse movements you like:
# Trace a 100x100 square
browser = Ferrum::Browser.new
page = browser.create_page
page.go_to("https://google.com")
page.mouse
.move(x: 0, y: 0)
.down
.move(x: 0, y: 100)
.move(x: 100, y: 100)
.move(x: 100, y: 0)
.move(x: 0, y: 0)
.up
browser.quit
In docker as root you must pass the no-sandbox browser option:
Ferrum::Browser.new(browser_options: { 'no-sandbox': nil })
It has also been reported that the Chrome process repeatedly crashes when running inside a Docker container on an M1 Mac preventing Ferrum from working. Ferrum should work as expected when deployed to a Docker container on a non-M1 Mac.
You can customize options with the following code in your test setup:
Ferrum::Browser.new(options)
Hash
:headless
(String | Boolean) - Set browser as headless or not, true
by default. You can set "new"
to support:xvfb
(Boolean) - Run browser in a virtual framebuffer, false
by default.:flatten
(Boolean) - Use one websocket connection to the browser and all the pages in flatten mode.:window_size
(Array) - The dimensions of the browser window in which to:extensions
(Array[String | Hash]) - An array of paths to files or JS["/path/to/script.js", { source: "window.secret = 'top'" }]
:logger
(Object responding to puts
) - When present, debug output is:slowmo
(Integer | Float) - Set a delay in seconds to wait before sending command.:timeout
(Numeric) - The number of seconds we’ll wait for a response when:js_errors
(Boolean) - When true, JavaScript errors get re-raised in Ruby.:pending_connection_errors
(Boolean) - When main frame is still waiting for slow responses while timeout isPendingConnectionsError
is raised. It’s better to figure out why you have slow responses and fix or:browser_name
(Symbol) - :chrome
by default, only experimental support:firefox
for now.:browser_path
(String) - Path to Chrome binary, you can also set ENVBROWSER_PATH=some/path/chrome bundle exec rspec
.:browser_options
(Hash) - Additional command line options,{ "ignore-certificate-errors" => nil }
:ignore_default_browser_options
(Boolean) - Ferrum has a number of defaulttrue
then only:browser_options
will be passed to the browser,:port
(Integer) - Remote debugging port for headless Chrome.:host
(String) - Remote debugging address for headless Chrome.:url
(String) - URL for a running instance of Chrome. If this is set, a:ws_url
(String) - Websocket url for a running instance of Chrome. If this is set, a:url
, setting both doesn’t make sense.:process_timeout
(Integer) - How long to wait for the Chrome process to:ws_max_receive_size
(Integer) - How big messages to accept from ChromeFerrum::DeadBrowserError
.:proxy
(Hash) - Specify proxy settings, read more:save_path
(String) - Path to save attachments with Content-Disposition header.:env
(Hash) - Environment variables you’d like to pass through to the processString
Navigate page to.
String
The url should include scheme unless you set base_url
whenpage.go_to("https://github.com/")
Navigate to the previous page in history.
page.go_to("https://github.com/")
page.at_xpath("//a").click
page.back
Navigate to the next page in history.
page.go_to("https://github.com/")
page.at_xpath("//a").click
page.back
page.forward
Reload current page.
page.go_to("https://github.com/")
page.refresh
Stop all navigations and loading pending resources on the page
page.go_to("https://github.com/")
page.stop
Set the position for the browser window
Hash
Integer
Integer
browser.position = { left: 10, top: 20 }
Array<Integer>
Get the position for the browser window
browser.position # => [10, 20]
Set window bounds
Hash
Integer
Integer
Integer
Integer
String
browser.window_bounds = { left: 10, top: 20, width: 1024, height: 768, window_state: "normal" }
Hash<String, Integer | String>
Get window bounds
browser.window_bounds # => { "left": 0, "top": 1286, "width": 10, "height": 10, "windowState": "normal" }
Integer
Current window id
browser.window_id # => 1
Node
| nil
Find node by selector. Runs document.querySelector
within the document or
provided node.
String
Hash
Node
| nil
page.go_to("https://github.com/")
page.at_css("a[aria-label='Issues you created']") # => Node
Array<Node>
| []
Find nodes by selector. The method runs document.querySelectorAll
within the
document or provided node.
String
Hash
Node
| nil
page.go_to("https://github.com/")
page.css("a[aria-label='Issues you created']") # => [Node]
Node
| nil
Find node by xpath.
String
Hash
Node
| nil
page.go_to("https://github.com/")
page.at_xpath("//a[@aria-label='Issues you created']") # => Node
Array<Node>
| []
Find nodes by xpath.
String
Hash
Node
| nil
page.go_to("https://github.com/")
page.xpath("//a[@aria-label='Issues you created']") # => [Node]
String
Returns current top window location href.
page.go_to("https://google.com/")
page.current_url # => "https://www.google.com/"
String
Returns current top window title
page.go_to("https://google.com/")
page.current_title # => "Google"
String
Returns current page’s html.
page.go_to("https://google.com/")
page.body # => '<html itemscope="" itemtype="http://schema.org/WebPage" lang="ru"><head>...
String
| Integer
Saves screenshot on a disk or returns it as base64.
Hash
String
to save a screenshot on the disk. :encoding
will be set to:binary
automaticallySymbol
:base64
| :binary
you can set it to return image asString
“jpeg” (“jpg”) | “png” | “webp”Integer
0-100 works for jpeg onlyBoolean
whether you need full page screenshot or a viewportString
css selector for given element, optionalHash
area for screenshot, optional
Integer
Integer
Integer
Integer
Float
zoom in/outFerrum::RGBA.new(0, 0, 0, 0.0)
to have specific background colorpage.go_to("https://google.com/")
# Save on the disk in PNG
page.screenshot(path: "google.png") # => 134660
# Save on the disk in JPG
page.screenshot(path: "google.jpg") # => 30902
# Save to Base64 the whole page not only viewport and reduce quality
page.screenshot(full: true, quality: 60, encoding: :base64) # "iVBORw0KGgoAAAANSUhEUgAABAAAAAMACAYAAAC6uhUNAAAAAXNSR0IArs4c6Q...
# Save on the disk with the selected element in PNG
page.screenshot(path: "google.png", selector: 'textarea') # => 11340
# Save to Base64 with an area of the page in PNG
page.screenshot(path: "google.png", area: { x: 0, y: 0, width: 400, height: 300 }) # => 54239
# Save with specific background color
page.screenshot(background_color: Ferrum::RGBA.new(0, 0, 0, 0.0))
String
| Boolean
Saves PDF on a disk or returns it as base64.
Hash
:path String
to save a pdf on the disk. :encoding
will be set to
:binary
automatically
:encoding Symbol
:base64
| :binary
you can set it to return pdf as
Base64
:landscape Boolean
paper orientation. Defaults to false.
:scale Float
zoom in/out
:format symbol
standard paper sizes :letter, :legal, :tabloid, :ledger, :A0, :A1, :A2, :A3, :A4, :A5, :A6
:paper_width Float
set paper width
:paper_height Float
set paper height
See other native options you can pass
page.go_to("https://google.com/")
# Save to disk as a PDF
page.pdf(path: "google.pdf", paper_width: 1.0, paper_height: 1.0) # => true
String
| Integer
Saves MHTML on a disk or returns it as a string.
Hash
String
to save a file on the disk.page.go_to("https://google.com/")
page.mhtml(path: "google.mhtml") # => 87742
page.network
Array<Network::Exchange>
Returns all information about network traffic as Network::Exchange
instance
which in general is a wrapper around request
, response
and error
.
page.go_to("https://github.com/")
page.network.traffic # => [#<Ferrum::Network::Exchange, ...]
Network::Request
Page request of the main frame.
page.go_to("https://github.com/")
page.network.request # => #<Ferrum::Network::Request...
Network::Response
Page response of the main frame.
page.go_to("https://github.com/")
page.network.response # => #<Ferrum::Network::Response...
Integer
Contains the status code of the main page response (e.g., 200 for a
success). This is just a shortcut for response.status
.
page.go_to("https://github.com/")
page.network.status # => 200
Boolean
Waits for network idle, returns true
in case of success and false
if there are still connections.
Hash
Integer
how many connections are allowed for network to be0
by defaultFloat
sleep for given amount of time and check again, 0.05
byFloat
during what time we try to check idle, browser.timeout
page.go_to("https://example.com/")
page.at_xpath("//a[text() = 'No UI changes button']").click
page.network.wait_for_idle # => true
Waits for network idle or raises Ferrum::TimeoutError
error. Accepts same arguments as wait_for_idle
.
page.go_to("https://example.com/")
page.at_xpath("//a[text() = 'No UI changes button']").click
page.network.wait_for_idle! # might raise an error
Clear page’s cache or collected traffic.
Symbol
it is either :traffic
or :cache
traffic = page.network.traffic # => []
page.go_to("https://github.com/")
traffic.size # => 51
page.network.clear(:traffic)
traffic.size # => 0
Set request interception for given options. This method is only sets request
interception, you should use on
callback to catch requests and abort or
continue them.
Hash
String
* by defaultSymbol
one of the resource typesbrowser = Ferrum::Browser.new
page = browser.create_page
page.network.intercept
page.on(:request) do |request|
if request.match?(/bla-bla/)
request.abort
elsif request.match?(/lorem/)
request.respond(body: "Lorem ipsum")
else
request.continue
end
end
page.go_to("https://google.com")
If site or proxy uses authorization you can provide credentials using this method.
Hash
Symbol
:server
| :proxy
site or proxy authorizationString
String
request.continue
.page.network.authorize(user: "login", password: "pass") { |req| req.continue }
page.go_to("http://example.com/authenticated")
puts page.network.status # => 200
puts page.body # => Welcome, authenticated client
Since Chrome implements authorize using request interception you must continue or abort authorized requests. If you
already have code that uses interception you can use authorize
without block, but if not you are obliged to pass
block, so this is version doesn’t pass block and can work just fine:
browser = Ferrum::Browser.new
page = browser.create_page
page.network.intercept
page.on(:request) do |request|
if request.resource_type == "Image"
request.abort
else
request.continue
end
end
page.network.authorize(user: "login", password: "pass", type: :proxy)
page.go_to("https://google.com")
You used to call authorize
method without block, but since it’s implemented using request interception there could be
a collision with another part of your code that also uses request interception, so that authorize allows the request
while your code denies but it’s too late. The block is mandatory now.
Activates emulation of network conditions.
Hash
Boolean
emulate internet disconnection, false
by defaultInteger
minimum latency from request sent to response headers received (ms), 0
byInteger
maximal aggregated download throughput (bytes/sec), -1
Integer
maximal aggregated upload throughput (bytes/sec), -1
String
connection type if known, one of: none, cellular2g, cellular3g, cellular4g,nil
by defaultpage.network.emulate_network_conditions(connection_type: "cellular2g")
page.go_to("https://github.com/")
Activates offline mode for a page.
page.network.offline_mode
page.go_to("https://github.com/") # => Ferrum::StatusError (Request to https://github.com/ failed(net::ERR_INTERNET_DISCONNECTED))
Boolean
)Toggles ignoring cache for each request. If true, cache will not be used.
page.network.cache(disable: true)
page.downloads
Array<Hash>
Returns all information about downloaded files as a Hash
.
page.go_to("http://localhost/attachment.pdf")
page.downloads.files # => [{"frameId"=>"E3316DF1B5383D38F8ADF7485005FDE3", "guid"=>"11a68745-98ac-4d54-9b57-9f9016c268b3", "url"=>"http://localhost/attachment.pdf", "suggestedFilename"=>"attachment.pdf", "totalBytes"=>4911, "receivedBytes"=>4911, "state"=>"completed"}]
Waits until the download is finished.
page.go_to("http://localhost/attachment.pdf")
page.downloads.wait
or
page.go_to("http://localhost/page")
page.downloads.wait { page.at_css("#download").click }
Sets behavior in case of file to be downloaded.
Hash
String
absolute path of where to store the fileSymbol
deny | allow | allowAndName | default
, allow
by defaultpage.go_to("https://example.com/")
page.downloads.set_behavior(save_path: "/tmp", behavior: :allow)
You can set a proxy with a :proxy
option:
Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", user: "user", password: "pa$$" })
:bypass
can specify semi-colon-separated list of hosts for which proxy shouldn’t be used:
Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", bypass: "*.google.com;*foo.com" })
In general passing a proxy option when instantiating a browser results in a browser running with proxy command line
flags, so that it affects all pages and contexts. You can create a page in a new context which can use its own proxy
settings:
browser = Ferrum::Browser.new
browser.create_page(proxy: { host: "x.x.x.x", port: 31337, user: "user", password: "password" }) do |page|
page.go_to("https://api.ipify.org?format=json")
page.body # => "x.x.x.x"
end
browser.create_page(proxy: { host: "y.y.y.y", port: 31337, user: "user", password: "password" }) do |page|
page.go_to("https://api.ipify.org?format=json")
page.body # => "y.y.y.y"
end
page.mouse
Scroll page to a given x, y
Integer
the pixel along the horizontal axis of the document that youInteger
the pixel along the vertical axis of the document that you wantpage.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
page.mouse.scroll_to(0, 400)
Mouse
Click given coordinates, fires mouse move, down and up events.
Hash
Integer
Integer
Float
defaults to 0. Delay between mouse down and mouse up eventsSymbol
:left | :right, defaults to :leftInteger
defaults to 1Integer
bitfield for key modifiers. Seekeyboard.modifiers
Mouse
Mouse down for given coordinates.
Hash
Symbol
:left | :right, defaults to :leftInteger
defaults to 1Integer
bitfield for key modifiers. Seekeyboard.modifiers
Mouse
Mouse up for given coordinates.
Hash
Symbol
:left | :right, defaults to :leftInteger
defaults to 1Integer
bitfield for key modifiers. Seekeyboard.modifiers
Mouse
Mouse move to given x and y.
Hash
Integer
Integer
Integer
defaults to 1. Sends intermediate mousemove events.page.keyboard
Keyboard
Dispatches a keydown event.
String
| Symbol
Name of key such as “a”, :enter, :backspaceKeyboard
Dispatches a keyup event.
String
| Symbol
Name of key such as “b”, :enter, :backspaceKeyboard
Sends a keydown, keypress/input, and keyup event for each character in the text.
String
| Array<String> | Array<Symbol>
A text to type into a focused[:Shift, "s"], "tring"
Integer
Returns bitfield for a given keys
Array<Symbol>
:alt | :ctrl | :command | :shiftpage.cookies
Hash<String, Cookie>
Returns cookies hash
page.cookies.all # => {"NID"=>#<Ferrum::Cookies::Cookie:0x0000558624b37a40 @attributes={"name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/", "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false}>}
Cookie
Returns cookie
String
page.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88 @attributes={"name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/", "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false}>
Boolean
Sets a cookie
Hash
String
String
String
Integer
String
Boolean
page.cookies.set(name: "stealth", value: "omg", domain: "google.com") # => true
Cookie
nid_cookie = page.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88>
page.cookies.set(nid_cookie) # => true
Boolean
Removes given cookie
Hash
String
String
String
page.cookies.remove(name: "stealth", domain: "google.com") # => true
Boolean
Removes all cookies for current page
page.cookies.clear # => true
Boolean
Stores all cookies of current page in a file.
# Cookies are saved into cookies.yml
page.cookies.store # => 15657
Boolean
Loads all cookies from the file and sets them for current page.
# Cookies are loaded from cookies.yml
page.cookies.load # => true
page.headers
Hash
Get all headers
Boolean
Set given headers. Eventually clear all headers and set given ones.
Hash
key-value pairs for example "User-Agent" => "Browser"
Boolean
Adds given headers to already set ones.
Hash
key-value pairs for example "Referer" => "http://example.com"
Boolean
Clear all headers.
Evaluate and return result for given JS expression
String
should be valid JavaScriptObject
you can pass arguments, though it should be a valid Node
or apage.evaluate("[window.scrollX, window.scrollY]")
Evaluate asynchronous expression and return result
String
should be valid JavaScriptObject
you can pass arguments, though it should be a valid Node
or apage.evaluate_async(%(arguments[0]({foo: "bar"})), 5) # => { "foo" => "bar" }
Execute expression. Doesn’t return the result
String
should be valid JavaScriptObject
you can pass arguments, though it should be a valid Node
or apage.execute(%(1 + 1)) # => true
Evaluate JavaScript to modify things before a page load
String
should be valid JavaScriptbrowser.evaluate_on_new_document <<~JS
Object.defineProperty(navigator, "languages", {
get: function() { return ["tlh"]; }
});
JS
Boolean
Hash
String
String
String
String
- text/javascript
by defaultpage.add_script_tag(url: "http://example.com/stylesheet.css") # => true
Boolean
Hash
String
String
String
page.add_style_tag(content: "h1 { font-size: 40px; }") # => true
Boolean
Hash
Boolean
, true
by defaultpage.bypass_csp # => true
page.go_to("https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md")
page.refresh
page.add_script_tag(content: "window.__injected = 42")
page.evaluate("window.__injected") # => 42
Disables Javascripts from the loaded HTML source.
You can still evaluate JavaScript with evaluate
or execute
.
Returns nothing.
page.disable_javascript
Overrides device screen dimensions and emulates viewport.
Hash
Integer
, viewport width. 0
by defaultInteger
, viewport height. 0
by defaultFloat
, device scale factor. 0
by defaultBoolean
, whether to emulate mobile device. false
by defaultpage.set_viewport(width: 1000, height: 600, scale_factor: 3)
Array[Frame] | []
Returns all the frames current page have.
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
page.frames # =>
# [
# #<Ferrum::Frame @id="C6D104CE454A025FBCF22B98DE612B12" @parent_id=nil @name=nil @state=:stopped_loading @execution_id=1>,
# #<Ferrum::Frame @id="C09C4E4404314AAEAE85928EAC109A93" @parent_id="C6D104CE454A025FBCF22B98DE612B12" @state=:stopped_loading @execution_id=2>,
# #<Ferrum::Frame @id="2E9C7F476ED09D87A42F2FEE3C6FBC3C" @parent_id="C6D104CE454A025FBCF22B98DE612B12" @state=:stopped_loading @execution_id=3>,
# ...
# ]
Frame
Returns page’s main frame, the top of the tree and the parent of all frames.
Frame | nil
Find frame by given options.
Hash
String
- Unique frame’s id that browser providesString
- Frame’s name if there’s onepage.frame_by(id: "C6D104CE454A025FBCF22B98DE612B12")
String
Frame’s unique id.
String | nil
Parent frame id if this one is nested in another one.
Integer
Execution context id which is used by JS, each frame has it’s own context in
which JS evaluates.
String | nil
If frame was given a name it should be here.
Symbol | nil
One of the states frame’s in:
:started_loading
:navigated
:stopped_loading
String
Returns current frame’s location href.
page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
frame = page.frames[1]
frame.url # => https://interactive-examples.mdn.mozilla.net/pages/tabbed/iframe.html
Returns current frame’s title.
page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
frame = page.frames[1]
frame.title # => HTML Demo: <iframe>
Boolean
If current frame is the main frame of the page (top of the tree).
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
frame.main? # => false
String
Returns current frame’s top window location href.
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
frame.current_url # => "https://www.w3schools.com/tags/tag_frame.asp"
String
Returns current frame’s top window title.
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
frame.current_title # => "HTML frame tag"
String
Returns current frame’s html.
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
frame.body # => "<html><head></head><body></body></html>"
Returns current frame’s doctype.
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
page.main_frame.doctype # => "<!DOCTYPE html>"
Sets a content of a given frame.
String
page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
frame = page.frames[1]
frame.body # <html lang="en"><head><style>body {transition: opacity ease-in 0.2s; }...
frame.content = "<html><head></head><body><p>lol</p></body></html>"
frame.body # => <html><head></head><body><p>lol</p></body></html>
Accept dialog with given text or default prompt if applicable
String
Dismiss dialog
page.on(:dialog) do |dialog|
if dialog.match?(/bla-bla/)
dialog.accept
else
dialog.dismiss
end
end
page.go_to("https://google.com")
You can slow down or speed up CSS animations.
Integer
Returns playback rate for CSS animations, defaults to 1
.
Sets playback rate of CSS animations
Integer
page.playback_rate = 2000
page.go_to("https://google.com")
page.playback_rate # => 2000
Boolean
Frame
Returns Frame object for current node, you can keep using
Finders for that object:
frame = page.at_xpath("//iframe").frame # => Frame
frame.at_css("//a[text() = 'Log in']") # => Node
Boolean
Array<Node>
Node | nil
) : Boolean
(chainable) Selects options by passed attribute.
page.at_xpath("//*[select]").select(["1"]) # => Node (select)
page.at_xpath("//*[select]").select(["text"], by: :text) # => Node (select)
Accept string, array or strings:
page.at_xpath("//*[select]").select("1")
page.at_xpath("//*[select]").select("1", "2")
page.at_xpath("//*[select]").select(["1", "2"])
You can use tracing.record
to create a trace file which can be opened in Chrome DevTools or
timeline viewer.
page.tracing.record(path: "trace.json") do
page.go_to("https://www.google.com")
end
String
Accepts block, records trace and by default returns trace data from Tracing.tracingComplete
event as output. When
path
is specified returns true
and stores trace data into file.
Hash
String
save data on the disk, nil
by defaultSymbol
:base64
| :binary
encode output as Base64 or plain text. :binary
by defaultFloat
wait until file streaming finishes in the specified time or raise error, defaults to nil
Boolean
capture screenshots in the trace, false
by defaultHash<String, Object>
config forCloses browser tabs opened by the Browser
instance.
# connect to a long-running Chrome process
browser = Ferrum::Browser.new(url: 'http://localhost:9222')
browser.go_to("https://github.com/")
# clean up, lest the tab stays there hanging forever
browser.reset
browser.quit
Ferrum is fully thread-safe. You can create one browser or a few as you wish and
start playing around using threads. Example below shows how to create a few pages
which share the same context. Context is similar to an incognito profile but you
can have more than one, think of it like it’s independent browser session:
browser = Ferrum::Browser.new
context = browser.contexts.create
t1 = Thread.new(context) do |c|
page = c.create_page
page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
page.screenshot(path: "t1.png")
end
t2 = Thread.new(context) do |c|
page = c.create_page
page.go_to("https://www.google.com/search?q=Ruby+static+typing")
page.screenshot(path: "t2.png")
end
t1.join
t2.join
context.dispose
browser.quit
or you can create two independent contexts:
browser = Ferrum::Browser.new
t1 = Thread.new(browser) do |b|
context = b.contexts.create
page = context.create_page
page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
page.screenshot(path: "t1.png")
context.dispose
end
t2 = Thread.new(browser) do |b|
context = b.contexts.create
page = context.create_page
page.go_to("https://www.google.com/search?q=Ruby+static+typing")
page.screenshot(path: "t2.png")
context.dispose
end
t1.join
t2.join
browser.quit
After checking out the repo, run bundle install
to install dependencies.
Then, run bundle exec rake test
to run the tests. You can also run bin/console
for an interactive prompt that will
allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the
version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version,
push git commits and the created tag, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub.
The gem is available as open source under the terms of the
MIT License.