ferrumwizard 0.1.3 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5eb39e3f7b96b87809950695d7987529b5d2abd7fe8a445e5e658453694d3c4
4
- data.tar.gz: ab1de29c5cb1c2c9a904069e0a6ef6d8bf8cbdadd68eba2ad1992945c4189948
3
+ metadata.gz: 2b8068fb08b6eb2a2c96e42a22e4e2290484fa98ca27271b3731d858e39d7bf5
4
+ data.tar.gz: a939996048a46f321bf66c4dc86991f9a37c91393599782e9d3a147a473e2216
5
5
  SHA512:
6
- metadata.gz: 511884c66a570b8fe74ab14109f3f731316a74824869b73a46cf26bff6b7fbc4f63a92848790229a95aa753b91ff3ada227ebdfa6ed19fe40641da812597d394
7
- data.tar.gz: 166d533864edff9c4b3cd00e9174064a900532bf8e420edf7ea1c4d16dad3145bb99acc0ab93a4ababf7bb76a12f5b383018a1f61ead98433cec2b1de07814d0
6
+ metadata.gz: 17c6c8faf26098abcbd716cedb7ba4a4c9d935595af6c4e1626887b3a465ab6632d68502f4f01f5f61f5af59a78c0a629da36e4ea6c0b11a35d1ce1f994872d1
7
+ data.tar.gz: 950098796922e1b514df83e92438f533ad92fa6bfb40208001d3b1de12b7810b87fa3f888a8f6733061e5f0672fb8e2919358ca52a11bef12b5bb24b40bcf451
checksums.yaml.gz.sig CHANGED
Binary file
data/lib/ferrumwizard.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  # file: ferrumwizard.rb
4
4
 
5
+ require 'yaml'
5
6
  require 'rexle'
6
7
  require 'ferrum'
7
8
 
@@ -10,125 +11,204 @@ class FerrumWizard
10
11
 
11
12
  attr_reader :browser, :links, :radio, :buttons, :js_methods
12
13
 
13
- def initialize(url, headless: true, timeout: 10, debug: false)
14
+ def initialize(url=nil, headless: true, timeout: 10, cookies: nil,
15
+ debug: false)
14
16
 
15
17
  @url, @debug = url, debug
16
18
  @browser = Ferrum::Browser.new headless: headless, timeout: timeout
17
- sleep 2
18
-
19
- @browser.goto url if url
19
+ sleep 3
20
+
21
+ if url then
22
+
23
+ loadx(cookies) if cookies
24
+
25
+ @browser.goto(@url)
26
+ @browser.network.wait_for_idle
27
+ sleep 4
28
+
29
+ end
20
30
  end
21
-
31
+
22
32
  def inspect()
23
33
  "#<FerrumWizard>"
24
34
  end
25
-
35
+
36
+ # Intended to load all the cookies for a user to login automatically
37
+ #
38
+ # Follow these steps to load the cookies file:
39
+ #
40
+ # 1. launch the Ferrum browser
41
+ # fw = FerrumWizard.new( headless: false, debug: false)
42
+ #
43
+ # 2. load the cookies before you visit the website
44
+ # fw.load_cookies('/tmp/indeed2.txt')
45
+ #
46
+ # 3. visit the website
47
+ # url='https://somewebsite.com'
48
+ # fw.browser.goto(url)
49
+ #
50
+ def load_cookies(filepath)
51
+
52
+ rawcookies = YAML.load(File.read(filepath))
53
+
54
+ rawcookies.each do |h|
55
+
56
+ if @debug then
57
+ puts 'name: ' + h['name']
58
+ puts 'h: ' + h.inspect
59
+ sleep 0.7
60
+ end
61
+
62
+ browser.cookies.set(name: h['name'], value: h['value'],
63
+ domain: h['domain'], expires: h['expires'],
64
+ httponly: h['httpOnly'])
65
+ end
66
+
67
+ end
68
+
69
+ alias loadx load_cookies
70
+
26
71
  def login(usernamex=nil, passwordx=nil, username: usernamex, password: passwordx)
27
-
28
- puts 'username: ' + username.inspect if @debug
29
72
 
30
- b = @browser
31
- b.goto(@url)
32
- @browser.network.wait_for_idle
33
- sleep 3
73
+ puts 'username: ' + username.inspect if @debug
34
74
 
35
75
  # search for the username input box
36
- e_username = b.at_xpath('//input[@type="email"]')
76
+ e_username = @browser.at_xpath('//input[@type="email"]')
37
77
  puts 'e_username: ' + e_username.inspect if @debug
38
78
  sleep 1
39
79
  # search for the password input box
40
- e_password = b.at_xpath('//input[@type="password"]')
80
+ found = @browser.at_xpath('//input[@type="password"]')
81
+
82
+ e_password = if found then
83
+ found
84
+ else
85
+ @browser.xpath('//input').find {|x| x.property(:id) =~ /password/i}
86
+ end
87
+
41
88
  sleep 1
42
-
89
+
43
90
  if username and e_username then
44
91
  puts 'entering the username' if @debug
45
- e_username.focus.type(username)
92
+ e_username.focus.type(username)
46
93
  sleep 1
47
94
  end
48
-
95
+
49
96
  e_password.focus.type(password, :Enter) if e_password
50
-
97
+
51
98
  after_login()
52
-
53
- end
54
-
99
+
100
+ end
101
+
102
+ # login2 is used for websites where the user is presented with the username
103
+ # input box on the first page and the password input box on the next page.
104
+ #
55
105
  def login2(usernamex=nil, passwordx=nil, username: usernamex, password: passwordx)
56
-
57
- puts 'username: ' + username.inspect if @debug
58
106
 
59
- b = @browser
60
- b.goto(@url)
61
- @browser.network.wait_for_idle
62
- sleep 3
107
+ puts 'username: ' + username.inspect if @debug
63
108
 
64
109
  # search for the username input box
65
- e_username = b.at_xpath('//input[@type="email"]')
110
+ e_username = @browser.at_xpath('//input[@type="email"]')
66
111
  puts 'e_username: ' + e_username.inspect if @debug
67
112
  sleep 1
68
113
  # search for the password input box
69
-
114
+
70
115
  if username and e_username then
71
116
  puts 'entering the username' if @debug
72
- e_username.focus.type(username, :Enter)
117
+ e_username.focus.type(username, :Enter)
73
118
  sleep 2
74
119
  end
75
120
 
76
- e_password = b.at_xpath('//input[@type="password"]')
121
+ e_password = @browser.at_xpath('//input[@type="password"]')
77
122
  sleep 1
78
-
123
+
79
124
  e_password.focus.type(password, :Enter) if e_password
80
-
125
+
81
126
  after_login()
82
127
 
83
-
84
- end
85
-
128
+
129
+ end
130
+
86
131
  def quit
87
132
  @browser.quit
88
133
  end
89
-
134
+
90
135
  def scan_page()
91
-
92
- @doc = Rexle.new @browser.body
136
+
137
+ @doc = Rexle.new @browser.body
93
138
  fetch_links()
94
- scan_form_elements()
139
+ scan_form_elements()
95
140
  scan_js_links()
96
- self
141
+ @browser.mouse.scroll_to(0, 800)
142
+ self
143
+ end
144
+
145
+ # Saves all cookies for a given website into a YAML file
146
+ # see also load_cookies()
147
+ #
148
+ # To use this method follow these steps:
149
+ #
150
+ # 1. launch the web browser through Ferrum
151
+ # fw = FerrumWizard.new(url, headless: false, debug: false)
152
+ #
153
+ # 2. go to the browser and login using your credentials
154
+ # fw.save_cookies(filepath)
155
+ #
156
+ # 3. exit the IRB session
157
+ #
158
+ def save_cookies(filepath=Tempfile.new('ferrum').path)
159
+
160
+ rawcookies = @browser.cookies.all.keys.map do |key|
161
+
162
+ if @debug then
163
+ puts 'key: ' + key.inspect
164
+ sleep 0.5
165
+ end
166
+
167
+ s = @browser.cookies[key].inspect
168
+ a = s.scan(/"([^"]+)"=\>/)
169
+ s2 = s[/(?<=@attributes=).*(?=>)/]
170
+ eval(s2)
171
+
172
+ end
173
+
174
+ File.write filepath, rawcookies.to_yaml
175
+
97
176
  end
98
-
177
+
99
178
  def submit(h)
100
179
 
101
180
  e = nil
102
-
181
+
103
182
  h.each do |key, value|
104
- e = @browser.xpath('//input').find {|x| x.attribute('name') == key.to_s}
105
- e.focus.type(value)
183
+ e = @browser.xpath('//input').find {|x| x.attribute('name') == key.to_s}
184
+ e.focus.type(value)
106
185
  end
107
-
108
- e.focus.type('', :Enter)
109
-
110
- sleep 4
186
+
187
+ e.focus.type('', :Enter)
188
+
189
+ sleep 4
111
190
  scan_page()
112
-
191
+
113
192
  end
114
193
 
115
194
  def to_rb()
116
195
  end
117
-
196
+
118
197
  private
119
-
198
+
120
199
  def after_login()
121
-
122
- @browser.network.wait_for_idle
200
+
201
+ @browser.network.wait_for_idle
123
202
  sleep 4
124
203
  scan_page()
125
-
204
+
126
205
  @browser.base_url = File.dirname(@browser.url)
127
206
  @browser.mouse.scroll_to(0, 800)
128
207
  self
129
-
208
+
130
209
  end
131
-
210
+
211
+
132
212
  def fetch_buttons()
133
213
 
134
214
  a2 = @browser.xpath('//input[@type="button"]')
@@ -144,24 +224,24 @@ class FerrumWizard
144
224
  buttons = @buttons
145
225
 
146
226
  names.each do |name|
147
-
227
+
148
228
  define_singleton_method name.to_sym do
149
229
  buttons[name].click
150
230
  @browser.network.wait_for_idle
151
231
  sleep = 1
152
232
  self
153
233
  end
154
-
234
+
155
235
  end
156
236
 
157
237
  end
158
-
238
+
159
239
  def fetch_links()
160
-
240
+
161
241
  all_links = @doc.root.xpath('//a[@href]')
162
-
242
+
163
243
  all_links.each do |x|
164
-
244
+
165
245
  if x.plaintext.empty? then
166
246
  x.text = x.attributes[:href].sub(/\.\w+$/,'')[/([^\/]+)$/].split(/[_]|(?=[A-Z])/).join(' ')
167
247
  else
@@ -169,76 +249,74 @@ class FerrumWizard
169
249
  end
170
250
 
171
251
  end
172
-
252
+
173
253
  valid_links = all_links.reject do |x|
174
-
254
+
175
255
  puts 'x: ' + x.inspect if @debug
176
256
  r = (x.attributes[:target] == '_blank')
177
257
 
178
258
  puts 'r: ' + r.inspect if @debug
179
259
  r
180
-
260
+
181
261
  end
182
-
262
+
183
263
  indices = valid_links.map {|x| all_links.index x}
184
264
 
185
265
  active_links = @browser.xpath('//a[@href]')
186
266
  valid_active_links = indices.map {|n| active_links[n]}
187
-
188
267
 
189
- @links = valid_active_links.flat_map.with_index do |x, i|
268
+
269
+ @links = valid_active_links.flat_map.with_index do |x, i|
190
270
 
191
271
  a = valid_links[i].text.split(/\W+/).map {|label| [label, x]}
192
272
  a << [valid_links[i].text, x]
193
-
273
+
194
274
  puts 'a: ' + a.inspect if @debug
195
275
  a + a.map {|x2, obj| [x2.downcase, obj]}
196
-
276
+
197
277
  end.to_h
198
-
278
+
199
279
  names = @links.keys.map(&:downcase).uniq.select {|x| x =~ /^[\w ]+$/}
200
280
  links = @links
201
-
281
+
202
282
  names.each do |name|
203
-
283
+
204
284
  define_singleton_method name.gsub(/ +/,'_').to_sym do
205
-
285
+
206
286
  links[name].click
207
287
  @browser.network.wait_for_idle
208
-
288
+
209
289
  sleep 1
210
290
  scan_page()
211
291
  self
212
-
292
+
213
293
  end
214
-
294
+
215
295
  end
216
-
296
+
217
297
  end
218
298
 
219
299
  def scan_form_elements()
220
-
300
+
221
301
  # find radio buttons
222
-
223
- #a = doc.root.xpath('//input[@type="radio"]')
302
+
224
303
  a = @browser.xpath('//input[@type="radio"]')
225
- #h = a.group_by {|x| x.attributes[:name]}
226
304
  h = a.group_by {|x| x.attribute('name')}
227
305
  @radio = h.values
228
306
  define_singleton_method(:on) { @radio[0][0].click; self }
229
307
  define_singleton_method(:off) { @radio[0][1].click; self }
230
-
308
+
231
309
  fetch_buttons()
232
-
310
+
233
311
  end
234
-
312
+
235
313
  def scan_js_links()
236
-
314
+
237
315
  @js_methods = {}
238
316
  b = @browser
239
-
317
+
240
318
  b.xpath('//a').select {|x| x.attribute('href') =~ /^javascript/}.each do |e|
241
-
319
+
242
320
 
243
321
  s = e.attribute('href')[/(?<=^javascript:)[^\(]+/]
244
322
  puts 's: ' + s.inspect if @debug
@@ -248,17 +326,17 @@ class FerrumWizard
248
326
  a << [s.split(/\W+|(?=[A-Z])/).join('_').downcase, s]
249
327
  #@js_methods[s] = a
250
328
 
251
- a.concat a.map {|x, name| [x.downcase, name] }
329
+ a.concat a.map {|x, name| [x.downcase, name] }
252
330
 
253
331
  puts 'a: ' + a.inspect if @debug
254
332
 
255
333
  a.uniq.select {|x, _| x =~ /^[a-z0-9_]+$/}.each do |x, name|
256
-
334
+
257
335
  if @debug then
258
336
  puts 'x: ' + x.inspect
259
337
  puts 'name: ' + name.inspect
260
338
  end
261
-
339
+
262
340
  define_singleton_method(x.to_sym) do |*args|
263
341
  #args = raw_args.map {|x| x[/^[0-9]+$/] ? x.to_i : x}
264
342
  js_method = "%s(%s)" % [name, args.map(&:inspect).join(', ')]
@@ -267,9 +345,9 @@ class FerrumWizard
267
345
  sleep 4
268
346
  self.scan_page()
269
347
  end
270
-
348
+
271
349
  end
272
-
350
+
273
351
  end
274
352
  end
275
353
 
@@ -278,7 +356,7 @@ class FerrumWizard
278
356
  puts 'method_missing: ' + method_name.inspect if @debug
279
357
  node = @browser.at_css '.' + method_name.to_s
280
358
  node.text if node
281
-
282
- end
283
-
359
+
360
+ end
361
+
284
362
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ferrumwizard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -11,31 +11,31 @@ cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIEXjCCAsagAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFnZW1t
14
- YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMjAwNzMwMTYxOTE5WhcN
15
- MjEwNzMwMTYxOTE5WjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
16
- cnRzb24vREM9ZXUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDhNEIG
17
- /Ab4nneih/AQFMcYk76JCiy26Xcy5uxd9ib7Emkj/9sZo6nxuSBaH03+Ixv3jgJs
18
- TxZyaIKRsESFFmupYmKsyatCGGaBEsDb210ZBm313rP2Pk2fGrUtON0CjwJljWxR
19
- 8pHuglEXrGN/XhVicy7sZLJ2nVnvRtyiKi92XmY0S9LaCkWlOx2f3D7yiazkmHh5
20
- 59nHiGNlZ/SOzFrRMdBvkWZYHgqUEBv0KxEuMqW65U4HdlQImcwqu8XOWH9kutof
21
- yyisv03kPqMvrOC8ptG/TieKYK0JuY23gS9MrVxkrf0gX3IQLY21JWG9t9uRImc/
22
- kHC+EJ2rI8HQqcq/v6dndJb6MhYEhj7R5XsZqlfsLFo21FFBAyaPrqPRUstnW5U0
23
- /tCpcuFyZJeRPqQ8LSlRGDuB/TdmV9dF+P5aGS32k9Okf9L6E6x3OGV29eMHSdDt
24
- LOOB8l0EJbNXzpvYW+htziU8TbuzRQU8K7uTeAfpMUg4auPxdVyQpJcQWXcCAwEA
25
- AaOBijCBhzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU2+nN7PCw
26
- js3NFmK8b17Ji/t+dvwwJgYDVR0RBB8wHYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0
14
+ YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMjIwMzMwMTI1ODU1WhcN
15
+ MjMwMzMwMTI1ODU1WjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
16
+ cnRzb24vREM9ZXUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDROL32
17
+ 3LQKGcDR6x6XFa1US/Vq98DVnMeZHCSKdf471I4gJIOA7sQnrQTB6IZKTxb94Wjr
18
+ OSeGzlJpVq6pa7ltxvb9T7YQVVRrXYMC+u0gD9ukolnkpV/4Rh2/IIMxSNKncoZB
19
+ LKPseizGKlli4gs134gAu3wuWdCC7/UWPG/XyocdJC8tLtf/zi4JuRJTojKqYLOp
20
+ KsP9jHPmGVr81cW8HePmhQ/+LiYlKDE4Fwj4yl16XqhF7/5YOz9e5LOHsMUEord4
21
+ JscQ3GnhMfEXGJpwqCwNEpM3xAwcHp2DDdrwtT36ujSfnTJ3UpUIQUKVehA2i9rm
22
+ uDcDTr1PATGcOMPpExvLZu3a9uC81mj9z+axH5mWQ7jZ92sze79oAQTsMiMyBavJ
23
+ djSpnVBo71PFk8QekgIVVBIzG0iN5zoNUrSthvL/xUWXM6ea015HEDCCIEL417ID
24
+ humVWZyzKf7ITCdZWcxTgTgFfuPMctcICT5u7va+FrycYpdtt8kXvtD3VnkCAwEA
25
+ AaOBijCBhzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUDipvmNU2
26
+ WydgAK8QPGb0vhhoGl0wJgYDVR0RBB8wHYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0
27
27
  c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1hc3RlckBqYW1lc3JvYmVydHNvbi5ldTAN
28
- BgkqhkiG9w0BAQsFAAOCAYEAlaYpTQ2vLuKU/nJl1inw9iE9XCwnTmIhmA9lnu1q
29
- QKKCd7Z2PwtkahbDvMVQ347DQZQAanuZmtTPFMc4FDA530qJtwoYk03FTQXBh12M
30
- d4C27VP9BOrUQcxkqtnTo+4Z60taszXqyPsPYU+Fd8AZUPeS5TOYG52OXTQ+q+pO
31
- vNxkRP9oEka81ZrN1y3r3YaFHATZzf4pJo0HupZvMsQwa33/vA+xxxpDeTuWytNN
32
- O0mYbo8Em2LnPnE8ehOnniDGXIIaDO9B1Qbbr0GhNCIWq3JIcbI2IBCKFWA6HyNF
33
- yCdr7ZqPrnxXlhhnTPLFkzR/0+XxpbrdW4zb6uQqX92/tiUqP9uKf5dBEVoCWax/
34
- IWPJE5JXx2iMvE9cWe4bFCUi7cZT7HsL6jkdUWxeTvsfc7XMbE8eWtHHiG6NjeFJ
35
- 7e24hNRMt3t/JE9ogEO4JzFUH2vq2zzR5X9JQqEclWfwHi4cf8bZFJ7spjZQPjSZ
36
- Ok3rs0A+kW4ixAj1rDYuoyG/
28
+ BgkqhkiG9w0BAQsFAAOCAYEAHqRvm6iqjJ+bpEzSSgVmOMOMcgIoN6px1LMVAOmY
29
+ BJpF5F0fJr99thc1EYZJoRTwEcXJYhCTqKg+3xhNKpCzk2qHsaLKYEygPeBpyJOg
30
+ LyfHLrj98QLPYyFzqhWsqZAAAGC9WSF/kBJazpuotU2ec/Xw/e3NPopedV/Zvuhs
31
+ +/OKZWwRez/hg97ckaCYAp/7OdrVhJvR87MaQnN52Uk8OQbuPSyUNQUJ044HWHtu
32
+ lEJjsDetEFhNB69j3wAIMjMEZao29/dZhALbUDp+9ewK7uYbrX9Bo68NX+H+XcCZ
33
+ VFrdrjkyJUOHwSmvjYXN1V0Yz8kVVFU7E+Q4RHL8yAwBv+ynd927HtZVjs+455Pc
34
+ z+9gNpBQVr6LLXLJgJF2pTaIoYhgG6pcoMQHGVoxWdKzvOcl0h1epeJSp/aynX/r
35
+ FK+cyrQNA9DLJYJuz6uO7Z+gXZWjwAO38LUwF01w49asSv/5ZH2HH/EauX5xWpe+
36
+ ry6lYQlb8j50Iys5elAy1p0i
37
37
  -----END CERTIFICATE-----
38
- date: 2020-08-01 00:00:00.000000000 Z
38
+ date: 2022-03-30 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: rexle
@@ -46,7 +46,7 @@ dependencies:
46
46
  version: '1.5'
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 1.5.7
49
+ version: 1.5.14
50
50
  type: :runtime
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
@@ -56,29 +56,29 @@ dependencies:
56
56
  version: '1.5'
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: 1.5.7
59
+ version: 1.5.14
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: ferrum
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- version: 0.9.0
67
64
  - - "~>"
68
65
  - !ruby/object:Gem::Version
69
- version: '0.9'
66
+ version: '0.11'
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0.11'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: 0.9.0
77
74
  - - "~>"
78
75
  - !ruby/object:Gem::Version
79
- version: '0.9'
76
+ version: '0.11'
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0.11'
80
80
  description:
81
- email: james@jamesrobertson.eu
81
+ email: digital.robertson@gmail.com
82
82
  executables: []
83
83
  extensions: []
84
84
  extra_rdoc_files: []
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.0.3
106
+ rubygems_version: 3.2.22
107
107
  signing_key:
108
108
  specification_version: 4
109
109
  summary: Makes web scraping easier using the Ferrum gem.
metadata.gz.sig CHANGED
Binary file