ferrum 0.14 → 0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +277 -154
- data/lib/ferrum/browser/command.rb +4 -0
- data/lib/ferrum/browser/options/chrome.rb +8 -3
- data/lib/ferrum/browser/options.rb +38 -25
- data/lib/ferrum/browser/process.rb +43 -16
- data/lib/ferrum/browser.rb +26 -50
- data/lib/ferrum/client/subscriber.rb +76 -0
- data/lib/ferrum/{browser → client}/web_socket.rb +35 -21
- data/lib/ferrum/client.rb +169 -0
- data/lib/ferrum/context.rb +19 -15
- data/lib/ferrum/contexts.rb +46 -12
- data/lib/ferrum/cookies.rb +1 -1
- data/lib/ferrum/downloads.rb +60 -0
- data/lib/ferrum/errors.rb +2 -1
- data/lib/ferrum/headers.rb +1 -1
- data/lib/ferrum/network/exchange.rb +10 -1
- data/lib/ferrum/network/intercepted_request.rb +5 -5
- data/lib/ferrum/network/request.rb +9 -0
- data/lib/ferrum/network.rb +11 -9
- data/lib/ferrum/page/frames.rb +5 -5
- data/lib/ferrum/page/screenshot.rb +36 -24
- data/lib/ferrum/page.rb +177 -119
- data/lib/ferrum/proxy.rb +1 -1
- data/lib/ferrum/target.rb +25 -5
- data/lib/ferrum/utils/elapsed_time.rb +0 -2
- data/lib/ferrum/utils/event.rb +19 -0
- data/lib/ferrum/utils/platform.rb +4 -0
- data/lib/ferrum/utils/thread.rb +18 -0
- data/lib/ferrum/version.rb +1 -1
- data/lib/ferrum.rb +3 -0
- metadata +14 -17
- data/lib/ferrum/browser/client.rb +0 -103
- data/lib/ferrum/browser/subscriber.rb +0 -36
data/README.md
CHANGED
@@ -25,6 +25,8 @@ going to crawl sites you better use Ferrum or
|
|
25
25
|
* [Vessel](https://github.com/rubycdp/vessel) high-level web crawling framework
|
26
26
|
based on Ferrum and Mechanize.
|
27
27
|
|
28
|
+
The development is done in [![RubyMine](https://resources.jetbrains.com/storage/products/company/brand/logos/RubyMine_icon.svg?width=10px)](https://jb.gg/ruby)
|
29
|
+
provided by [OSS license](https://jb.gg/OpenSourceSupport).
|
28
30
|
|
29
31
|
## Index
|
30
32
|
|
@@ -35,8 +37,8 @@ based on Ferrum and Mechanize.
|
|
35
37
|
* [Navigation](https://github.com/rubycdp/ferrum#navigation)
|
36
38
|
* [Finders](https://github.com/rubycdp/ferrum#finders)
|
37
39
|
* [Screenshots](https://github.com/rubycdp/ferrum#screenshots)
|
38
|
-
* [Cleaning Up](https://github.com/rubycdp/ferrum#cleaning-up)
|
39
40
|
* [Network](https://github.com/rubycdp/ferrum#network)
|
41
|
+
* [Downloads](https://github.com/rubycdp/ferrum#downloads)
|
40
42
|
* [Proxy](https://github.com/rubycdp/ferrum#proxy)
|
41
43
|
* [Mouse](https://github.com/rubycdp/ferrum#mouse)
|
42
44
|
* [Keyboard](https://github.com/rubycdp/ferrum#keyboard)
|
@@ -49,6 +51,7 @@ based on Ferrum and Mechanize.
|
|
49
51
|
* [Animation](https://github.com/rubycdp/ferrum#animation)
|
50
52
|
* [Node](https://github.com/rubycdp/ferrum#node)
|
51
53
|
* [Tracing](https://github.com/rubycdp/ferrum#tracing)
|
54
|
+
* [Clean Up](https://github.com/rubycdp/ferrum#clean-up)
|
52
55
|
* [Thread safety](https://github.com/rubycdp/ferrum#thread-safety)
|
53
56
|
* [Development](https://github.com/rubycdp/ferrum#development)
|
54
57
|
* [Contributing](https://github.com/rubycdp/ferrum#contributing)
|
@@ -61,7 +64,7 @@ There's no official Chrome or Chromium package for Linux don't install it this
|
|
61
64
|
way because it's either outdated or unofficial, both are bad. Download it from
|
62
65
|
official source for [Chrome](https://www.google.com/chrome/) or
|
63
66
|
[Chromium](https://www.chromium.org/getting-involved/download-chromium).
|
64
|
-
Chrome binary should be in the `PATH` or `BROWSER_PATH`
|
67
|
+
Chrome binary should be in the `PATH` or `BROWSER_PATH` and you can pass it as an
|
65
68
|
option to browser instance see `:browser_path` in
|
66
69
|
[Customization](https://github.com/rubycdp/ferrum#customization).
|
67
70
|
|
@@ -83,14 +86,17 @@ browser.screenshot(path: "google.png")
|
|
83
86
|
browser.quit
|
84
87
|
```
|
85
88
|
|
86
|
-
|
89
|
+
When you work with browser instance Ferrum creates and maintains a default page for you, in fact all the methods above
|
90
|
+
are sent to the `page` instance that is created in the `default_context` of the `browser` instance. You can interact
|
91
|
+
with a page created manually and this is preferred:
|
87
92
|
|
88
93
|
```ruby
|
89
94
|
browser = Ferrum::Browser.new
|
90
|
-
browser.
|
91
|
-
|
95
|
+
page = browser.create_page
|
96
|
+
page.go_to("https://google.com")
|
97
|
+
input = page.at_xpath("//input[@name='q']")
|
92
98
|
input.focus.type("Ruby headless driver for Chrome", :Enter)
|
93
|
-
|
99
|
+
page.at_css("a > h3").text # => "rubycdp/ferrum: Ruby Chrome/Chromium driver - GitHub"
|
94
100
|
browser.quit
|
95
101
|
```
|
96
102
|
|
@@ -98,8 +104,9 @@ Evaluate some JavaScript and get full width/height:
|
|
98
104
|
|
99
105
|
```ruby
|
100
106
|
browser = Ferrum::Browser.new
|
101
|
-
browser.
|
102
|
-
|
107
|
+
page = browser.create_page
|
108
|
+
page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
|
109
|
+
width, height = page.evaluate <<~JS
|
103
110
|
[document.documentElement.offsetWidth,
|
104
111
|
document.documentElement.offsetHeight]
|
105
112
|
JS
|
@@ -112,8 +119,9 @@ Do any mouse movements you like:
|
|
112
119
|
```ruby
|
113
120
|
# Trace a 100x100 square
|
114
121
|
browser = Ferrum::Browser.new
|
115
|
-
browser.
|
116
|
-
|
122
|
+
page = browser.create_page
|
123
|
+
page.go_to("https://google.com")
|
124
|
+
page.mouse
|
117
125
|
.move(x: 0, y: 0)
|
118
126
|
.down
|
119
127
|
.move(x: 0, y: 100)
|
@@ -148,6 +156,7 @@ Ferrum::Browser.new(options)
|
|
148
156
|
* `:headless` (String | Boolean) - Set browser as headless or not, `true` by default. You can set `"new"` to support
|
149
157
|
[new headless mode](https://developer.chrome.com/articles/new-headless/).
|
150
158
|
* `:xvfb` (Boolean) - Run browser in a virtual framebuffer, `false` by default.
|
159
|
+
* `:flatten` (Boolean) - Use one websocket connection to the browser and all the pages in flatten mode.
|
151
160
|
* `:window_size` (Array) - The dimensions of the browser window in which to
|
152
161
|
test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
|
153
162
|
* `:extensions` (Array[String | Hash]) - An array of paths to files or JS
|
@@ -178,6 +187,8 @@ Ferrum::Browser.new(options)
|
|
178
187
|
* `:host` (String) - Remote debugging address for headless Chrome.
|
179
188
|
* `:url` (String) - URL for a running instance of Chrome. If this is set, a
|
180
189
|
browser process will not be spawned.
|
190
|
+
* `:ws_url` (String) - Websocket url for a running instance of Chrome. If this is set, a
|
191
|
+
browser process will not be spawned.
|
181
192
|
* `:process_timeout` (Integer) - How long to wait for the Chrome process to
|
182
193
|
respond on startup.
|
183
194
|
* `:ws_max_receive_size` (Integer) - How big messages to accept from Chrome
|
@@ -198,7 +209,7 @@ Navigate page to.
|
|
198
209
|
configuring driver.
|
199
210
|
|
200
211
|
```ruby
|
201
|
-
|
212
|
+
page.go_to("https://github.com/")
|
202
213
|
```
|
203
214
|
|
204
215
|
#### back
|
@@ -206,9 +217,9 @@ browser.go_to("https://github.com/")
|
|
206
217
|
Navigate to the previous page in history.
|
207
218
|
|
208
219
|
```ruby
|
209
|
-
|
210
|
-
|
211
|
-
|
220
|
+
page.go_to("https://github.com/")
|
221
|
+
page.at_xpath("//a").click
|
222
|
+
page.back
|
212
223
|
```
|
213
224
|
|
214
225
|
#### forward
|
@@ -216,10 +227,10 @@ browser.back
|
|
216
227
|
Navigate to the next page in history.
|
217
228
|
|
218
229
|
```ruby
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
230
|
+
page.go_to("https://github.com/")
|
231
|
+
page.at_xpath("//a").click
|
232
|
+
page.back
|
233
|
+
page.forward
|
223
234
|
```
|
224
235
|
|
225
236
|
#### refresh
|
@@ -227,8 +238,8 @@ browser.forward
|
|
227
238
|
Reload current page.
|
228
239
|
|
229
240
|
```ruby
|
230
|
-
|
231
|
-
|
241
|
+
page.go_to("https://github.com/")
|
242
|
+
page.refresh
|
232
243
|
```
|
233
244
|
|
234
245
|
#### stop
|
@@ -236,8 +247,8 @@ browser.refresh
|
|
236
247
|
Stop all navigations and loading pending resources on the page
|
237
248
|
|
238
249
|
```ruby
|
239
|
-
|
240
|
-
|
250
|
+
page.go_to("https://github.com/")
|
251
|
+
page.stop
|
241
252
|
```
|
242
253
|
|
243
254
|
#### position = \*\*options
|
@@ -260,6 +271,37 @@ Get the position for the browser window
|
|
260
271
|
browser.position # => [10, 20]
|
261
272
|
```
|
262
273
|
|
274
|
+
#### window_bounds = \*\*options
|
275
|
+
|
276
|
+
Set window bounds
|
277
|
+
|
278
|
+
* options `Hash`
|
279
|
+
* :left `Integer`
|
280
|
+
* :top `Integer`
|
281
|
+
* :width `Integer`
|
282
|
+
* :height `Integer`
|
283
|
+
* :window_state `String`
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
browser.window_bounds = { left: 10, top: 20, width: 1024, height: 768, window_state: "normal" }
|
287
|
+
```
|
288
|
+
|
289
|
+
#### window_bounds : `Hash<String, Integer | String>`
|
290
|
+
|
291
|
+
Get window bounds
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
browser.window_bounds # => { "left": 0, "top": 1286, "width": 10, "height": 10, "windowState": "normal" }
|
295
|
+
```
|
296
|
+
|
297
|
+
#### window_id : `Integer`
|
298
|
+
|
299
|
+
Current window id
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
browser.window_id # => 1
|
303
|
+
```
|
304
|
+
|
263
305
|
## Finders
|
264
306
|
|
265
307
|
#### at_css(selector, \*\*options) : `Node` | `nil`
|
@@ -272,8 +314,8 @@ provided node.
|
|
272
314
|
* :within `Node` | `nil`
|
273
315
|
|
274
316
|
```ruby
|
275
|
-
|
276
|
-
|
317
|
+
page.go_to("https://github.com/")
|
318
|
+
page.at_css("a[aria-label='Issues you created']") # => Node
|
277
319
|
```
|
278
320
|
|
279
321
|
|
@@ -287,8 +329,8 @@ document or provided node.
|
|
287
329
|
* :within `Node` | `nil`
|
288
330
|
|
289
331
|
```ruby
|
290
|
-
|
291
|
-
|
332
|
+
page.go_to("https://github.com/")
|
333
|
+
page.css("a[aria-label='Issues you created']") # => [Node]
|
292
334
|
```
|
293
335
|
|
294
336
|
#### at_xpath(selector, \*\*options) : `Node` | `nil`
|
@@ -300,8 +342,8 @@ Find node by xpath.
|
|
300
342
|
* :within `Node` | `nil`
|
301
343
|
|
302
344
|
```ruby
|
303
|
-
|
304
|
-
|
345
|
+
page.go_to("https://github.com/")
|
346
|
+
page.at_xpath("//a[@aria-label='Issues you created']") # => Node
|
305
347
|
```
|
306
348
|
|
307
349
|
#### xpath(selector, \*\*options) : `Array<Node>` | `[]`
|
@@ -313,8 +355,8 @@ Find nodes by xpath.
|
|
313
355
|
* :within `Node` | `nil`
|
314
356
|
|
315
357
|
```ruby
|
316
|
-
|
317
|
-
|
358
|
+
page.go_to("https://github.com/")
|
359
|
+
page.xpath("//a[@aria-label='Issues you created']") # => [Node]
|
318
360
|
```
|
319
361
|
|
320
362
|
#### current_url : `String`
|
@@ -322,8 +364,8 @@ browser.xpath("//a[@aria-label='Issues you created']") # => [Node]
|
|
322
364
|
Returns current top window location href.
|
323
365
|
|
324
366
|
```ruby
|
325
|
-
|
326
|
-
|
367
|
+
page.go_to("https://google.com/")
|
368
|
+
page.current_url # => "https://www.google.com/"
|
327
369
|
```
|
328
370
|
|
329
371
|
#### current_title : `String`
|
@@ -331,8 +373,8 @@ browser.current_url # => "https://www.google.com/"
|
|
331
373
|
Returns current top window title
|
332
374
|
|
333
375
|
```ruby
|
334
|
-
|
335
|
-
|
376
|
+
page.go_to("https://google.com/")
|
377
|
+
page.current_title # => "Google"
|
336
378
|
```
|
337
379
|
|
338
380
|
#### body : `String`
|
@@ -340,8 +382,8 @@ browser.current_title # => "Google"
|
|
340
382
|
Returns current page's html.
|
341
383
|
|
342
384
|
```ruby
|
343
|
-
|
344
|
-
|
385
|
+
page.go_to("https://google.com/")
|
386
|
+
page.body # => '<html itemscope="" itemtype="http://schema.org/WebPage" lang="ru"><head>...
|
345
387
|
```
|
346
388
|
|
347
389
|
|
@@ -359,20 +401,29 @@ Saves screenshot on a disk or returns it as base64.
|
|
359
401
|
* :format `String` "jpeg" | "png"
|
360
402
|
* :quality `Integer` 0-100 works for jpeg only
|
361
403
|
* :full `Boolean` whether you need full page screenshot or a viewport
|
362
|
-
* :selector `String` css selector for given element
|
404
|
+
* :selector `String` css selector for given element, optional
|
405
|
+
* :area `Hash` area for screenshot, optional
|
406
|
+
* :x `Integer`
|
407
|
+
* :y `Integer`
|
408
|
+
* :width `Integer`
|
409
|
+
* :height `Integer`
|
363
410
|
* :scale `Float` zoom in/out
|
364
411
|
* :background_color `Ferrum::RGBA.new(0, 0, 0, 0.0)` to have specific background color
|
365
412
|
|
366
413
|
```ruby
|
367
|
-
|
414
|
+
page.go_to("https://google.com/")
|
368
415
|
# Save on the disk in PNG
|
369
|
-
|
416
|
+
page.screenshot(path: "google.png") # => 134660
|
370
417
|
# Save on the disk in JPG
|
371
|
-
|
418
|
+
page.screenshot(path: "google.jpg") # => 30902
|
372
419
|
# Save to Base64 the whole page not only viewport and reduce quality
|
373
|
-
|
420
|
+
page.screenshot(full: true, quality: 60, encoding: :base64) # "iVBORw0KGgoAAAANSUhEUgAABAAAAAMACAYAAAC6uhUNAAAAAXNSR0IArs4c6Q...
|
421
|
+
# Save on the disk with the selected element in PNG
|
422
|
+
page.screenshot(path: "google.png", selector: 'textarea') # => 11340
|
423
|
+
# Save to Base64 with an area of the page in PNG
|
424
|
+
page.screenshot(path: "google.png", area: { x: 0, y: 0, width: 400, height: 300 }) # => 54239
|
374
425
|
# Save with specific background color
|
375
|
-
|
426
|
+
page.screenshot(background_color: Ferrum::RGBA.new(0, 0, 0, 0.0))
|
376
427
|
```
|
377
428
|
|
378
429
|
#### pdf(\*\*options) : `String` | `Boolean`
|
@@ -393,9 +444,9 @@ Saves PDF on a disk or returns it as base64.
|
|
393
444
|
* See other [native options](https://chromedevtools.github.io/devtools-protocol/tot/Page#method-printToPDF) you can pass
|
394
445
|
|
395
446
|
```ruby
|
396
|
-
|
447
|
+
page.go_to("https://google.com/")
|
397
448
|
# Save to disk as a PDF
|
398
|
-
|
449
|
+
page.pdf(path: "google.pdf", paper_width: 1.0, paper_height: 1.0) # => true
|
399
450
|
```
|
400
451
|
|
401
452
|
#### mhtml(\*\*options) : `String` | `Integer`
|
@@ -406,33 +457,14 @@ Saves MHTML on a disk or returns it as a string.
|
|
406
457
|
* :path `String` to save a file on the disk.
|
407
458
|
|
408
459
|
```ruby
|
409
|
-
|
410
|
-
|
411
|
-
```
|
412
|
-
|
413
|
-
|
414
|
-
## Cleaning Up
|
415
|
-
|
416
|
-
#### reset
|
417
|
-
|
418
|
-
Closes browser tabs opened by the `Browser` instance.
|
419
|
-
|
420
|
-
```ruby
|
421
|
-
# connect to a long-running Chrome process
|
422
|
-
browser = Ferrum::Browser.new(url: 'http://localhost:9222')
|
423
|
-
|
424
|
-
browser.go_to("https://github.com/")
|
425
|
-
|
426
|
-
# clean up, lest the tab stays there hanging forever
|
427
|
-
browser.reset
|
428
|
-
|
429
|
-
browser.quit
|
460
|
+
page.go_to("https://google.com/")
|
461
|
+
page.mhtml(path: "google.mhtml") # => 87742
|
430
462
|
```
|
431
463
|
|
432
464
|
|
433
465
|
## Network
|
434
466
|
|
435
|
-
`
|
467
|
+
`page.network`
|
436
468
|
|
437
469
|
#### traffic `Array<Network::Exchange>`
|
438
470
|
|
@@ -440,8 +472,8 @@ Returns all information about network traffic as `Network::Exchange` instance
|
|
440
472
|
which in general is a wrapper around `request`, `response` and `error`.
|
441
473
|
|
442
474
|
```ruby
|
443
|
-
|
444
|
-
|
475
|
+
page.go_to("https://github.com/")
|
476
|
+
page.network.traffic # => [#<Ferrum::Network::Exchange, ...]
|
445
477
|
```
|
446
478
|
|
447
479
|
#### request : `Network::Request`
|
@@ -449,8 +481,8 @@ browser.network.traffic # => [#<Ferrum::Network::Exchange, ...]
|
|
449
481
|
Page request of the main frame.
|
450
482
|
|
451
483
|
```ruby
|
452
|
-
|
453
|
-
|
484
|
+
page.go_to("https://github.com/")
|
485
|
+
page.network.request # => #<Ferrum::Network::Request...
|
454
486
|
```
|
455
487
|
|
456
488
|
#### response : `Network::Response`
|
@@ -458,8 +490,8 @@ browser.network.request # => #<Ferrum::Network::Request...
|
|
458
490
|
Page response of the main frame.
|
459
491
|
|
460
492
|
```ruby
|
461
|
-
|
462
|
-
|
493
|
+
page.go_to("https://github.com/")
|
494
|
+
page.network.response # => #<Ferrum::Network::Response...
|
463
495
|
```
|
464
496
|
|
465
497
|
#### status : `Integer`
|
@@ -468,8 +500,8 @@ Contains the status code of the main page response (e.g., 200 for a
|
|
468
500
|
success). This is just a shortcut for `response.status`.
|
469
501
|
|
470
502
|
```ruby
|
471
|
-
|
472
|
-
|
503
|
+
page.go_to("https://github.com/")
|
504
|
+
page.network.status # => 200
|
473
505
|
```
|
474
506
|
|
475
507
|
#### wait_for_idle(\*\*options)
|
@@ -485,22 +517,22 @@ Waits for network idle or raises `Ferrum::TimeoutError` error
|
|
485
517
|
by default
|
486
518
|
|
487
519
|
```ruby
|
488
|
-
|
489
|
-
|
490
|
-
|
520
|
+
page.go_to("https://example.com/")
|
521
|
+
page.at_xpath("//a[text() = 'No UI changes button']").click
|
522
|
+
page.network.wait_for_idle
|
491
523
|
```
|
492
524
|
|
493
525
|
#### clear(type)
|
494
526
|
|
495
|
-
Clear
|
527
|
+
Clear page's cache or collected traffic.
|
496
528
|
|
497
529
|
* type `Symbol` it is either `:traffic` or `:cache`
|
498
530
|
|
499
531
|
```ruby
|
500
|
-
traffic =
|
501
|
-
|
532
|
+
traffic = page.network.traffic # => []
|
533
|
+
page.go_to("https://github.com/")
|
502
534
|
traffic.size # => 51
|
503
|
-
|
535
|
+
page.network.clear(:traffic)
|
504
536
|
traffic.size # => 0
|
505
537
|
```
|
506
538
|
|
@@ -516,8 +548,9 @@ continue them.
|
|
516
548
|
|
517
549
|
```ruby
|
518
550
|
browser = Ferrum::Browser.new
|
519
|
-
browser.
|
520
|
-
|
551
|
+
page = browser.create_page
|
552
|
+
page.network.intercept
|
553
|
+
page.on(:request) do |request|
|
521
554
|
if request.match?(/bla-bla/)
|
522
555
|
request.abort
|
523
556
|
elsif request.match?(/lorem/)
|
@@ -526,7 +559,7 @@ browser.on(:request) do |request|
|
|
526
559
|
request.continue
|
527
560
|
end
|
528
561
|
end
|
529
|
-
|
562
|
+
page.go_to("https://google.com")
|
530
563
|
```
|
531
564
|
|
532
565
|
#### authorize(\*\*options, &block)
|
@@ -541,10 +574,10 @@ If site or proxy uses authorization you can provide credentials using this metho
|
|
541
574
|
care about unwanted requests just call `request.continue`.
|
542
575
|
|
543
576
|
```ruby
|
544
|
-
|
545
|
-
|
546
|
-
puts
|
547
|
-
puts
|
577
|
+
page.network.authorize(user: "login", password: "pass") { |req| req.continue }
|
578
|
+
page.go_to("http://example.com/authenticated")
|
579
|
+
puts page.network.status # => 200
|
580
|
+
puts page.body # => Welcome, authenticated client
|
548
581
|
```
|
549
582
|
|
550
583
|
Since Chrome implements authorize using request interception you must continue or abort authorized requests. If you
|
@@ -553,8 +586,9 @@ block, so this is version doesn't pass block and can work just fine:
|
|
553
586
|
|
554
587
|
```ruby
|
555
588
|
browser = Ferrum::Browser.new
|
556
|
-
browser.
|
557
|
-
|
589
|
+
page = browser.create_page
|
590
|
+
page.network.intercept
|
591
|
+
page.on(:request) do |request|
|
558
592
|
if request.resource_type == "Image"
|
559
593
|
request.abort
|
560
594
|
else
|
@@ -562,9 +596,9 @@ browser.on(:request) do |request|
|
|
562
596
|
end
|
563
597
|
end
|
564
598
|
|
565
|
-
|
599
|
+
page.network.authorize(user: "login", password: "pass", type: :proxy)
|
566
600
|
|
567
|
-
|
601
|
+
page.go_to("https://google.com")
|
568
602
|
```
|
569
603
|
|
570
604
|
You used to call `authorize` method without block, but since it's implemented using request interception there could be
|
@@ -587,8 +621,8 @@ Activates emulation of network conditions.
|
|
587
621
|
bluetooth, ethernet, wifi, wimax, other. `nil` by default
|
588
622
|
|
589
623
|
```ruby
|
590
|
-
|
591
|
-
|
624
|
+
page.network.emulate_network_conditions(connection_type: "cellular2g")
|
625
|
+
page.go_to("https://github.com/")
|
592
626
|
```
|
593
627
|
|
594
628
|
#### offline_mode
|
@@ -596,8 +630,8 @@ browser.go_to("https://github.com/")
|
|
596
630
|
Activates offline mode for a page.
|
597
631
|
|
598
632
|
```ruby
|
599
|
-
|
600
|
-
|
633
|
+
page.network.offline_mode
|
634
|
+
page.go_to("https://github.com/") # => Ferrum::StatusError (Request to https://github.com/ failed(net::ERR_INTERNET_DISCONNECTED))
|
601
635
|
```
|
602
636
|
|
603
637
|
#### cache(disable: `Boolean`)
|
@@ -605,21 +639,65 @@ browser.go_to("https://github.com/") # => Ferrum::StatusError (Request to https:
|
|
605
639
|
Toggles ignoring cache for each request. If true, cache will not be used.
|
606
640
|
|
607
641
|
```ruby
|
608
|
-
|
642
|
+
page.network.cache(disable: true)
|
609
643
|
```
|
610
644
|
|
645
|
+
|
646
|
+
## Downloads
|
647
|
+
|
648
|
+
`page.downloads`
|
649
|
+
|
650
|
+
#### files `Array<Hash>`
|
651
|
+
|
652
|
+
Returns all information about downloaded files as a `Hash`.
|
653
|
+
|
654
|
+
```ruby
|
655
|
+
page.go_to("http://localhost/attachment.pdf")
|
656
|
+
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"}]
|
657
|
+
```
|
658
|
+
|
659
|
+
#### wait(timeout)
|
660
|
+
|
661
|
+
Waits until the download is finished.
|
662
|
+
|
663
|
+
```ruby
|
664
|
+
page.go_to("http://localhost/attachment.pdf")
|
665
|
+
page.downloads.wait
|
666
|
+
```
|
667
|
+
|
668
|
+
or
|
669
|
+
|
670
|
+
```ruby
|
671
|
+
page.go_to("http://localhost/page")
|
672
|
+
page.downloads.wait { page.at_css("#download").click }
|
673
|
+
```
|
674
|
+
|
675
|
+
#### set_behavior(\*\*options)
|
676
|
+
|
677
|
+
Sets behavior in case of file to be downloaded.
|
678
|
+
|
679
|
+
* options `Hash`
|
680
|
+
* :save_path `String` absolute path of where to store the file
|
681
|
+
* :behavior `Symbol` `deny | allow | allowAndName | default`, `allow` by default
|
682
|
+
|
683
|
+
```ruby
|
684
|
+
page.go_to("https://example.com/")
|
685
|
+
page.downloads.set_behavior(save_path: "/tmp", behavior: :allow)
|
686
|
+
```
|
687
|
+
|
688
|
+
|
611
689
|
## Proxy
|
612
690
|
|
613
691
|
You can set a proxy with a `:proxy` option:
|
614
692
|
|
615
693
|
```ruby
|
616
|
-
|
694
|
+
Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", user: "user", password: "pa$$" })
|
617
695
|
```
|
618
696
|
|
619
697
|
`:bypass` can specify semi-colon-separated list of hosts for which proxy shouldn't be used:
|
620
698
|
|
621
699
|
```ruby
|
622
|
-
|
700
|
+
Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", bypass: "*.google.com;*foo.com" })
|
623
701
|
```
|
624
702
|
|
625
703
|
In general passing a proxy option when instantiating a browser results in a browser running with proxy command line
|
@@ -643,7 +721,7 @@ end
|
|
643
721
|
|
644
722
|
### Mouse
|
645
723
|
|
646
|
-
`
|
724
|
+
`page.mouse`
|
647
725
|
|
648
726
|
#### scroll_to(x, y)
|
649
727
|
|
@@ -655,8 +733,8 @@ Scroll page to a given x, y
|
|
655
733
|
displayed in the upper left
|
656
734
|
|
657
735
|
```ruby
|
658
|
-
|
659
|
-
|
736
|
+
page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
|
737
|
+
page.mouse.scroll_to(0, 400)
|
660
738
|
```
|
661
739
|
|
662
740
|
#### click(\*\*options) : `Mouse`
|
@@ -700,7 +778,7 @@ Mouse move to given x and y.
|
|
700
778
|
|
701
779
|
### Keyboard
|
702
780
|
|
703
|
-
|
781
|
+
`page.keyboard`
|
704
782
|
|
705
783
|
#### down(key) : `Keyboard`
|
706
784
|
|
@@ -730,14 +808,14 @@ Returns bitfield for a given keys
|
|
730
808
|
|
731
809
|
## Cookies
|
732
810
|
|
733
|
-
`
|
811
|
+
`page.cookies`
|
734
812
|
|
735
813
|
#### all : `Hash<String, Cookie>`
|
736
814
|
|
737
815
|
Returns cookies hash
|
738
816
|
|
739
817
|
```ruby
|
740
|
-
|
818
|
+
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}>}
|
741
819
|
```
|
742
820
|
|
743
821
|
#### [](value) : `Cookie`
|
@@ -747,7 +825,7 @@ Returns cookie
|
|
747
825
|
* value `String`
|
748
826
|
|
749
827
|
```ruby
|
750
|
-
|
828
|
+
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}>
|
751
829
|
```
|
752
830
|
|
753
831
|
#### set(value) : `Boolean`
|
@@ -763,14 +841,14 @@ Sets a cookie
|
|
763
841
|
* :httponly `Boolean`
|
764
842
|
|
765
843
|
```ruby
|
766
|
-
|
844
|
+
page.cookies.set(name: "stealth", value: "omg", domain: "google.com") # => true
|
767
845
|
```
|
768
846
|
|
769
847
|
* value `Cookie`
|
770
848
|
|
771
849
|
```ruby
|
772
|
-
nid_cookie =
|
773
|
-
|
850
|
+
nid_cookie = page.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88>
|
851
|
+
page.cookies.set(nid_cookie) # => true
|
774
852
|
```
|
775
853
|
|
776
854
|
#### remove(\*\*options) : `Boolean`
|
@@ -783,7 +861,7 @@ Removes given cookie
|
|
783
861
|
* :url `String`
|
784
862
|
|
785
863
|
```ruby
|
786
|
-
|
864
|
+
page.cookies.remove(name: "stealth", domain: "google.com") # => true
|
787
865
|
```
|
788
866
|
|
789
867
|
#### clear : `Boolean`
|
@@ -791,12 +869,12 @@ browser.cookies.remove(name: "stealth", domain: "google.com") # => true
|
|
791
869
|
Removes all cookies for current page
|
792
870
|
|
793
871
|
```ruby
|
794
|
-
|
872
|
+
page.cookies.clear # => true
|
795
873
|
```
|
796
874
|
|
797
875
|
## Headers
|
798
876
|
|
799
|
-
`
|
877
|
+
`page.headers`
|
800
878
|
|
801
879
|
#### get : `Hash`
|
802
880
|
|
@@ -830,7 +908,7 @@ Evaluate and return result for given JS expression
|
|
830
908
|
simple value.
|
831
909
|
|
832
910
|
```ruby
|
833
|
-
|
911
|
+
page.evaluate("[window.scrollX, window.scrollY]")
|
834
912
|
```
|
835
913
|
|
836
914
|
#### evaluate_async(expression, wait_time, \*args)
|
@@ -843,7 +921,7 @@ Evaluate asynchronous expression and return result
|
|
843
921
|
simple value.
|
844
922
|
|
845
923
|
```ruby
|
846
|
-
|
924
|
+
page.evaluate_async(%(arguments[0]({foo: "bar"})), 5) # => { "foo" => "bar" }
|
847
925
|
```
|
848
926
|
|
849
927
|
#### execute(expression, \*args)
|
@@ -855,7 +933,7 @@ Execute expression. Doesn't return the result
|
|
855
933
|
simple value.
|
856
934
|
|
857
935
|
```ruby
|
858
|
-
|
936
|
+
page.execute(%(1 + 1)) # => true
|
859
937
|
```
|
860
938
|
|
861
939
|
#### evaluate_on_new_document(expression)
|
@@ -881,7 +959,7 @@ JS
|
|
881
959
|
* :type `String` - `text/javascript` by default
|
882
960
|
|
883
961
|
```ruby
|
884
|
-
|
962
|
+
page.add_script_tag(url: "http://example.com/stylesheet.css") # => true
|
885
963
|
```
|
886
964
|
|
887
965
|
#### add_style_tag(\*\*options) : `Boolean`
|
@@ -892,7 +970,7 @@ browser.add_script_tag(url: "http://example.com/stylesheet.css") # => true
|
|
892
970
|
* :content `String`
|
893
971
|
|
894
972
|
```ruby
|
895
|
-
|
973
|
+
page.add_style_tag(content: "h1 { font-size: 40px; }") # => true
|
896
974
|
|
897
975
|
```
|
898
976
|
#### bypass_csp(\*\*options) : `Boolean`
|
@@ -901,11 +979,39 @@ browser.add_style_tag(content: "h1 { font-size: 40px; }") # => true
|
|
901
979
|
* :enabled `Boolean`, `true` by default
|
902
980
|
|
903
981
|
```ruby
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
982
|
+
page.bypass_csp # => true
|
983
|
+
page.go_to("https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md")
|
984
|
+
page.refresh
|
985
|
+
page.add_script_tag(content: "window.__injected = 42")
|
986
|
+
page.evaluate("window.__injected") # => 42
|
987
|
+
```
|
988
|
+
|
989
|
+
|
990
|
+
## Emulation
|
991
|
+
|
992
|
+
#### disable_javascript
|
993
|
+
|
994
|
+
Disables Javascripts from the loaded HTML source.
|
995
|
+
You can still evaluate JavaScript with `evaluate` or `execute`.
|
996
|
+
Returns nothing.
|
997
|
+
|
998
|
+
```ruby
|
999
|
+
page.disable_javascript
|
1000
|
+
```
|
1001
|
+
|
1002
|
+
|
1003
|
+
#### set_viewport
|
1004
|
+
|
1005
|
+
Overrides device screen dimensions and emulates viewport.
|
1006
|
+
|
1007
|
+
* options `Hash`
|
1008
|
+
* :width `Integer`, viewport width. `0` by default
|
1009
|
+
* :height `Integer`, viewport height. `0` by default
|
1010
|
+
* :scale_factor `Float`, device scale factor. `0` by default
|
1011
|
+
* :mobile `Boolean`, whether to emulate mobile device. `false` by default
|
1012
|
+
|
1013
|
+
```ruby
|
1014
|
+
page.set_viewport(width: 1000, height: 600, scale_factor: 3)
|
909
1015
|
```
|
910
1016
|
|
911
1017
|
|
@@ -916,8 +1022,8 @@ browser.evaluate("window.__injected") # => 42
|
|
916
1022
|
Returns all the frames current page have.
|
917
1023
|
|
918
1024
|
```ruby
|
919
|
-
|
920
|
-
|
1025
|
+
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
|
1026
|
+
page.frames # =>
|
921
1027
|
# [
|
922
1028
|
# #<Ferrum::Frame @id="C6D104CE454A025FBCF22B98DE612B12" @parent_id=nil @name=nil @state=:stopped_loading @execution_id=1>,
|
923
1029
|
# #<Ferrum::Frame @id="C09C4E4404314AAEAE85928EAC109A93" @parent_id="C6D104CE454A025FBCF22B98DE612B12" @state=:stopped_loading @execution_id=2>,
|
@@ -939,7 +1045,7 @@ Find frame by given options.
|
|
939
1045
|
* :name `String` - Frame's name if there's one
|
940
1046
|
|
941
1047
|
```ruby
|
942
|
-
|
1048
|
+
page.frame_by(id: "C6D104CE454A025FBCF22B98DE612B12")
|
943
1049
|
```
|
944
1050
|
|
945
1051
|
|
@@ -975,8 +1081,8 @@ One of the states frame's in:
|
|
975
1081
|
Returns current frame's location href.
|
976
1082
|
|
977
1083
|
```ruby
|
978
|
-
|
979
|
-
frame =
|
1084
|
+
page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
|
1085
|
+
frame = page.frames[1]
|
980
1086
|
frame.url # => https://interactive-examples.mdn.mozilla.net/pages/tabbed/iframe.html
|
981
1087
|
```
|
982
1088
|
|
@@ -985,8 +1091,8 @@ frame.url # => https://interactive-examples.mdn.mozilla.net/pages/tabbed/iframe.
|
|
985
1091
|
Returns current frame's title.
|
986
1092
|
|
987
1093
|
```ruby
|
988
|
-
|
989
|
-
frame =
|
1094
|
+
page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
|
1095
|
+
frame = page.frames[1]
|
990
1096
|
frame.title # => HTML Demo: <iframe>
|
991
1097
|
```
|
992
1098
|
|
@@ -995,8 +1101,8 @@ frame.title # => HTML Demo: <iframe>
|
|
995
1101
|
If current frame is the main frame of the page (top of the tree).
|
996
1102
|
|
997
1103
|
```ruby
|
998
|
-
|
999
|
-
frame =
|
1104
|
+
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
|
1105
|
+
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
|
1000
1106
|
frame.main? # => false
|
1001
1107
|
```
|
1002
1108
|
|
@@ -1005,8 +1111,8 @@ frame.main? # => false
|
|
1005
1111
|
Returns current frame's top window location href.
|
1006
1112
|
|
1007
1113
|
```ruby
|
1008
|
-
|
1009
|
-
frame =
|
1114
|
+
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
|
1115
|
+
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
|
1010
1116
|
frame.current_url # => "https://www.w3schools.com/tags/tag_frame.asp"
|
1011
1117
|
```
|
1012
1118
|
|
@@ -1015,8 +1121,8 @@ frame.current_url # => "https://www.w3schools.com/tags/tag_frame.asp"
|
|
1015
1121
|
Returns current frame's top window title.
|
1016
1122
|
|
1017
1123
|
```ruby
|
1018
|
-
|
1019
|
-
frame =
|
1124
|
+
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
|
1125
|
+
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
|
1020
1126
|
frame.current_title # => "HTML frame tag"
|
1021
1127
|
```
|
1022
1128
|
|
@@ -1025,8 +1131,8 @@ frame.current_title # => "HTML frame tag"
|
|
1025
1131
|
Returns current frame's html.
|
1026
1132
|
|
1027
1133
|
```ruby
|
1028
|
-
|
1029
|
-
frame =
|
1134
|
+
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
|
1135
|
+
frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
|
1030
1136
|
frame.body # => "<html><head></head><body></body></html>"
|
1031
1137
|
```
|
1032
1138
|
|
@@ -1035,8 +1141,8 @@ frame.body # => "<html><head></head><body></body></html>"
|
|
1035
1141
|
Returns current frame's doctype.
|
1036
1142
|
|
1037
1143
|
```ruby
|
1038
|
-
|
1039
|
-
|
1144
|
+
page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
|
1145
|
+
page.main_frame.doctype # => "<!DOCTYPE html>"
|
1040
1146
|
```
|
1041
1147
|
|
1042
1148
|
#### content = html
|
@@ -1046,8 +1152,8 @@ Sets a content of a given frame.
|
|
1046
1152
|
* html `String`
|
1047
1153
|
|
1048
1154
|
```ruby
|
1049
|
-
|
1050
|
-
frame =
|
1155
|
+
page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
|
1156
|
+
frame = page.frames[1]
|
1051
1157
|
frame.body # <html lang="en"><head><style>body {transition: opacity ease-in 0.2s; }...
|
1052
1158
|
frame.content = "<html><head></head><body><p>lol</p></body></html>"
|
1053
1159
|
frame.body # => <html><head></head><body><p>lol</p></body></html>
|
@@ -1067,15 +1173,14 @@ Accept dialog with given text or default prompt if applicable
|
|
1067
1173
|
Dismiss dialog
|
1068
1174
|
|
1069
1175
|
```ruby
|
1070
|
-
|
1071
|
-
browser.on(:dialog) do |dialog|
|
1176
|
+
page.on(:dialog) do |dialog|
|
1072
1177
|
if dialog.match?(/bla-bla/)
|
1073
1178
|
dialog.accept
|
1074
1179
|
else
|
1075
1180
|
dialog.dismiss
|
1076
1181
|
end
|
1077
1182
|
end
|
1078
|
-
|
1183
|
+
page.go_to("https://google.com")
|
1079
1184
|
```
|
1080
1185
|
|
1081
1186
|
|
@@ -1095,10 +1200,9 @@ Sets playback rate of CSS animations
|
|
1095
1200
|
* value `Integer`
|
1096
1201
|
|
1097
1202
|
```ruby
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
browser.playback_rate # => 2000
|
1203
|
+
page.playback_rate = 2000
|
1204
|
+
page.go_to("https://google.com")
|
1205
|
+
page.playback_rate # => 2000
|
1102
1206
|
```
|
1103
1207
|
|
1104
1208
|
|
@@ -1112,7 +1216,7 @@ Returns [Frame](https://github.com/rubycdp/ferrum#frame) object for current node
|
|
1112
1216
|
[Finders](https://github.com/rubycdp/ferrum#Finders) for that object:
|
1113
1217
|
|
1114
1218
|
```ruby
|
1115
|
-
frame =
|
1219
|
+
frame = page.at_xpath("//iframe").frame # => Frame
|
1116
1220
|
frame.at_css("//a[text() = 'Log in']") # => Node
|
1117
1221
|
```
|
1118
1222
|
|
@@ -1143,15 +1247,15 @@ frame.at_css("//a[text() = 'Log in']") # => Node
|
|
1143
1247
|
(chainable) Selects options by passed attribute.
|
1144
1248
|
|
1145
1249
|
```ruby
|
1146
|
-
|
1147
|
-
|
1250
|
+
page.at_xpath("//*[select]").select(["1"]) # => Node (select)
|
1251
|
+
page.at_xpath("//*[select]").select(["text"], by: :text) # => Node (select)
|
1148
1252
|
```
|
1149
1253
|
|
1150
1254
|
Accept string, array or strings:
|
1151
1255
|
```ruby
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1256
|
+
page.at_xpath("//*[select]").select("1")
|
1257
|
+
page.at_xpath("//*[select]").select("1", "2")
|
1258
|
+
page.at_xpath("//*[select]").select(["1", "2"])
|
1155
1259
|
```
|
1156
1260
|
|
1157
1261
|
|
@@ -1182,6 +1286,25 @@ Accepts block, records trace and by default returns trace data from `Tracing.tra
|
|
1182
1286
|
only one trace config can be active at a time per browser.
|
1183
1287
|
|
1184
1288
|
|
1289
|
+
## Clean Up
|
1290
|
+
|
1291
|
+
#### reset
|
1292
|
+
|
1293
|
+
Closes browser tabs opened by the `Browser` instance.
|
1294
|
+
|
1295
|
+
```ruby
|
1296
|
+
# connect to a long-running Chrome process
|
1297
|
+
browser = Ferrum::Browser.new(url: 'http://localhost:9222')
|
1298
|
+
|
1299
|
+
browser.go_to("https://github.com/")
|
1300
|
+
|
1301
|
+
# clean up, lest the tab stays there hanging forever
|
1302
|
+
browser.reset
|
1303
|
+
|
1304
|
+
browser.quit
|
1305
|
+
```
|
1306
|
+
|
1307
|
+
|
1185
1308
|
## Thread safety ##
|
1186
1309
|
|
1187
1310
|
Ferrum is fully thread-safe. You can create one browser or a few as you wish and
|