stealth_browser_automation 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/browserfactory.rb +382 -167
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e5b7d022b4081943660188d38da808fde5a8fb4
|
4
|
+
data.tar.gz: 7d78271edc4513a15d1a8b5ffc97b73ce3954396
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2a3ac895d730e2411fe797056c01b8faba33b84b1a9bf3c7a8c96cf3c669d5ff3abfc2751cc304a5e6bea1d5bddfcc959ab3c3fa625ee74ea3500eed8b9fdbc
|
7
|
+
data.tar.gz: 543b5abc9fa2a7ca7f891964439bd4eceaf8cd71b357cdfd60fa765e75c3d559aa0147e9b878872f0f8b69dbd9772cd1ba6f0d23916864edd4a81b49d1cd2bd3
|
data/lib/browserfactory.rb
CHANGED
@@ -27,6 +27,7 @@ require "pathname"
|
|
27
27
|
# and user interaction.
|
28
28
|
#
|
29
29
|
|
30
|
+
# Custom Selenium elements to stream the browser windows when some events happen.
|
30
31
|
module Selenium
|
31
32
|
module WebDriver
|
32
33
|
class Element
|
@@ -41,12 +42,37 @@ module Selenium
|
|
41
42
|
end # module WebDriver
|
42
43
|
end # module Selenium
|
43
44
|
|
45
|
+
|
44
46
|
module BlackStack
|
45
47
|
|
48
|
+
# clase de base para todos los bots ejecuten acciones con una cuenta de LinkedIn, Facebook, Twitter, etc.
|
49
|
+
class MyBotProcess < BlackStack::MyRemoteProcess
|
50
|
+
def run()
|
51
|
+
begin
|
52
|
+
super
|
53
|
+
rescue Interrupt => e
|
54
|
+
self.logger.reset
|
55
|
+
self.logger.log 'Interrupt signal on MyBotProcess!'
|
56
|
+
|
57
|
+
self.logger.logs 'Close all browsers... '
|
58
|
+
begin
|
59
|
+
BlackStack::BrowserFactory.destroy
|
60
|
+
self.logger.done
|
61
|
+
rescue => e
|
62
|
+
self.logger.logf("error:#{e.to_s}")
|
63
|
+
end
|
64
|
+
|
65
|
+
# raise the exception
|
66
|
+
raise e
|
67
|
+
end # begin ... rescue
|
68
|
+
end # def run
|
69
|
+
end # class MyBotProcess
|
70
|
+
|
71
|
+
# Custom Selenium browser to track all browser activity, and stream the browser window.
|
46
72
|
class PampaBrowser < Watir::Browser
|
47
73
|
|
48
74
|
# TODO: enable this when you move to the "frequency-based-streaming" model
|
49
|
-
#PAMPA_BROWSER_CHANNEL_LOCK_FILENAME = './browserfactory.channel.%
|
75
|
+
#PAMPA_BROWSER_CHANNEL_LOCK_FILENAME = './browserfactory.channel.%PROFILE_NAME%.lock' # manejo de concurrencia en la creación de browsers
|
50
76
|
#attr_accessor :lockfile
|
51
77
|
|
52
78
|
attr_accessor :proxy, :lnuser, :agent_name, :profile_name
|
@@ -61,7 +87,7 @@ module BlackStack
|
|
61
87
|
|
62
88
|
def initialize(driver)
|
63
89
|
# TODO: enable this when you move to the "frequency-based-streaming" model
|
64
|
-
#fname = PAMPA_BROWSER_CHANNEL_LOCK_FILENAME.gsub('%
|
90
|
+
#fname = PAMPA_BROWSER_CHANNEL_LOCK_FILENAME.gsub('%PROFILE_NAME%', self.profile_name.to_s)
|
65
91
|
#self.lockfile = File.open(fname,"w")
|
66
92
|
|
67
93
|
#
|
@@ -246,22 +272,109 @@ module BlackStack
|
|
246
272
|
|
247
273
|
|
248
274
|
class BrowserFactory
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
275
|
+
# This file is to launch one browser at time in the same host.
|
276
|
+
# There is one, and only one, lock file for reach host where
|
277
|
+
# Blackstack is running.
|
278
|
+
# More information here: https://bitbucket.org/leandro_sardi/blackstack/issues/1155/browserfactory-use-one-single-lock-file
|
279
|
+
HOST_LOCK_FILENAME = "./sba.host.#{BlackStack::MyProcess.macaddress}.lock" # manejo de concurrencia en la creación de browsers
|
280
|
+
|
281
|
+
# This file keeps the PIDs of all the child processes of this process.
|
282
|
+
# It is neccessary to kill all the child processes of this process when
|
283
|
+
# you have started a chrome browser, and you want to be sure that you
|
284
|
+
# have closed it.
|
285
|
+
# More infromation here: https://bitbucket.org/leandro_sardi/blackstack/issues/943/browserfactory-deja-exploradores-abiertos
|
286
|
+
PROFILE_PID_LIST_FILENAME = "./sba.profile.%PROFILE_NAME%.list" # manejo de concurrencia en la creación de browsers
|
287
|
+
|
288
|
+
# This file store the PID of the last processes that started a browser
|
289
|
+
# with this profile name. There is one, and only one, pid_lockfile for
|
290
|
+
# each browser profile; and such pid_lockfile is shared by all the hosts
|
291
|
+
# where BlackStack is running.
|
292
|
+
PROFILE_LOCK_FILENAME = "./sba.profile.%PROFILE_NAME%.lock" # manejo de concurrencia en la creación de browsers
|
293
|
+
|
294
|
+
# Page load timeout by default.
|
295
|
+
# Works for chrome browsers only.
|
253
296
|
DEFAULT_LOAD_TIMEOUT = 360
|
297
|
+
|
298
|
+
# Location of the chromedriver.exe file by default.
|
299
|
+
# Works for chrome browsers only.
|
254
300
|
DEFAULT_CHROMEDRIVER_PATH = './chromedriver.exe'
|
301
|
+
|
302
|
+
# Different supported browsers.
|
303
|
+
TYPE_CHROME = 1
|
304
|
+
TYPE_MIMIC = 2
|
305
|
+
|
306
|
+
# File handler for HOST_LOCK_FILENAME
|
307
|
+
@@fd_host_lock = File.open(HOST_LOCK_FILENAME,"w")
|
308
|
+
|
309
|
+
# File handler for PROFILE_PID_LIST_FILENAME
|
310
|
+
@@fd_profile_pid_list = nil
|
311
|
+
|
312
|
+
# File handler for PROFILE_LOCK_FILENAME
|
313
|
+
@@fd_profile_lock = nil
|
255
314
|
|
315
|
+
# Selenium driver
|
316
|
+
@@driver = nil
|
317
|
+
|
318
|
+
# Selenium browser
|
319
|
+
@@browser = nil
|
320
|
+
|
321
|
+
# PID of this browser.
|
322
|
+
# Works for Chrme only.
|
323
|
+
@@pid = nil
|
324
|
+
|
325
|
+
# Profile name of this browser.
|
326
|
+
# For Chrome, it will store the name of the profile folder.
|
327
|
+
# For Mimic, it will store the profileId in the MultiLogin APP.
|
328
|
+
@@profile_name = nil
|
329
|
+
|
330
|
+
# Type of this browser.
|
331
|
+
# Only TYPE_CHROME or TYPE_MIMIC are supported at this moment.
|
332
|
+
@@type = nil
|
333
|
+
|
334
|
+
# Returns the PampaBrowser object
|
335
|
+
def self.browser
|
336
|
+
@@browser
|
337
|
+
end
|
338
|
+
|
339
|
+
# Returns the list of supported browsers
|
340
|
+
def self.types
|
341
|
+
[BlackStack::BrowserFactory.TYPE_CHROME, BlackStack::BrowserFactory.TYPE_MIMIC]
|
342
|
+
end
|
343
|
+
|
344
|
+
# Returns the description string from a browser type code
|
345
|
+
def self.typeDesc(type)
|
346
|
+
return 'Chrome' if @@type == BlackStack::BrowserFactory.TYPE_CHROME
|
347
|
+
return 'Mimic' if @@type == BlackStack::BrowserFactory.TYPE_MIMIC
|
348
|
+
raise 'Unknown browser type'
|
349
|
+
end
|
350
|
+
|
351
|
+
# Lock PROFILE_PID_LIST_FILENAME file.
|
352
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
353
|
+
def self.lockProfileList()
|
354
|
+
#@@fd_profile.flock(File::LOCK_EX)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Unlock PROFILE_PID_LIST_FILENAME file.
|
358
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
359
|
+
def self.releaseProfileList()
|
360
|
+
#@@fd_profile.flock(File::LOCK_UN)
|
361
|
+
end
|
362
|
+
|
363
|
+
# Add a PID to the PROFILE_PID_LIST_FILENAME file.
|
364
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
365
|
+
# This method is used for chrome browsers only.
|
256
366
|
def self.addPidToProfileList(profile_name, pid)
|
257
|
-
fname = PROFILE_PID_LIST_FILENAME.gsub('%
|
367
|
+
fname = PROFILE_PID_LIST_FILENAME.gsub('%PROFILE_NAME%', profile_name)
|
258
368
|
f = File.open(fname, 'a')
|
259
369
|
f.write("#{pid},")
|
260
370
|
f.close
|
261
371
|
end
|
262
372
|
|
373
|
+
# Remove a PID from the PROFILE_PID_LIST_FILENAME file.
|
374
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
375
|
+
# This method is used for chrome browsers only.
|
263
376
|
def self.removePidToProfileList(profile_name, pid)
|
264
|
-
fname = PROFILE_PID_LIST_FILENAME.gsub('%
|
377
|
+
fname = PROFILE_PID_LIST_FILENAME.gsub('%PROFILE_NAME%', profile_name)
|
265
378
|
s = File.read(fname)
|
266
379
|
s = s.gsub("#{pid},", "")
|
267
380
|
f = File.open(fname, 'w')
|
@@ -269,9 +382,12 @@ module BlackStack
|
|
269
382
|
f.close
|
270
383
|
end
|
271
384
|
|
385
|
+
# Returns an array of strings with the PIDs registered for this browser.
|
386
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
387
|
+
# This method is used for chrome browsers only.
|
272
388
|
def self.readPidToProfileList(profile_name)
|
273
|
-
if
|
274
|
-
fname = PROFILE_PID_LIST_FILENAME.gsub('%
|
389
|
+
if profile_name != nil
|
390
|
+
fname = PROFILE_PID_LIST_FILENAME.gsub('%PROFILE_NAME%', profile_name)
|
275
391
|
s = File.read(fname)
|
276
392
|
return s.split(",")
|
277
393
|
else
|
@@ -279,43 +395,102 @@ module BlackStack
|
|
279
395
|
end
|
280
396
|
end
|
281
397
|
|
282
|
-
|
398
|
+
# Add the PID of this browser; and the PID of all the child processes of this, with name like /chrome\.exe/.
|
399
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
400
|
+
# This method is used for chrome browsers only.
|
401
|
+
def self.updateProfileList
|
283
402
|
addPidToProfileList(@@profile_name, @@pid)
|
284
|
-
PROCESS.list().select { |p| p[:ppid] == @@pid &&
|
403
|
+
PROCESS.list().select { |p| p[:ppid] == @@pid && p[:executablepath] =~ /chrome\.exe/ }.each { |p2|
|
285
404
|
addPidToProfileList(@@profile_name, p2[:pid])
|
286
405
|
}
|
287
406
|
end
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
@@type = nil
|
301
|
-
|
302
|
-
def self.browser()
|
303
|
-
@@browser
|
407
|
+
|
408
|
+
# Returns true if @@browser is not nil, or @@profile_name is not nil.
|
409
|
+
# Otherwise, returns false
|
410
|
+
# If the browser type is Chrome, this method will return true if the PROFILE_PID_LIST_FILENAME has one or more PIDs registered.
|
411
|
+
# For more information, read documentations about PROFILE_PID_LIST_FILENAME.
|
412
|
+
def self.isCreated
|
413
|
+
if @@type == BlackStack::BrowserFactory.TYPE_CHROME
|
414
|
+
if (self.readPidToProfileList(@@profile_name).size>0)
|
415
|
+
return true
|
416
|
+
end
|
417
|
+
end
|
418
|
+
!@@browser.nil? || !@@profile_name.nil?
|
304
419
|
end
|
305
420
|
|
306
|
-
|
307
|
-
|
421
|
+
# Call isCreated() method.
|
422
|
+
# For more information, read the documentation of isCreated() method.
|
423
|
+
def self.isCreated?
|
424
|
+
self.isCreated()
|
425
|
+
end
|
426
|
+
|
427
|
+
# Retorna true si el perfil en @@profile_name esta siendo trabajado por este proceso
|
428
|
+
def self.itIsMe?
|
429
|
+
# el archivo tiene una unica primera linea de ancho fijo
|
430
|
+
line_chars = 100
|
431
|
+
# obtengo el id de este proceso que esta corriendo
|
432
|
+
my_pid = PROCESS.pid
|
433
|
+
# bloqueo el archivo de este perfil
|
434
|
+
@@fd_profile_lock.flock(File::LOCK_EX)
|
435
|
+
# valido que my_pid no tenga mas caracteres que al ancho fijo
|
436
|
+
raise 'Cannot work browser profile lockfile because the lenght if the id of this process is larger than the max number of chars allowed (#{line_chars.to_s})' if line_chars < my_pid.size
|
437
|
+
# obtengo el id del proceso que se reservo este perfil
|
438
|
+
@@fd_profile_lock.seek(-line_chars, IO::SEEK_CUR)
|
439
|
+
lock_pid = @@fd_profile_lock.read.to_s
|
440
|
+
# libero el archivo de este perfil
|
441
|
+
@@fd_profile_lock.flock(File::LOCK_UN)
|
442
|
+
# return
|
443
|
+
my_pid.strip.upcase == lock_pid.strip.upcase
|
308
444
|
end
|
445
|
+
|
446
|
+
# This method is to open no more than one browser of the same profile at time.
|
447
|
+
# It will lock the file at the begining.
|
448
|
+
# If the content of the file is the PID of this process, so this process is good to start the browser.
|
449
|
+
# If the content of the file is different than the PID of this process, but such content is not equal to the PID of any other process alive, so this process is good to start the browser.
|
450
|
+
# If the content of the file is different than the PID of this process, and such content is equal to the PID of another process alive, this method unlock the file and will raise an exception.
|
451
|
+
def self.lockProfile
|
452
|
+
# el archivo tiene una unica primera linea de ancho fijo
|
453
|
+
line_chars = 100
|
454
|
+
# bloqueo el archivo de este perfil
|
455
|
+
@@fd_profile_lock.flock(File::LOCK_EX)
|
456
|
+
# obtengo el id de este proceso que esta corriendo
|
457
|
+
my_pid = PROCESS.pid
|
458
|
+
# valido que my_pid no tenga mas caracteres que al ancho fijo
|
459
|
+
raise 'Cannot work browser profile lockfile because the lenght if the id of this process is larger than the max number of chars allowed (#{line_chars.to_s})' if line_chars < my_pid.size
|
460
|
+
# obtengo el id del proceso que se reservo este perfil
|
461
|
+
lock_pid = @@fd_profile_lock.read.to_s
|
462
|
+
#
|
463
|
+
if lock_pid.size == 0
|
464
|
+
@@fd_profile_lock.write my_pid
|
465
|
+
@@fd_profile_lock.write ' ' * (line_chars - my_pid.size)
|
466
|
+
@@fd_profile_lock.flush
|
467
|
+
elsif lock_pid.strip.upcase != my_pid.strip.upcase
|
468
|
+
# verifico si el proceso que reservo este perfil esta activo
|
469
|
+
p = PROCESS.list().select { |h| h[:pid].strip.upcase == lock_pid.strip.upcase }.first
|
470
|
+
lock_process_is_alive = !p.nil?
|
471
|
+
# levanto una excepcion de bloqueo si este perfil fue reservado por otro proceso y el proceso sigue activo
|
472
|
+
if lock_process_is_alive
|
473
|
+
# libero el archivo de este perfil
|
474
|
+
@@fd_profile_lock.flock(File::LOCK_UN)
|
475
|
+
#
|
476
|
+
raise 'Profile is locked'
|
477
|
+
# me reservo este perfil si fue reservado por un proceso que ya no esta activo
|
478
|
+
else # if lock_process_is_alive
|
479
|
+
@@fd_profile_lock.seek(-line_chars, IO::SEEK_CUR)
|
480
|
+
@@fd_profile_lock.write my_pid
|
481
|
+
@@fd_profile_lock.write ' ' * (line_chars - my_pid.size)
|
482
|
+
@@fd_profile_lock.flush
|
483
|
+
end # if lock_process_is_alive
|
484
|
+
else # lock_pid.strip.upcase == my_pid.strip.upcase
|
485
|
+
# go ahead
|
486
|
+
end # if lock_pid.size == 0
|
487
|
+
end # def self.lockProfile()
|
309
488
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
rescue
|
316
|
-
end
|
317
|
-
@@fd_profile = nil
|
318
|
-
=end
|
489
|
+
# This method is to open no more than one browser of the same profile at time.
|
490
|
+
# It will unlock the file at the begining.
|
491
|
+
def self.releaseProfile
|
492
|
+
# libero el archivo de este perfil
|
493
|
+
@@fd_profile_lock.flock(File::LOCK_UN)
|
319
494
|
end
|
320
495
|
|
321
496
|
# NOTA: esta lista debe estar permitida por LinkedIn. De caso contrario, aparecera el mensaje "Upgrad your browser"
|
@@ -330,86 +505,101 @@ module BlackStack
|
|
330
505
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063",
|
331
506
|
]
|
332
507
|
|
333
|
-
#
|
334
|
-
#
|
508
|
+
# Toma una captura del area visible de la pagina.
|
509
|
+
# Mas informacion: https://stackoverflow.com/questions/25543651/screenshot-of-entire-webpage-using-selenium-webdriver-rc-rails
|
335
510
|
def self.screenshot(filename)
|
336
511
|
@@driver.save_screenshot(filename)
|
337
512
|
end
|
338
513
|
|
339
|
-
|
514
|
+
# Returns a suggested list of user-agents
|
515
|
+
def self.agents
|
340
516
|
return @@arAgents
|
341
517
|
end
|
342
518
|
|
343
|
-
|
519
|
+
# Returns the PID of the browser.
|
520
|
+
# Returns always nill if the browser is Mimic.
|
521
|
+
def self.getPid
|
344
522
|
return @@pid
|
345
523
|
end
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
524
|
+
|
525
|
+
# This method will lock the lockfile regarding this host,
|
526
|
+
# in order to get all processes in the same host launching
|
527
|
+
# one browser at time.
|
528
|
+
#
|
529
|
+
# Since chromedriver can't take one starting request at time,
|
530
|
+
# this method is to force the BrowserFactory classs, running
|
531
|
+
# in many processes of the same host at the same time, to try
|
532
|
+
# to launch browsers at the same time.
|
533
|
+
def self.lock
|
534
|
+
@@fd_host_lock.flock(File::LOCK_EX) if @@type == BlackStack::BrowserFactory::TYPE_CHROME
|
356
535
|
end
|
357
536
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
def self.reservation_id()
|
363
|
-
q = "SELECT TOP 1 reservation_id FROM browserfactory WHERE host_name='#{Socket.gethostname}'"
|
364
|
-
row = DB[q].first
|
365
|
-
if (row == nil)
|
366
|
-
DB.execute("INSERT INTO browserfactory (reservation_id, reservation_time, host_name) VALUES (NULL, NULL, '#{Socket.gethostname}')")
|
367
|
-
end
|
368
|
-
row = DB[q].first
|
369
|
-
return row[:reservation_id]
|
537
|
+
# Releases the lockfile regarding this host.
|
538
|
+
def self.release
|
539
|
+
@@fd_host_lock.flock(File::LOCK_UN) if @@type == BlackStack::BrowserFactory::TYPE_CHROME
|
370
540
|
end
|
371
541
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
542
|
+
# Close the browser only if itIsMe? returns true.
|
543
|
+
# Set nil to @@browser, @@pid, @@profile_name, @@driver, @@type.
|
544
|
+
def self.destroy
|
545
|
+
if self.itIsMe?
|
546
|
+
begin
|
547
|
+
# borro el contenido de PROFILE_LOCK_FILENAME
|
548
|
+
if !@@profile_name.nil?
|
549
|
+
fname = PROFILE_LOCK_FILENAME.gsub('%PROFILE_NAME%', @@profile_name)
|
550
|
+
File.open(fname,'w')
|
551
|
+
end
|
552
|
+
|
553
|
+
#
|
554
|
+
if @@type == BlackStack::BrowserFactory::TYPE_CHROME
|
555
|
+
# kill all child process
|
556
|
+
self.lockProfileList()
|
557
|
+
self.readPidToProfileList(@@profile_name).each { |pid|
|
558
|
+
MyProcess.kill(pid)
|
559
|
+
self.removePidToProfileList(@@profile_name, pid)
|
560
|
+
}
|
561
|
+
self.releaseProfileList()
|
562
|
+
|
563
|
+
begin
|
564
|
+
@@browser.close if !@@browser.nil?
|
565
|
+
rescue
|
566
|
+
end
|
567
|
+
|
568
|
+
elsif @@type == BlackStack::BrowserFactory::TYPE_MIMIC
|
569
|
+
begin
|
570
|
+
#@@browser.close if !@@browser.nil?
|
571
|
+
rescue
|
572
|
+
end
|
379
573
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
574
|
+
begin
|
575
|
+
# TODO: entender porque debo hacer esta llamada a start para que el perfil se cierre cuando ya estaba iniciado
|
576
|
+
BlackStack::BrowserFactory.mimic(@@profile_name) if !@@profile_name.nil?
|
577
|
+
rescue
|
578
|
+
# nothing here
|
579
|
+
end
|
580
|
+
|
581
|
+
i = 0
|
582
|
+
max = 3
|
583
|
+
success = false
|
584
|
+
while i<max && !success
|
585
|
+
i+=1
|
586
|
+
url = "http://127.0.0.1:#{BlackStack::StealthBrowserAutomation::Multilogin::mla_local_port}/api/v1/profile/stop?profileId=#{@@profile_name}"
|
587
|
+
uri = URI.parse(url)
|
588
|
+
body = Net::HTTP.get(uri)
|
589
|
+
res = JSON.parse(body)
|
590
|
+
success = true if res['status'].to_s == 'OK'
|
591
|
+
end # while i<max
|
592
|
+
raise 'Error requesting Mimic to stop (tried #{i.to_s} times)' if !success
|
593
|
+
|
594
|
+
else
|
595
|
+
raise 'Cannot destroy browser due unknown browser type'
|
596
|
+
end
|
390
597
|
rescue => e
|
391
|
-
|
392
|
-
|
393
|
-
elsif @@type == BlackStack::BrowserFactory::TYPE_MIMIC
|
394
|
-
@@browser.close if !@@browser.nil?
|
395
|
-
begin
|
396
|
-
BlackStack::BrowserFactory.mimic(@@profile_name)
|
397
|
-
rescue
|
398
|
-
# nothing here
|
598
|
+
self.release
|
599
|
+
raise e
|
399
600
|
end
|
400
|
-
|
401
|
-
|
402
|
-
success = false
|
403
|
-
while i<max && !success
|
404
|
-
i+=1
|
405
|
-
url = "http://127.0.0.1:#{BlackStack::StealthBrowserAutomation::Multilogin::mla_local_port}/api/v1/profile/stop?profileId=#{@@profile_name}"
|
406
|
-
uri = URI.parse(url)
|
407
|
-
body = Net::HTTP.get(uri)
|
408
|
-
res = JSON.parse(body)
|
409
|
-
success = true if res['status'].to_s == 'OK'
|
410
|
-
end # while i<max
|
411
|
-
raise 'Error requesting Mimic to stop (tried #{i.to_s} times)' if !success
|
412
|
-
end
|
601
|
+
end # if self.isItMe?
|
602
|
+
|
413
603
|
# reseteo las variables
|
414
604
|
@@browser = nil
|
415
605
|
@@pid = nil
|
@@ -418,7 +608,7 @@ module BlackStack
|
|
418
608
|
@@type = nil
|
419
609
|
end
|
420
610
|
|
421
|
-
#
|
611
|
+
# Returns the version of the availalble chrome browser.
|
422
612
|
def self.chrome_version
|
423
613
|
res = `reg query \"HKEY_CURRENT_USER\\Software\\Google\\Chrome\\BLBeacon\" /v version`.scan(/REG_SZ (.*)$/).first
|
424
614
|
return nil if res.nil?
|
@@ -426,7 +616,12 @@ module BlackStack
|
|
426
616
|
return nil
|
427
617
|
end
|
428
618
|
|
619
|
+
# Returns the version of the availalble chromedriver.
|
620
|
+
# The filename parameter is the full path of the chromedriver.exe command.
|
621
|
+
# If filename parameter is nil, it will look for the chromedriver.exe in the PATH environment.
|
429
622
|
#
|
623
|
+
# Not valid for Mimic, since MLA handle its own chromedriver
|
624
|
+
# into its installation folder.
|
430
625
|
def self.chromedriver_version(filename=nil)
|
431
626
|
res = `chromedriver -v`.scan(/ChromeDriver\s(.*)\s\(/).first if filename.nil?
|
432
627
|
res = `#{filename} -v`.scan(/ChromeDriver\s(.*)\s\(/).first if !filename.nil?
|
@@ -435,31 +630,23 @@ module BlackStack
|
|
435
630
|
return nil
|
436
631
|
end
|
437
632
|
|
438
|
-
#
|
439
|
-
def self.chrome(h)
|
440
|
-
# TODO: check if h is a hash
|
441
|
-
# TODO: check the variable type of each param
|
442
|
-
# TODO: check mandatory params
|
443
|
-
self.launch_chrome(
|
444
|
-
h[:proxy],
|
445
|
-
h[:load_timeout].nil? ? DEFAULT_LOAD_TIMEOUT : h[:load_timeout],
|
446
|
-
h[:user_agent],
|
447
|
-
h[:profile_name],
|
448
|
-
h[:chromedriver_path],
|
449
|
-
h[:chromedriver_signature]
|
450
|
-
)
|
451
|
-
end
|
452
|
-
|
633
|
+
# Launch a Mimic browser.
|
453
634
|
def self.mimic(mimic_profile_id)
|
635
|
+
#
|
636
|
+
@@type = BlackStack::BrowserFactory::TYPE_MIMIC
|
637
|
+
@@profile_name = mimic_profile_id
|
454
638
|
|
455
|
-
#
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
@@type = BlackStack::BrowserFactory::TYPE_MIMIC
|
460
|
-
@@profile_name = mimic_profile_id
|
639
|
+
#
|
640
|
+
fname = PROFILE_LOCK_FILENAME.gsub('%PROFILE_NAME%', @@profile_name)
|
641
|
+
File.open(fname,'w') if !File.file?(fname)
|
642
|
+
@@fd_profile_lock = File.open(fname,'r+')
|
461
643
|
|
462
|
-
|
644
|
+
begin
|
645
|
+
# Levantar el flag de reserva a mi favor
|
646
|
+
self.lock()
|
647
|
+
|
648
|
+
#
|
649
|
+
self.lockProfile()
|
463
650
|
|
464
651
|
url_2 = nil
|
465
652
|
i = 0
|
@@ -503,7 +690,7 @@ module BlackStack
|
|
503
690
|
end
|
504
691
|
rescue => e
|
505
692
|
#
|
506
|
-
|
693
|
+
self.releaseProfile()
|
507
694
|
# libero el flag de reserva de turno para crar un browser
|
508
695
|
self.release()
|
509
696
|
#
|
@@ -511,7 +698,7 @@ module BlackStack
|
|
511
698
|
end
|
512
699
|
|
513
700
|
#
|
514
|
-
|
701
|
+
self.releaseProfile()
|
515
702
|
|
516
703
|
# libero el flag de reserva de turno para crar un browser
|
517
704
|
self.release()
|
@@ -520,8 +707,28 @@ module BlackStack
|
|
520
707
|
@@browser
|
521
708
|
end
|
522
709
|
|
523
|
-
#
|
524
|
-
|
710
|
+
# It will call launch_chrome to launch a chrome browser.
|
711
|
+
# The hash parameters musy have the following keys:
|
712
|
+
# * proxy: a BlackStack::RemoteProxy object;
|
713
|
+
# * load_timeout: max number of seconds to wait a page to load;
|
714
|
+
# * user_agent: user agent of the browser;
|
715
|
+
# * profile_name: will create a folder with ths name to store all the data of the chrome profile (history, cookies, saved passwords, etc);
|
716
|
+
# * chromedriver_path: location of the chromedriver.exe file, will use DEFAULT_CHROMEDRIVER_PATH by default.
|
717
|
+
def self.chrome(h)
|
718
|
+
# TODO: check if h is a hash
|
719
|
+
# TODO: check the variable type of each param
|
720
|
+
# TODO: check mandatory params
|
721
|
+
self.launch_chrome(
|
722
|
+
h[:proxy],
|
723
|
+
h[:load_timeout].nil? ? DEFAULT_LOAD_TIMEOUT : h[:load_timeout],
|
724
|
+
h[:user_agent],
|
725
|
+
h[:profile_name],
|
726
|
+
h[:chromedriver_path]
|
727
|
+
)
|
728
|
+
end
|
729
|
+
|
730
|
+
# Launch a chrome browser.
|
731
|
+
def self.launch_chrome(proxy=nil, load_timeout=DEFAULT_LOAD_TIMEOUT, user_agent=nil, profile_name=nil, chromedriver_path=nil)
|
525
732
|
#
|
526
733
|
@@browser = nil
|
527
734
|
@@driver = nil
|
@@ -529,8 +736,9 @@ module BlackStack
|
|
529
736
|
@@profile_name = profile_name
|
530
737
|
|
531
738
|
#
|
532
|
-
fname =
|
533
|
-
|
739
|
+
fname = PROFILE_LOCK_FILENAME.gsub('%PROFILE_NAME%', @@profile_name)
|
740
|
+
File.open(fname,'w') if !File.file?(fname)
|
741
|
+
@@fd_profile_lock = File.open(fname, 'r+')
|
534
742
|
|
535
743
|
#
|
536
744
|
agent = @@arAgents[0] if user_agent.nil?
|
@@ -542,10 +750,17 @@ module BlackStack
|
|
542
750
|
#
|
543
751
|
while (@@browser == nil)
|
544
752
|
|
545
|
-
# Levantar el flag de reserva a mi favor
|
546
|
-
self.lock()
|
547
|
-
|
548
753
|
begin
|
754
|
+
# Levantar el flag de reserva a mi favor
|
755
|
+
self.lock()
|
756
|
+
|
757
|
+
#
|
758
|
+
self.lockProfile()
|
759
|
+
|
760
|
+
#
|
761
|
+
self.lockProfileList()
|
762
|
+
|
763
|
+
#
|
549
764
|
client = Selenium::WebDriver::Remote::Http::Default.new
|
550
765
|
begin
|
551
766
|
client.read_timeout = load_timeout # for newest selenium webdriver version
|
@@ -582,54 +797,54 @@ module BlackStack
|
|
582
797
|
if (proxy!=nil)
|
583
798
|
switches += proxy.chrome_switches
|
584
799
|
end
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
begin
|
589
|
-
|
590
|
-
Selenium::WebDriver::Chrome.driver_path = chromedriver_path if !chromedriver_path.nil?
|
591
|
-
Selenium::WebDriver::Chrome.driver_path = DEFAULT_CHROMEDRIVER_PATH if chromedriver_path.nil?
|
592
|
-
|
593
|
-
@@driver = Selenium::WebDriver.for :chrome, :switches => switches
|
594
|
-
bridge = @@driver.instance_variable_get(:@bridge)
|
595
|
-
service = bridge.instance_variable_get(:@service)
|
596
|
-
process = service.instance_variable_get(:@process)
|
597
|
-
@@pid = process.pid.to_s # es el PID del chromedriver
|
598
|
-
@@driver.manage.window().maximize()
|
599
|
-
@@browser = PampaBrowser.new(@@driver)
|
600
|
-
@@browser.proxy = proxy.clone if !proxy.nil?
|
601
|
-
@@browser.agent_name = agent
|
602
|
-
@@browser.profile_name = profile_name
|
603
|
-
self.updateProfileList
|
604
|
-
rescue => e
|
605
|
-
p1 = PROCESS.list().select { |p| p[:ppid] == PROCESS.pid && p[:executablepath] =~ /chromedriver(.*)\.exe/ }.first
|
606
|
-
if (p1 != nil)
|
607
|
-
@@pid = p1[:pid]
|
608
|
-
self.updateProfileList
|
609
|
-
end
|
610
|
-
self.releaseProfileList()
|
611
|
-
raise e
|
612
|
-
end
|
613
|
-
self.releaseProfileList()
|
800
|
+
|
801
|
+
Selenium::WebDriver::Chrome.driver_path = chromedriver_path if !chromedriver_path.nil?
|
802
|
+
Selenium::WebDriver::Chrome.driver_path = DEFAULT_CHROMEDRIVER_PATH if chromedriver_path.nil?
|
614
803
|
|
615
|
-
|
616
|
-
|
804
|
+
@@driver = Selenium::WebDriver.for :chrome, :switches => switches
|
805
|
+
bridge = @@driver.instance_variable_get(:@bridge)
|
806
|
+
service = bridge.instance_variable_get(:@service)
|
807
|
+
process = service.instance_variable_get(:@process)
|
808
|
+
@@pid = process.pid.to_s # es el PID del chromedriver
|
809
|
+
@@driver.manage.window().maximize()
|
810
|
+
@@browser = PampaBrowser.new(@@driver)
|
811
|
+
@@browser.proxy = proxy.clone if !proxy.nil?
|
812
|
+
@@browser.agent_name = agent
|
813
|
+
@@browser.profile_name = profile_name
|
814
|
+
self.updateProfileList
|
617
815
|
|
618
816
|
#
|
619
817
|
rescue => e # TODO: Se atrapa una expecion porque sigue ocurreiendo el error reportado en el issue #134 y #129
|
818
|
+
#
|
819
|
+
p1 = PROCESS.list().select { |p| p[:ppid] == PROCESS.pid && p[:executablepath] =~ /chromedriver\.exe/ }.first
|
820
|
+
if (p1 != nil)
|
821
|
+
@@pid = p1[:pid]
|
822
|
+
self.updateProfileList
|
823
|
+
end
|
824
|
+
self.releaseProfileList()
|
825
|
+
|
826
|
+
#
|
827
|
+
self.releaseProfile()
|
828
|
+
|
620
829
|
# Liberar el flag de reserva de creacion del browser
|
621
830
|
self.release()
|
622
831
|
|
623
832
|
# disparar la exepcion
|
624
833
|
raise e
|
625
834
|
end
|
835
|
+
|
836
|
+
#
|
837
|
+
self.releaseProfile()
|
838
|
+
|
839
|
+
# Liberar el flag de reserva de creacion del browser
|
840
|
+
self.release()
|
841
|
+
|
626
842
|
end # while
|
627
843
|
|
628
844
|
#
|
629
845
|
@@browser
|
630
846
|
end # create
|
631
847
|
|
632
|
-
|
633
848
|
end # class
|
634
849
|
|
635
850
|
end # module BlackStack
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stealth_browser_automation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leandro Daniel Sardi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mini_magick
|