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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/browserfactory.rb +382 -167
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a69446713baa56fc8ce31194cad216bd8cfb781b
4
- data.tar.gz: 0b8821a33b1a8a2dd9323e4d055b7964285cd9a6
3
+ metadata.gz: 8e5b7d022b4081943660188d38da808fde5a8fb4
4
+ data.tar.gz: 7d78271edc4513a15d1a8b5ffc97b73ce3954396
5
5
  SHA512:
6
- metadata.gz: 022264107d17a0cf48a8467e3cdab944f1edf9072a61d4575491ddf8bd57e4c6c853c3b55d16fd792166bbbf6dd0d922963992d32468f4c8fd8f16d61dbab977
7
- data.tar.gz: 812b9580f4c2ef495751b0ee4d1c8f071a5f28066b7298d766da817ddf88c3983dbdcae283731ab753a33752438e0b2e5996b06cbd6fe9e17c9e9ea4d567a1ca
6
+ metadata.gz: b2a3ac895d730e2411fe797056c01b8faba33b84b1a9bf3c7a8c96cf3c669d5ff3abfc2751cc304a5e6bea1d5bddfcc959ab3c3fa625ee74ea3500eed8b9fdbc
7
+ data.tar.gz: 543b5abc9fa2a7ca7f891964439bd4eceaf8cd71b357cdfd60fa765e75c3d559aa0147e9b878872f0f8b69dbd9772cd1ba6f0d23916864edd4a81b49d1cd2bd3
@@ -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.%PRFILE_NAME%.lock' # manejo de concurrencia en la creación de browsers
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('%PRFILE_NAME%', self.profile_name.to_s)
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
- LOCKING_FILENAME = BlackStack::MyProcess.macaddress # manejo de concurrencia en la creación de browsers
250
- PROFILE_PID_LIST_FILENAME = "./browserfactory.%PRFILE_NAME%.list" # manejo de concurrencia en la creación de browsers
251
- PROFILE_PID_LOCK_FILENAME = "./browserfactory.%PRFILE_NAME%.lock" # manejo de concurrencia en la creación de browsers
252
- CHROME_EXTENSION_DIRECTORY = File.absolute_path('./chrome_extension')
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('%PRFILE_NAME%', profile_name)
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('%PRFILE_NAME%', profile_name)
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 (profile_name != nil)
274
- fname = PROFILE_PID_LIST_FILENAME.gsub('%PRFILE_NAME%', profile_name)
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
- def self.updateProfileList()
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 && (p[:executablepath] =~ /chrome\.exe/ || p[:executablepath] =~ /mimic/) }.each { |p2|
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
- TYPE_PHANTOMJS = 0 # discontinued!
290
- TYPE_FIREFOX = 1
291
- TYPE_CHROME = 2
292
- TYPE_MIMIC = 3
293
-
294
- @@fd = File.open(LOCKING_FILENAME,"w")
295
- @@fd_profile = nil
296
- @@driver = nil
297
- @@browser = nil
298
- @@pid = nil
299
- @@profile_name = nil
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
- def self.lockProfileList()
307
- # @@fd_profile.flock(File::LOCK_EX)
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
- def self.releaseProfileList()
311
- # @@fd_profile.flock(File::LOCK_UN)
312
- =begin
313
- begin
314
- @@fd_profile.close
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
- # toma una captura del area visible de la pagina
334
- # mas informacion: https://stackoverflow.com/questions/25543651/screenshot-of-entire-webpage-using-selenium-webdriver-rc-rails
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
- def self.agents()
514
+ # Returns a suggested list of user-agents
515
+ def self.agents
340
516
  return @@arAgents
341
517
  end
342
518
 
343
- def self.getPid()
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
- def self.isCreated()
348
- if (self.readPidToProfileList(@@profile_name).size>0)
349
- return true
350
- end
351
- if (@@browser != nil)
352
- return true
353
- end
354
-
355
- return false
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
- def self.isCreated?
359
- self.isCreated()
360
- end
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
- def self.lock()
373
- @@fd.flock(File::LOCK_EX)
374
- end
375
-
376
- def self.release()
377
- @@fd.flock(File::LOCK_UN)
378
- end
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
- def self.destroy()
381
- if @@type == BlackStack::BrowserFactory::TYPE_CHROME
382
- self.lockProfileList()
383
- self.readPidToProfileList(@@profile_name).each { |pid|
384
- MyProcess.kill(pid)
385
- self.removePidToProfileList(@@profile_name, pid)
386
- }
387
- self.releaseProfileList()
388
- begin
389
- @@browser.close if !@@browser.nil?
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
- end
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
- i = 0
401
- max = 3
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
- # Levantar el flag de reserva a mi favor
456
- self.lock()
457
-
458
- begin
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
- #self.lockProfileList()
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
- #self.releaseProfileList()
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
- #self.releaseProfileList()
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
- def self.launch_chrome(proxy=nil, load_timeout=DEFAULT_LOAD_TIMEOUT, user_agent=nil, profile_name=nil, chromedriver_path=nil, chromedriver_signature=nil)
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 = PROFILE_PID_LOCK_FILENAME.gsub('%PRFILE_NAME%', @@profile_name)
533
- @@fd_profile = File.open(fname,"w")
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
- self.lockProfileList()
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
- # Liberar el flag de reserva de creacion del browser
616
- self.release()
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.8
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 00:00:00.000000000 Z
11
+ date: 2020-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mini_magick