ferrum 0.13 → 0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +288 -154
- data/lib/ferrum/browser/command.rb +8 -0
- data/lib/ferrum/browser/options/chrome.rb +17 -5
- data/lib/ferrum/browser/options.rb +38 -25
- data/lib/ferrum/browser/process.rb +44 -17
- data/lib/ferrum/browser.rb +34 -52
- data/lib/ferrum/client/subscriber.rb +76 -0
- data/lib/ferrum/{browser → client}/web_socket.rb +36 -22
- 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/cookie.rb +57 -0
- data/lib/ferrum/cookies.rb +40 -4
- data/lib/ferrum/downloads.rb +60 -0
- data/lib/ferrum/errors.rb +2 -1
- data/lib/ferrum/frame.rb +1 -0
- data/lib/ferrum/headers.rb +1 -1
- data/lib/ferrum/network/exchange.rb +29 -2
- data/lib/ferrum/network/intercepted_request.rb +8 -17
- data/lib/ferrum/network/request.rb +23 -39
- data/lib/ferrum/network/request_params.rb +57 -0
- data/lib/ferrum/network/response.rb +25 -5
- data/lib/ferrum/network.rb +43 -16
- data/lib/ferrum/node.rb +21 -1
- data/lib/ferrum/page/frames.rb +5 -5
- data/lib/ferrum/page/screenshot.rb +42 -24
- data/lib/ferrum/page.rb +183 -131
- 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 -114
- data/lib/ferrum/browser/client.rb +0 -102
- data/lib/ferrum/browser/subscriber.rb +0 -36
data/lib/ferrum.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ferrum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.15'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Vorotilin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -55,121 +55,17 @@ dependencies:
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: websocket-driver
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.6'
|
62
|
-
- - "<"
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: '0.8'
|
65
|
-
type: :runtime
|
66
|
-
prerelease: false
|
67
|
-
version_requirements: !ruby/object:Gem::Requirement
|
68
|
-
requirements:
|
69
|
-
- - ">="
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
version: '0.6'
|
72
|
-
- - "<"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '0.8'
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: chunky_png
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - "~>"
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '1.3'
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - "~>"
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '1.3'
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: image_size
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - "~>"
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '2.0'
|
96
|
-
type: :development
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - "~>"
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '2.0'
|
103
|
-
- !ruby/object:Gem::Dependency
|
104
|
-
name: pdf-reader
|
105
|
-
requirement: !ruby/object:Gem::Requirement
|
106
|
-
requirements:
|
107
|
-
- - "~>"
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '2.2'
|
110
|
-
type: :development
|
111
|
-
prerelease: false
|
112
|
-
version_requirements: !ruby/object:Gem::Requirement
|
113
58
|
requirements:
|
114
59
|
- - "~>"
|
115
60
|
- !ruby/object:Gem::Version
|
116
|
-
version: '
|
117
|
-
|
118
|
-
name: puma
|
119
|
-
requirement: !ruby/object:Gem::Requirement
|
120
|
-
requirements:
|
121
|
-
- - "~>"
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '4.1'
|
124
|
-
type: :development
|
125
|
-
prerelease: false
|
126
|
-
version_requirements: !ruby/object:Gem::Requirement
|
127
|
-
requirements:
|
128
|
-
- - "~>"
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version: '4.1'
|
131
|
-
- !ruby/object:Gem::Dependency
|
132
|
-
name: rake
|
133
|
-
requirement: !ruby/object:Gem::Requirement
|
134
|
-
requirements:
|
135
|
-
- - "~>"
|
136
|
-
- !ruby/object:Gem::Version
|
137
|
-
version: '13.0'
|
138
|
-
type: :development
|
139
|
-
prerelease: false
|
140
|
-
version_requirements: !ruby/object:Gem::Requirement
|
141
|
-
requirements:
|
142
|
-
- - "~>"
|
143
|
-
- !ruby/object:Gem::Version
|
144
|
-
version: '13.0'
|
145
|
-
- !ruby/object:Gem::Dependency
|
146
|
-
name: rspec
|
147
|
-
requirement: !ruby/object:Gem::Requirement
|
148
|
-
requirements:
|
149
|
-
- - "~>"
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
version: '3.8'
|
152
|
-
type: :development
|
153
|
-
prerelease: false
|
154
|
-
version_requirements: !ruby/object:Gem::Requirement
|
155
|
-
requirements:
|
156
|
-
- - "~>"
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: '3.8'
|
159
|
-
- !ruby/object:Gem::Dependency
|
160
|
-
name: sinatra
|
161
|
-
requirement: !ruby/object:Gem::Requirement
|
162
|
-
requirements:
|
163
|
-
- - "~>"
|
164
|
-
- !ruby/object:Gem::Version
|
165
|
-
version: '2.0'
|
166
|
-
type: :development
|
61
|
+
version: '0.7'
|
62
|
+
type: :runtime
|
167
63
|
prerelease: false
|
168
64
|
version_requirements: !ruby/object:Gem::Requirement
|
169
65
|
requirements:
|
170
66
|
- - "~>"
|
171
67
|
- !ruby/object:Gem::Version
|
172
|
-
version: '
|
68
|
+
version: '0.7'
|
173
69
|
description: Ferrum allows you to control headless Chrome browser
|
174
70
|
email:
|
175
71
|
- d.vorotilin@gmail.com
|
@@ -182,22 +78,23 @@ files:
|
|
182
78
|
- lib/ferrum.rb
|
183
79
|
- lib/ferrum/browser.rb
|
184
80
|
- lib/ferrum/browser/binary.rb
|
185
|
-
- lib/ferrum/browser/client.rb
|
186
81
|
- lib/ferrum/browser/command.rb
|
187
82
|
- lib/ferrum/browser/options.rb
|
188
83
|
- lib/ferrum/browser/options/base.rb
|
189
84
|
- lib/ferrum/browser/options/chrome.rb
|
190
85
|
- lib/ferrum/browser/options/firefox.rb
|
191
86
|
- lib/ferrum/browser/process.rb
|
192
|
-
- lib/ferrum/browser/subscriber.rb
|
193
87
|
- lib/ferrum/browser/version_info.rb
|
194
|
-
- lib/ferrum/browser/web_socket.rb
|
195
88
|
- lib/ferrum/browser/xvfb.rb
|
89
|
+
- lib/ferrum/client.rb
|
90
|
+
- lib/ferrum/client/subscriber.rb
|
91
|
+
- lib/ferrum/client/web_socket.rb
|
196
92
|
- lib/ferrum/context.rb
|
197
93
|
- lib/ferrum/contexts.rb
|
198
94
|
- lib/ferrum/cookies.rb
|
199
95
|
- lib/ferrum/cookies/cookie.rb
|
200
96
|
- lib/ferrum/dialog.rb
|
97
|
+
- lib/ferrum/downloads.rb
|
201
98
|
- lib/ferrum/errors.rb
|
202
99
|
- lib/ferrum/frame.rb
|
203
100
|
- lib/ferrum/frame/dom.rb
|
@@ -212,6 +109,7 @@ files:
|
|
212
109
|
- lib/ferrum/network/exchange.rb
|
213
110
|
- lib/ferrum/network/intercepted_request.rb
|
214
111
|
- lib/ferrum/network/request.rb
|
112
|
+
- lib/ferrum/network/request_params.rb
|
215
113
|
- lib/ferrum/network/response.rb
|
216
114
|
- lib/ferrum/node.rb
|
217
115
|
- lib/ferrum/page.rb
|
@@ -225,7 +123,9 @@ files:
|
|
225
123
|
- lib/ferrum/target.rb
|
226
124
|
- lib/ferrum/utils/attempt.rb
|
227
125
|
- lib/ferrum/utils/elapsed_time.rb
|
126
|
+
- lib/ferrum/utils/event.rb
|
228
127
|
- lib/ferrum/utils/platform.rb
|
128
|
+
- lib/ferrum/utils/thread.rb
|
229
129
|
- lib/ferrum/version.rb
|
230
130
|
homepage: https://github.com/rubycdp/ferrum
|
231
131
|
licenses:
|
@@ -245,14 +145,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
245
145
|
requirements:
|
246
146
|
- - ">="
|
247
147
|
- !ruby/object:Gem::Version
|
248
|
-
version: 2.
|
148
|
+
version: 2.7.0
|
249
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
250
150
|
requirements:
|
251
151
|
- - ">="
|
252
152
|
- !ruby/object:Gem::Version
|
253
153
|
version: '0'
|
254
154
|
requirements: []
|
255
|
-
rubygems_version: 3.
|
155
|
+
rubygems_version: 3.5.6
|
256
156
|
signing_key:
|
257
157
|
specification_version: 4
|
258
158
|
summary: Ruby headless Chrome driver
|
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "ferrum/browser/subscriber"
|
4
|
-
require "ferrum/browser/web_socket"
|
5
|
-
|
6
|
-
module Ferrum
|
7
|
-
class Browser
|
8
|
-
class Client
|
9
|
-
INTERRUPTIONS = %w[Fetch.requestPaused Fetch.authRequired].freeze
|
10
|
-
|
11
|
-
def initialize(ws_url, connectable, logger: nil, ws_max_receive_size: nil, id_starts_with: 0)
|
12
|
-
@connectable = connectable
|
13
|
-
@command_id = id_starts_with
|
14
|
-
@pendings = Concurrent::Hash.new
|
15
|
-
@ws = WebSocket.new(ws_url, ws_max_receive_size, logger)
|
16
|
-
@subscriber, @interrupter = Subscriber.build(2)
|
17
|
-
|
18
|
-
@thread = Thread.new do
|
19
|
-
Thread.current.abort_on_exception = true
|
20
|
-
Thread.current.report_on_exception = true if Thread.current.respond_to?(:report_on_exception=)
|
21
|
-
|
22
|
-
loop do
|
23
|
-
message = @ws.messages.pop
|
24
|
-
break unless message
|
25
|
-
|
26
|
-
if INTERRUPTIONS.include?(message["method"])
|
27
|
-
@interrupter.async.call(message)
|
28
|
-
elsif message.key?("method")
|
29
|
-
@subscriber.async.call(message)
|
30
|
-
else
|
31
|
-
@pendings[message["id"]]&.set(message)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def command(method, params = {})
|
38
|
-
pending = Concurrent::IVar.new
|
39
|
-
message = build_message(method, params)
|
40
|
-
@pendings[message[:id]] = pending
|
41
|
-
@ws.send_message(message)
|
42
|
-
data = pending.value!(@connectable.timeout)
|
43
|
-
@pendings.delete(message[:id])
|
44
|
-
|
45
|
-
raise DeadBrowserError if data.nil? && @ws.messages.closed?
|
46
|
-
raise TimeoutError unless data
|
47
|
-
|
48
|
-
error, response = data.values_at("error", "result")
|
49
|
-
raise_browser_error(error) if error
|
50
|
-
response
|
51
|
-
end
|
52
|
-
|
53
|
-
def on(event, &block)
|
54
|
-
case event
|
55
|
-
when *INTERRUPTIONS
|
56
|
-
@interrupter.on(event, &block)
|
57
|
-
else
|
58
|
-
@subscriber.on(event, &block)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def subscribed?(event)
|
63
|
-
[@interrupter, @subscriber].any? { |s| s.subscribed?(event) }
|
64
|
-
end
|
65
|
-
|
66
|
-
def close
|
67
|
-
@ws.close
|
68
|
-
# Give a thread some time to handle a tail of messages
|
69
|
-
@pendings.clear
|
70
|
-
@thread.kill unless @thread.join(1)
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
def build_message(method, params)
|
76
|
-
{ method: method, params: params }.merge(id: next_command_id)
|
77
|
-
end
|
78
|
-
|
79
|
-
def next_command_id
|
80
|
-
@command_id += 1
|
81
|
-
end
|
82
|
-
|
83
|
-
def raise_browser_error(error)
|
84
|
-
case error["message"]
|
85
|
-
# Node has disappeared while we were trying to get it
|
86
|
-
when "No node with given id found",
|
87
|
-
"Could not find node with given id"
|
88
|
-
raise NodeNotFoundError, error
|
89
|
-
# Context is lost, page is reloading
|
90
|
-
when "Cannot find context with specified id"
|
91
|
-
raise NoExecutionContextError, error
|
92
|
-
when "No target with given id found"
|
93
|
-
raise NoSuchPageError
|
94
|
-
when /Could not compute content quads/
|
95
|
-
raise CoordinatesNotFoundError
|
96
|
-
else
|
97
|
-
raise BrowserError, error
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Ferrum
|
4
|
-
class Browser
|
5
|
-
class Subscriber
|
6
|
-
include Concurrent::Async
|
7
|
-
|
8
|
-
def self.build(size)
|
9
|
-
(0..size).map { new }
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
super
|
14
|
-
@on = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
|
15
|
-
end
|
16
|
-
|
17
|
-
def on(event, &block)
|
18
|
-
@on[event] << block
|
19
|
-
true
|
20
|
-
end
|
21
|
-
|
22
|
-
def subscribed?(event)
|
23
|
-
@on.key?(event)
|
24
|
-
end
|
25
|
-
|
26
|
-
def call(message)
|
27
|
-
method, params = message.values_at("method", "params")
|
28
|
-
total = @on[method].size
|
29
|
-
@on[method].each_with_index do |block, index|
|
30
|
-
# In case of multiple callbacks we provide current index and total
|
31
|
-
block.call(params, index, total)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|