如何隐藏 geckodriver 控制台 window?

How to hide geckodriver console window?

我是 运行 Selenium 3.141.0 python 3.6.7 windows 10

我的脚本无头运行 Firefox 驱动程序,但是 geckodriver 的控制台 window 仍然弹出。

from selenium import webdriver

options = webdriver.FirefoxOptions()
options.add_argument('-headless')
driver = webdriver.Firefox(executable_path=r'c:\webdrivers\geckodriver.exe', log_path='C:\webdrivers\geckodriver.log', firefox_options=options)
driver.get('http://10.0.0.102/')

element = WebDriverWait(driver, 20).until(
    EC.presence_of_element_located((By.ID, "body-home-tile-pgDevServ"))
)
button = driver.find_element_by_id('body-home-tile-pgDevServ')
button.click()
element = WebDriverWait(driver, 20).until(
    EC.presence_of_element_located((By.ID, "devserv-printQ-Inp"))
)
button = driver.find_element_by_id('devserv-printQ-Inp')
button.click()

经过一番折腾后,似乎添加 options.add_argument('--disable-gpu') 可以解决问题(有时)。

运行 来自 vscode 的脚本有效,运行 带有 windows 任务调度程序的脚本有效。 运行 来自 powershell 或 cmd 不工作。

我破解了 selenium 库,更改其中的代码, \AppData\Roaming\Python\Python38\site-packages\selenium\webdriver\common\service.py 第 72 行及以下,

原码为:

        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)

然后再添加两行,像这样

        try:
        cmd = [self.path]
        cmd.extend(self.command_line_args())
        CREATE_NO_WINDOW = 0x08000000
        self.process = subprocess.Popen(cmd, env=self.env,
                                        close_fds=platform.system() != 'Windows',
                                        stdout=self.log_file,
                                        stderr=self.log_file,
                                        creationflags=CREATE_NO_WINDOW,
                                        stdin=PIPE)

适用于 windows。

我找到了一种方法,基于 Anguo Zhao 的解决方案,无需编辑 selenium 文件本身即可解决此问题,方法是将其猴子修补到导入的 selenium 模块中:

import functools

from selenium import webdriver

flag = 0x08000000  # No-Window flag
# flag = 0x00000008  # Detached-Process flag, if first doesn't work
webdriver.common.service.subprocess.Popen = functools.partial(
    webdriver.common.service.subprocess.Popen, creationflags=flag)

如果您认为这可能会被执行多次:

import functools
import subprocess

from selenium import webdriver

flag = 0x08000000  # No-Window flag
webdriver.common.service.subprocess.Popen = functools.partial(
    subprocess.Popen, creationflags=flag)

我在 selenium 模块中找不到可以单独使用 creationflags 的地方,因此应该不会破坏任何东西(截至目前)。

自然语言解释:

使用 functools.partial,我们创建一个“准备好的”Popen-调用,其中已经包含 creationflags-参数。
然后,我们将 selenium 尝试调用的原始 Popen 替换为准备好的
瞧,每当 selenium.webdriver.common.service 中的某物试图创建一个 Popen 对象时,它将是已经准备好创建标志的对象。