catch python selenium-webdriver keyboardinterrupt

python catch keyboard interrupt



Capturando `KeyboardInterrupt` sin cerrar las sesiones de Selenium Webdriver en Python (1)

Tengo una solución, pero es bastante fea.

Cuando se presiona Ctrl + C, Python recibe una señal de interrupción (SIGINT), que se propaga a lo largo de su árbol de proceso. Python también genera un Interruptor de teclado, por lo que puede tratar de manejar algo que está vinculado a la lógica de su proceso, pero la lógica que está acoplada a procesos secundarios no puede ser influenciada.

Para influir en qué señales se transmiten a los procesos de su hijo, debe especificar cómo deben manejarse las señales, antes de que el proceso se genere a través de subprocess.Popen .

Hay varias opciones, esta es tomada de otra respuesta :

import subprocess import signal def preexec_function(): # Ignore the SIGINT signal by setting the handler to the standard # signal handler SIG_IGN. signal.signal(signal.SIGINT, signal.SIG_IGN) my_process = subprocess.Popen( ["my_executable"], preexec_fn = preexec_function )

El problema es que no eres el que llama a Popen , que está delegado al selenio . Hay varias discusiones sobre SO. De lo que he recopilado, otras soluciones que intentan influir en el enmascaramiento de señales son propensas a fallar cuando el enmascaramiento no se ejecuta justo antes de la llamada a Popen .

También tenga en cuenta que hay una gran advertencia sobre el uso de preexec_fn en la documentación de Python , así que úselo a su criterio.

"Afortunadamente" python permite anular funciones en tiempo de ejecución, por lo que podríamos hacer esto:

>>> import monkey >>> import selenium.webdriver >>> selenium.webdriver.common.service.Service.start = monkey.start >>> ffx = selenium.webdriver.Firefox() >>> # pressed Ctrl+C, window stays open. KeyboardInterrupt >>> ffx.service.assert_process_still_running() >>> ffx.quit() >>> ffx.service.assert_process_still_running() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.6/site-packages/selenium/webdriver/common/service.py", line 107, in assert_process_still_running return_code = self.process.poll() AttributeError: ''NoneType'' object has no attribute ''poll''

con monkey.py como sigue:

import errno import os import platform import subprocess from subprocess import PIPE import signal import time from selenium.common.exceptions import WebDriverException from selenium.webdriver.common import utils def preexec_function(): signal.signal(signal.SIGINT, signal.SIG_IGN) def start(self): """ Starts the Service. :Exceptions: - WebDriverException : Raised either when it can''t start the service or when it can''t connect to the service """ try: cmd = [self.path] cmd.extend(self.command_line_args()) self.process = subprocess.Popen(cmd, env=self.env, close_fds=platform.system() != ''Windows'', stdout=self.log_file, stderr=self.log_file, stdin=PIPE, preexec_fn=preexec_function) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ except TypeError: raise except OSError as err: if err.errno == errno.ENOENT: raise WebDriverException( "''%s'' executable needs to be in PATH. %s" % ( os.path.basename(self.path), self.start_error_message) ) elif err.errno == errno.EACCES: raise WebDriverException( "''%s'' executable may have wrong permissions. %s" % ( os.path.basename(self.path), self.start_error_message) ) else: raise except Exception as e: raise WebDriverException( "The executable %s needs to be available in the path. %s/n%s" % (os.path.basename(self.path), self.start_error_message, str(e))) count = 0 while True: self.assert_process_still_running() if self.is_connectable(): break count += 1 time.sleep(1) if count == 30: raise WebDriverException("Can not connect to the Service %s" % self.path)

el código para el inicio es de selenio , con la línea agregada como resaltada. Es un truco crudo, bien podría morderte. Buena suerte: d

Un programa de Python controla Firefox a través de Selenium WebDriver. El código está incrustado en un bloque try / except como este:

session = selenium.webdriver.Firefox(firefox_profile) try: # do stuff except (Exception, KeyboardInterrupt) as exception: logging.info("Caught exception.") traceback.print_exc(file=sys.stdout)

Si el programa se cancela debido a un error, la sesión de WebDriver no se cierra y, por lo tanto, la ventana de Firefox se deja abierta. Pero si el programa se cancela con una excepción KeyboardInterrupt , la ventana de Firefox se cierra (supongo que porque las sesiones de WebDriver también se lanzan) y me gustaría evitar esto.

Sé que ambas excepciones pasan por el mismo controlador porque veo el mensaje "Caught exception" en ambos casos.

¿Cómo podría evitar el cierre de la ventana de Firefox con KeyboardInterrupt ?