有很多问题和各种各样的答案。问题是,在没有控制台窗口的Python进程中使用Selenium会导致它在新窗口中启动驱动程序(包括chromedriver)。
与其直接修改Selenium代码(尽管这最终需要完成),不如为它使用的ChromeWebDriver和Service类创建自己的子类。Service类是Selenium实际调用Popen来启动服务进程的地方,例如chromedriver.exe(如接受的答案中所述):import errno
import os
import platform
import subprocess
import sys
import time
import warnings
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common import utils
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from selenium.webdriver.chrome import service, webdriver, remote_connection
class HiddenChromeService(service.Service):
def start(self):
try:
cmd = [self.path]
cmd.extend(self.command_line_args())
if platform.system() == 'Windows':
info = subprocess.STARTUPINFO()
info.dwFlags = subprocess.STARTF_USESHOWWINDOW
info.wShowWindow = 0 # SW_HIDE (6 == SW_MINIMIZE)
else:
info = None
self.process = subprocess.Popen(
cmd, env=self.env,
close_fds=platform.system() != 'Windows',
startupinfo=info,
stdout=self.log_file,
stderr=self.log_file,
stdin=subprocess.PIPE)
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(
"Executable %s must be in 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't connect to the Service %s" % (
self.path,))
class HiddenChromeWebDriver(webdriver.WebDriver):
def __init__(self, executable_path="chromedriver", port=0,
options=None, service_args=None,
desired_capabilities=None, service_log_path=None,
chrome_options=None, keep_alive=True):
if chrome_options:
warnings.warn('use options instead of chrome_options',
DeprecationWarning, stacklevel=2)
options = chrome_options
if options is None:
# desired_capabilities stays as passed in
if desired_capabilities is None:
desired_capabilities = self.create_options().to_capabilities()
else:
if desired_capabilities is None:
desired_capabilities = options.to_capabilities()
else:
desired_capabilities.update(options.to_capabilities())
self.service = HiddenChromeService(
executable_path,
port=port,
service_args=service_args,
log_path=service_log_path)
self.service.start()
try:
RemoteWebDriver.__init__(
self,
command_executor=remote_connection.ChromeRemoteConnection(
remote_server_addr=self.service.service_url,
keep_alive=keep_alive),
desired_capabilities=desired_capabilities)
except Exception:
self.quit()
raise
self._is_remote = False
为了简洁起见,我删除了一些额外的注释和doc string goo。然后,您可以像使用Selenium中的官方Chrome一样使用这个自定义WebDriver:from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('headless')
headless_chrome = HiddenChromeWebDriver(chrome_options=options)
headless_chrome.get('http://www.example.com/')
headless_chrome.quit()
最后,如果创建自定义WebDriver不适合您,并且您不介意窗口闪烁和消失,那么您还可以在启动后使用win32gui library隐藏窗口:# hide chromedriver console on Windows
def enumWindowFunc(hwnd, windowList):
""" win32gui.EnumWindows() callback """
text = win32gui.GetWindowText(hwnd)
className = win32gui.GetClassName(hwnd)
if 'chromedriver' in text.lower() or 'chromedriver' in className.lower():
win32gui.ShowWindow(hwnd, False)
win32gui.EnumWindows(enumWindowFunc, [])