24

Python プログラムは、Selenium WebDriver を介して Firefox を駆動します。コードは次のようにtry/exceptブロックに埋め込まれます。

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

エラーが原因でプログラムが中止された場合、WebDriver セッションは閉じられないため、Firefox ウィンドウは開いたままになります。しかし、プログラムがKeyboardInterrupt例外で異常終了すると、Firefox ウィンドウが閉じてしまいます (WebDriver セッションも解放されるためだと思います)。これは避けたいと思います。

"Caught exception"どちらの場合もメッセージが表示されるため、両方の例外が同じハンドラーを通過することがわかります。

で Firefox ウィンドウを閉じないようにするにはどうすればよいKeyboardInterruptですか?

4

2 に答える 2

7

私は解決策を持っていますが、それはかなり醜いです。

Ctrl+C が押されると、Python は割り込みシグナル (SIGINT) を受け取り、それがプロセス ツリー全体に伝播されます。Python は KeyboardInterrupt も生成するため、プロセスのロジックにバインドされているものを処理しようとすることはできますが子プロセスに結合されているロジックには影響を与えることができません。

子プロセスに渡されるシグナルに影響を与えるには、プロセスが を介して生成される前に、シグナルの処理方法を指定する必要がありますsubprocess.Popen

さまざまなオプションがありますが、これは別の回答から取られています:

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
)

問題は、あなたがselenium に委譲された をPopen呼び出しているのではありません。SOについてはさまざまな議論があります。私が集めたものから、信号のマスキングに影響を与えようとする他のソリューションは、 への呼び出しの直前にマスキングが実行されないと失敗する傾向があります。Popen

また、Python のドキュメントに preexec_fn の使用に関する重大な警告があるため、ご自身の判断で使用してください。

「幸いなことに」Python では実行時に関数をオーバーライドできるため、次のようにできます。

>>> 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'

次のようにmonkey.pyを使用します。

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)

startのコードは seleniumからのもので、追加された行が強調表示されています。それは大まかなハックです、それはあなたを噛むかもしれません. 頑張ってください:D

于 2018-03-16T14:36:44.707 に答える