2235 lines
88 KiB
Python
Executable File
2235 lines
88 KiB
Python
Executable File
import logging
|
|
import os
|
|
import re
|
|
import sys
|
|
import urllib3
|
|
import warnings
|
|
from selenium import webdriver
|
|
from selenium.webdriver.chrome.service import Service as ChromeService
|
|
from selenium.webdriver.edge.service import Service as EdgeService
|
|
from selenium.webdriver.firefox.service import Service as FirefoxService
|
|
from seleniumbase.config import settings
|
|
from seleniumbase.core import download_helper
|
|
from seleniumbase.core import proxy_helper
|
|
from seleniumbase.fixtures import constants
|
|
from seleniumbase import drivers # webdriver storage folder for SeleniumBase
|
|
from seleniumbase import extensions # browser extensions storage folder
|
|
|
|
urllib3.disable_warnings()
|
|
selenium4 = False
|
|
if sys.version_info[0] == 3 and sys.version_info[1] >= 7:
|
|
selenium4 = True
|
|
from selenium.webdriver.common.options import ArgOptions
|
|
|
|
DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__))
|
|
# Make sure that the SeleniumBase DRIVER_DIR is at the top of the System PATH
|
|
# (Changes to the System PATH with os.environ only last during the test run)
|
|
if not os.environ["PATH"].startswith(DRIVER_DIR):
|
|
# Remove existing SeleniumBase DRIVER_DIR from System PATH if present
|
|
os.environ["PATH"] = os.environ["PATH"].replace(DRIVER_DIR, "")
|
|
# If two path separators are next to each other, replace with just one
|
|
os.environ["PATH"] = os.environ["PATH"].replace(
|
|
os.pathsep + os.pathsep, os.pathsep
|
|
)
|
|
# Put the SeleniumBase DRIVER_DIR at the beginning of the System PATH
|
|
os.environ["PATH"] = DRIVER_DIR + os.pathsep + os.environ["PATH"]
|
|
EXTENSIONS_DIR = os.path.dirname(os.path.realpath(extensions.__file__))
|
|
DISABLE_CSP_ZIP_PATH = "%s/%s" % (EXTENSIONS_DIR, "disable_csp.zip")
|
|
AD_BLOCK_ZIP_PATH = "%s/%s" % (EXTENSIONS_DIR, "ad_block.zip")
|
|
RECORDER_ZIP_PATH = "%s/%s" % (EXTENSIONS_DIR, "recorder.zip")
|
|
PROXY_ZIP_PATH = proxy_helper.PROXY_ZIP_PATH
|
|
PROXY_ZIP_LOCK = proxy_helper.PROXY_ZIP_LOCK
|
|
PLATFORM = sys.platform
|
|
IS_WINDOWS = False
|
|
LOCAL_CHROMEDRIVER = None
|
|
LOCAL_GECKODRIVER = None
|
|
LOCAL_EDGEDRIVER = None
|
|
LOCAL_IEDRIVER = None
|
|
LOCAL_HEADLESS_IEDRIVER = None
|
|
LOCAL_OPERADRIVER = None
|
|
if "darwin" in PLATFORM or "linux" in PLATFORM:
|
|
LOCAL_CHROMEDRIVER = DRIVER_DIR + "/chromedriver"
|
|
LOCAL_GECKODRIVER = DRIVER_DIR + "/geckodriver"
|
|
LOCAL_EDGEDRIVER = DRIVER_DIR + "/msedgedriver"
|
|
LOCAL_OPERADRIVER = DRIVER_DIR + "/operadriver"
|
|
elif "win32" in PLATFORM or "win64" in PLATFORM or "x64" in PLATFORM:
|
|
IS_WINDOWS = True
|
|
LOCAL_EDGEDRIVER = DRIVER_DIR + "/msedgedriver.exe"
|
|
LOCAL_IEDRIVER = DRIVER_DIR + "/IEDriverServer.exe"
|
|
LOCAL_HEADLESS_IEDRIVER = DRIVER_DIR + "/headless_ie_selenium.exe"
|
|
LOCAL_CHROMEDRIVER = DRIVER_DIR + "/chromedriver.exe"
|
|
LOCAL_GECKODRIVER = DRIVER_DIR + "/geckodriver.exe"
|
|
LOCAL_OPERADRIVER = DRIVER_DIR + "/operadriver.exe"
|
|
else:
|
|
# Cannot determine system
|
|
pass # SeleniumBase will use web drivers from the System PATH by default
|
|
|
|
|
|
def make_executable(file_path):
|
|
# Set permissions to: "If you can read it, you can execute it."
|
|
mode = os.stat(file_path).st_mode
|
|
mode |= (mode & 0o444) >> 2 # copy R bits to X
|
|
os.chmod(file_path, mode)
|
|
|
|
|
|
def make_driver_executable_if_not(driver_path):
|
|
# Verify driver has executable permissions. If not, add them.
|
|
permissions = oct(os.stat(driver_path)[0])[-3:]
|
|
if "4" in permissions or "6" in permissions:
|
|
# We want at least a '5' or '7' to make sure it's executable
|
|
make_executable(driver_path)
|
|
|
|
|
|
def is_chromedriver_on_path():
|
|
paths = os.environ["PATH"].split(os.pathsep)
|
|
for path in paths:
|
|
if (not IS_WINDOWS) and os.path.exists(path + "/chromedriver"):
|
|
return True
|
|
elif IS_WINDOWS and os.path.exists(path + "/chromedriver.exe"):
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_edgedriver_on_path():
|
|
return os.path.exists(LOCAL_EDGEDRIVER)
|
|
|
|
|
|
def is_geckodriver_on_path():
|
|
paths = os.environ["PATH"].split(os.pathsep)
|
|
for path in paths:
|
|
if (not IS_WINDOWS) and os.path.exists(path + "/geckodriver"):
|
|
return True
|
|
elif IS_WINDOWS and os.path.exists(path + "/geckodriver.exe"):
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_iedriver_on_path():
|
|
paths = os.environ["PATH"].split(os.pathsep)
|
|
for path in paths:
|
|
if os.path.exists(path + "/IEDriverServer.exe"):
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_headless_iedriver_on_path():
|
|
return os.path.exists(LOCAL_HEADLESS_IEDRIVER)
|
|
|
|
|
|
def _repair_chromedriver(chrome_options, headless_options, mcv=None):
|
|
import subprocess
|
|
|
|
if mcv:
|
|
subprocess.check_call(
|
|
"sbase install chromedriver %s" % mcv, shell=True
|
|
)
|
|
return
|
|
driver = None
|
|
subprocess.check_call(
|
|
"sbase install chromedriver 72.0.3626.69", shell=True
|
|
)
|
|
try:
|
|
if selenium4:
|
|
service = ChromeService(executable_path=LOCAL_CHROMEDRIVER)
|
|
driver = webdriver.Chrome(
|
|
service=service,
|
|
options=headless_options,
|
|
)
|
|
else:
|
|
driver = webdriver.Chrome(
|
|
executable_path=LOCAL_CHROMEDRIVER,
|
|
options=headless_options,
|
|
)
|
|
except Exception:
|
|
subprocess.check_call(
|
|
"sbase install chromedriver latest-1", shell=True
|
|
)
|
|
return
|
|
chrome_version = None
|
|
if "version" in driver.capabilities:
|
|
chrome_version = driver.capabilities["version"]
|
|
else:
|
|
chrome_version = driver.capabilities["browserVersion"]
|
|
major_chrome_ver = chrome_version.split(".")[0]
|
|
chrome_dict = driver.capabilities["chrome"]
|
|
driver.quit()
|
|
chromedriver_ver = chrome_dict["chromedriverVersion"]
|
|
chromedriver_ver = chromedriver_ver.split(" ")[0]
|
|
major_chromedriver_ver = chromedriver_ver.split(".")[0]
|
|
if (
|
|
major_chromedriver_ver != major_chrome_ver
|
|
and int(major_chrome_ver) >= 73
|
|
):
|
|
subprocess.check_call(
|
|
"sbase install chromedriver %s" % major_chrome_ver, shell=True
|
|
)
|
|
return
|
|
|
|
|
|
def _repair_edgedriver(edge_version):
|
|
import subprocess
|
|
|
|
print(
|
|
"\nWarning: msedgedriver version doesn't match Edge version!"
|
|
"\nAttempting to install a matching version of msedgedriver:"
|
|
)
|
|
subprocess.check_call(
|
|
"sbase install edgedriver %s" % edge_version, shell=True
|
|
)
|
|
return
|
|
|
|
|
|
def _mark_driver_repaired():
|
|
import codecs
|
|
|
|
abs_path = os.path.abspath(".")
|
|
driver_repaired_lock = constants.MultiBrowser.DRIVER_REPAIRED
|
|
file_path = os.path.join(abs_path, driver_repaired_lock)
|
|
downloads_folder = download_helper.get_downloads_folder()
|
|
if not os.path.exists(downloads_folder):
|
|
os.makedirs(downloads_folder)
|
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
|
out_file.writelines("")
|
|
out_file.close()
|
|
|
|
|
|
def _was_driver_repaired():
|
|
abs_path = os.path.abspath(".")
|
|
driver_repaired_lock = constants.MultiBrowser.DRIVER_REPAIRED
|
|
file_path = os.path.join(abs_path, driver_repaired_lock)
|
|
return os.path.exists(file_path)
|
|
|
|
|
|
def _add_chrome_proxy_extension(
|
|
chrome_options, proxy_string, proxy_user, proxy_pass
|
|
):
|
|
"""Implementation of https://stackoverflow.com/a/35293284 for
|
|
https://stackoverflow.com/questions/12848327/
|
|
(Run Selenium on a proxy server that requires authentication.)"""
|
|
arg_join = " ".join(sys.argv)
|
|
if not ("-n" in sys.argv or " -n=" in arg_join or arg_join == "-c"):
|
|
# Single-threaded
|
|
proxy_helper.create_proxy_zip(proxy_string, proxy_user, proxy_pass)
|
|
proxy_zip = PROXY_ZIP_PATH
|
|
chrome_options.add_extension(proxy_zip)
|
|
else:
|
|
# Pytest multi-threaded test
|
|
import fasteners
|
|
|
|
proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
|
|
with proxy_zip_lock:
|
|
if not os.path.exists(PROXY_ZIP_PATH):
|
|
proxy_helper.create_proxy_zip(
|
|
proxy_string, proxy_user, proxy_pass
|
|
)
|
|
proxy_zip = PROXY_ZIP_PATH
|
|
chrome_options.add_extension(proxy_zip)
|
|
return chrome_options
|
|
|
|
|
|
def _add_chrome_disable_csp_extension(chrome_options):
|
|
"""Disable Chrome's Content-Security-Policy with a browser extension.
|
|
See https://github.com/PhilGrayson/chrome-csp-disable for details."""
|
|
disable_csp_zip = DISABLE_CSP_ZIP_PATH
|
|
chrome_options.add_extension(disable_csp_zip)
|
|
return chrome_options
|
|
|
|
|
|
def _add_chrome_ad_block_extension(chrome_options):
|
|
"""Block Ads on Chromium Browsers with a browser extension.
|
|
See https://github.com/slingamn/simpleblock for details."""
|
|
ad_block_zip = AD_BLOCK_ZIP_PATH
|
|
chrome_options.add_extension(ad_block_zip)
|
|
return chrome_options
|
|
|
|
|
|
def _add_chrome_recorder_extension(chrome_options):
|
|
"""The SeleniumBase Recorder Chrome/Edge extension.
|
|
https://seleniumbase.io/help_docs/recorder_mode/"""
|
|
recorder_zip = RECORDER_ZIP_PATH
|
|
chrome_options.add_extension(recorder_zip)
|
|
return chrome_options
|
|
|
|
|
|
def _set_chrome_options(
|
|
browser_name,
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
servername,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
):
|
|
chrome_options = webdriver.ChromeOptions()
|
|
if browser_name == constants.Browser.OPERA:
|
|
chrome_options = webdriver.opera.options.Options()
|
|
prefs = {
|
|
"download.default_directory": downloads_path,
|
|
"local_discovery.notifications_enabled": False,
|
|
"credentials_enable_service": False,
|
|
"download.prompt_for_download": False,
|
|
"download.directory_upgrade": True,
|
|
"safebrowsing.enabled": False,
|
|
"safebrowsing.disable_download_protection": True,
|
|
"default_content_setting_values.notifications": 0,
|
|
"default_content_settings.popups": 0,
|
|
"managed_default_content_settings.popups": 0,
|
|
"content_settings.exceptions.automatic_downloads.*.setting": 1,
|
|
"profile.password_manager_enabled": False,
|
|
"profile.default_content_setting_values.notifications": 2,
|
|
"profile.default_content_settings.popups": 0,
|
|
"profile.managed_default_content_settings.popups": 0,
|
|
"profile.default_content_setting_values.automatic_downloads": 1,
|
|
}
|
|
if locale_code:
|
|
prefs["intl.accept_languages"] = locale_code
|
|
if block_images:
|
|
prefs["profile.managed_default_content_settings.images"] = 2
|
|
if external_pdf:
|
|
prefs["plugins.always_open_pdf_externally"] = True
|
|
chrome_options.add_experimental_option("prefs", prefs)
|
|
chrome_options.add_experimental_option("w3c", True)
|
|
if enable_sync:
|
|
chrome_options.add_experimental_option(
|
|
"excludeSwitches",
|
|
["enable-automation", "enable-logging", "disable-sync"],
|
|
)
|
|
chrome_options.add_argument("--enable-sync")
|
|
else:
|
|
chrome_options.add_experimental_option(
|
|
"excludeSwitches",
|
|
["enable-automation", "enable-logging", "enable-blink-features"],
|
|
)
|
|
if browser_name == constants.Browser.OPERA:
|
|
# Disable the Blink features
|
|
if enable_sync:
|
|
chrome_options.add_experimental_option(
|
|
"excludeSwitches",
|
|
(
|
|
[
|
|
"enable-automation",
|
|
"enable-logging",
|
|
"disable-sync",
|
|
"enable-blink-features",
|
|
]
|
|
),
|
|
)
|
|
chrome_options.add_argument("--enable-sync")
|
|
else:
|
|
chrome_options.add_experimental_option(
|
|
"excludeSwitches",
|
|
(
|
|
[
|
|
"enable-automation",
|
|
"enable-logging",
|
|
"enable-blink-features",
|
|
]
|
|
),
|
|
)
|
|
if mobile_emulator:
|
|
emulator_settings = {}
|
|
device_metrics = {}
|
|
if (
|
|
type(device_width) is int
|
|
and type(device_height) is int
|
|
and type(device_pixel_ratio) is int
|
|
):
|
|
device_metrics["width"] = device_width
|
|
device_metrics["height"] = device_height
|
|
device_metrics["pixelRatio"] = device_pixel_ratio
|
|
else:
|
|
device_metrics["width"] = 360
|
|
device_metrics["height"] = 640
|
|
device_metrics["pixelRatio"] = 2
|
|
emulator_settings["deviceMetrics"] = device_metrics
|
|
if user_agent:
|
|
emulator_settings["userAgent"] = user_agent
|
|
chrome_options.add_experimental_option(
|
|
"mobileEmulation", emulator_settings
|
|
)
|
|
if (
|
|
not proxy_auth
|
|
and not disable_csp
|
|
and not ad_block_on
|
|
and not recorder_ext
|
|
and (not extension_zip and not extension_dir)
|
|
):
|
|
if incognito:
|
|
# Use Chrome's Incognito Mode
|
|
# Incognito Mode prevents Chrome extensions from loading,
|
|
# so if using extensions or a feature that uses extensions,
|
|
# then Chrome's Incognito mode will be disabled instead.
|
|
chrome_options.add_argument("--incognito")
|
|
elif guest_mode:
|
|
# Use Chrome's Guest Mode
|
|
# Guest mode prevents Chrome extensions from loading,
|
|
# so if using extensions or a feature that uses extensions,
|
|
# then Chrome's Guest Mode will be disabled instead.
|
|
chrome_options.add_argument("--guest")
|
|
else:
|
|
pass
|
|
if user_data_dir:
|
|
abs_path = os.path.abspath(user_data_dir)
|
|
chrome_options.add_argument("user-data-dir=%s" % abs_path)
|
|
if extension_zip:
|
|
# Can be a comma-separated list of .ZIP or .CRX files
|
|
extension_zip_list = extension_zip.split(",")
|
|
for extension_zip_item in extension_zip_list:
|
|
abs_path = os.path.abspath(extension_zip_item)
|
|
chrome_options.add_extension(abs_path)
|
|
if extension_dir:
|
|
# load-extension input can be a comma-separated list
|
|
abs_path = os.path.abspath(extension_dir)
|
|
chrome_options.add_argument("--load-extension=%s" % abs_path)
|
|
chrome_options.add_argument("--test-type")
|
|
chrome_options.add_argument("--log-level=3")
|
|
chrome_options.add_argument("--no-first-run")
|
|
if devtools and not headless:
|
|
chrome_options.add_argument("--auto-open-devtools-for-tabs")
|
|
chrome_options.add_argument("--allow-file-access-from-files")
|
|
chrome_options.add_argument("--allow-insecure-localhost")
|
|
chrome_options.add_argument("--allow-running-insecure-content")
|
|
if user_agent:
|
|
chrome_options.add_argument("--user-agent=%s" % user_agent)
|
|
chrome_options.add_argument("--disable-infobars")
|
|
chrome_options.add_argument("--disable-notifications")
|
|
chrome_options.add_argument("--disable-save-password-bubble")
|
|
chrome_options.add_argument("--disable-single-click-autofill")
|
|
chrome_options.add_argument(
|
|
"--disable-autofill-keyboard-accessory-view[8]"
|
|
)
|
|
chrome_options.add_argument("--disable-translate")
|
|
chrome_options.add_argument("--homepage=about:blank")
|
|
chrome_options.add_argument("--dns-prefetch-disable")
|
|
chrome_options.add_argument("--dom-automation")
|
|
chrome_options.add_argument("--disable-hang-monitor")
|
|
chrome_options.add_argument("--disable-prompt-on-repost")
|
|
if servername != "localhost":
|
|
use_auto_ext = True # Use Automation Extension with the Selenium Grid
|
|
if not use_auto_ext: # Disable Automation Extension / detection. (Default)
|
|
if browser_name != constants.Browser.OPERA:
|
|
chrome_options.add_argument(
|
|
"--disable-blink-features=AutomationControlled"
|
|
)
|
|
chrome_options.add_experimental_option("useAutomationExtension", False)
|
|
if (settings.DISABLE_CSP_ON_CHROME or disable_csp) and not headless:
|
|
# Headless Chrome does not support extensions, which are required
|
|
# for disabling the Content Security Policy on Chrome.
|
|
chrome_options = _add_chrome_disable_csp_extension(chrome_options)
|
|
if ad_block_on and not headless:
|
|
# Headless Chrome does not support extensions.
|
|
chrome_options = _add_chrome_ad_block_extension(chrome_options)
|
|
if recorder_ext and not headless:
|
|
chrome_options = _add_chrome_recorder_extension(chrome_options)
|
|
if proxy_string:
|
|
if proxy_auth:
|
|
chrome_options = _add_chrome_proxy_extension(
|
|
chrome_options, proxy_string, proxy_user, proxy_pass
|
|
)
|
|
chrome_options.add_argument("--proxy-server=%s" % proxy_string)
|
|
if proxy_bypass_list:
|
|
chrome_options.add_argument(
|
|
"--proxy-bypass-list=%s" % proxy_bypass_list
|
|
)
|
|
elif proxy_pac_url:
|
|
if proxy_auth:
|
|
chrome_options = _add_chrome_proxy_extension(
|
|
chrome_options, None, proxy_user, proxy_pass
|
|
)
|
|
chrome_options.add_argument("--proxy-pac-url=%s" % proxy_pac_url)
|
|
if headless:
|
|
if not proxy_auth and not browser_name == constants.Browser.OPERA:
|
|
# Headless Chrome doesn't support extensions, which are
|
|
# required when using a proxy server that has authentication.
|
|
# Instead, base_case.py will use PyVirtualDisplay when not
|
|
# using Chrome's built-in headless mode. See link for details:
|
|
# https://bugs.chromium.org/p/chromium/issues/detail?id=706008
|
|
# Also, Opera Chromium doesn't support headless mode:
|
|
# https://github.com/operasoftware/operachromiumdriver/issues/62
|
|
chrome_options.add_argument("--headless")
|
|
if browser_name != constants.Browser.OPERA:
|
|
# Opera Chromium doesn't support these switches
|
|
chrome_options.add_argument("--ignore-certificate-errors")
|
|
if not enable_ws:
|
|
chrome_options.add_argument("--disable-web-security")
|
|
chrome_options.add_argument("--no-sandbox")
|
|
else:
|
|
# Opera Chromium only!
|
|
chrome_options.add_argument("--allow-elevated-browser")
|
|
if remote_debug:
|
|
# To access the Remote Debugger, go to: http://localhost:9222
|
|
# while a Chromium driver is running.
|
|
# Info: https://chromedevtools.github.io/devtools-protocol/
|
|
chrome_options.add_argument("--remote-debugging-port=9222")
|
|
if swiftshader:
|
|
chrome_options.add_argument("--use-gl=swiftshader")
|
|
else:
|
|
chrome_options.add_argument("--disable-gpu")
|
|
if "linux" in PLATFORM:
|
|
chrome_options.add_argument("--disable-dev-shm-usage")
|
|
if chromium_arg:
|
|
# Can be a comma-separated list of Chromium args
|
|
chromium_arg_list = chromium_arg.split(",")
|
|
for chromium_arg_item in chromium_arg_list:
|
|
chromium_arg_item = chromium_arg_item.strip()
|
|
if not chromium_arg_item.startswith("--"):
|
|
if chromium_arg_item.startswith("-"):
|
|
chromium_arg_item = "-" + chromium_arg_item
|
|
else:
|
|
chromium_arg_item = "--" + chromium_arg_item
|
|
if len(chromium_arg_item) >= 3:
|
|
chrome_options.add_argument(chromium_arg_item)
|
|
return chrome_options
|
|
|
|
|
|
def _set_firefox_options(
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
disable_csp,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
):
|
|
options = webdriver.FirefoxOptions()
|
|
options.accept_untrusted_certs = True
|
|
options.set_preference("reader.parse-on-load.enabled", False)
|
|
options.set_preference("pdfjs.disabled", True)
|
|
options.set_preference("app.update.auto", False)
|
|
options.set_preference("app.update.enabled", False)
|
|
options.set_preference("app.update.silent", True)
|
|
options.set_preference("browser.formfill.enable", False)
|
|
options.set_preference("browser.privatebrowsing.autostart", False)
|
|
options.set_preference("devtools.errorconsole.enabled", True)
|
|
options.set_preference("dom.webnotifications.enabled", False)
|
|
options.set_preference("dom.disable_beforeunload", True)
|
|
options.set_preference("browser.contentblocking.database.enabled", True)
|
|
options.set_preference("extensions.allowPrivateBrowsingByDefault", True)
|
|
options.set_preference("extensions.PrivateBrowsing.notification", False)
|
|
options.set_preference("extensions.systemAddon.update.enabled", False)
|
|
options.set_preference("extensions.update.autoUpdateDefault", False)
|
|
options.set_preference("extensions.update.enabled", False)
|
|
options.set_preference("extensions.update.silent", True)
|
|
options.set_preference("datareporting.healthreport.service.enabled", False)
|
|
options.set_preference("datareporting.healthreport.uploadEnabled", False)
|
|
options.set_preference("datareporting.policy.dataSubmissionEnabled", False)
|
|
options.set_preference("toolkit.telemetry.unified", False)
|
|
if proxy_string:
|
|
socks_proxy = False
|
|
socks_ver = 0
|
|
chunks = proxy_string.split(":")
|
|
if len(chunks) == 3 and (
|
|
chunks[0] == "socks4" or chunks[0] == "socks5"
|
|
):
|
|
socks_proxy = True
|
|
socks_ver = int(chunks[0][5])
|
|
if chunks[1].startswith("//") and len(chunks[1]) > 2:
|
|
chunks[1] = chunks[1][2:]
|
|
proxy_server = chunks[1]
|
|
proxy_port = chunks[2]
|
|
else:
|
|
proxy_server = proxy_string.split(":")[0]
|
|
proxy_port = proxy_string.split(":")[1]
|
|
options.set_preference("network.proxy.type", 1)
|
|
if socks_proxy:
|
|
options.set_preference("network.proxy.socks", proxy_server)
|
|
options.set_preference("network.proxy.socks_port", int(proxy_port))
|
|
options.set_preference("network.proxy.socks_version", socks_ver)
|
|
else:
|
|
options.set_preference("network.proxy.http", proxy_server)
|
|
options.set_preference("network.proxy.http_port", int(proxy_port))
|
|
options.set_preference("network.proxy.ssl", proxy_server)
|
|
options.set_preference("network.proxy.ssl_port", int(proxy_port))
|
|
if proxy_bypass_list:
|
|
options.set_preference("no_proxies_on", proxy_bypass_list)
|
|
elif proxy_pac_url:
|
|
options.set_preference("network.proxy.type", 2)
|
|
options.set_preference("network.proxy.autoconfig_url", proxy_pac_url)
|
|
if user_agent:
|
|
options.set_preference("general.useragent.override", user_agent)
|
|
options.set_preference(
|
|
"security.mixed_content.block_active_content", False
|
|
)
|
|
if settings.DISABLE_CSP_ON_FIREFOX or disable_csp:
|
|
options.set_preference("security.csp.enable", False)
|
|
options.set_preference(
|
|
"browser.download.manager.showAlertOnComplete", False
|
|
)
|
|
if headless and "linux" not in PLATFORM:
|
|
options.add_argument("--headless")
|
|
if locale_code:
|
|
options.set_preference("intl.accept_languages", locale_code)
|
|
options.set_preference("browser.shell.checkDefaultBrowser", False)
|
|
options.set_preference("browser.startup.page", 0)
|
|
options.set_preference("browser.download.panel.shown", False)
|
|
options.set_preference("browser.download.animateNotifications", False)
|
|
options.set_preference("browser.download.dir", downloads_path)
|
|
options.set_preference("browser.download.folderList", 2)
|
|
options.set_preference("browser.helperApps.alwaysAsk.force", False)
|
|
options.set_preference("browser.download.manager.showWhenStarting", False)
|
|
options.set_preference(
|
|
"browser.helperApps.neverAsk.saveToDisk",
|
|
(
|
|
"application/pdf, application/zip, application/octet-stream, "
|
|
"text/csv, text/xml, application/xml, text/plain, "
|
|
"text/octet-stream, application/x-gzip, application/x-tar "
|
|
"application/"
|
|
"vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
),
|
|
)
|
|
if firefox_arg:
|
|
# Can be a comma-separated list of Firefox args
|
|
firefox_arg_list = firefox_arg.split(",")
|
|
for firefox_arg_item in firefox_arg_list:
|
|
firefox_arg_item = firefox_arg_item.strip()
|
|
if not firefox_arg_item.startswith("--"):
|
|
if firefox_arg_item.startswith("-"):
|
|
firefox_arg_item = "-" + firefox_arg_item
|
|
else:
|
|
firefox_arg_item = "--" + firefox_arg_item
|
|
if len(firefox_arg_item) >= 3:
|
|
options.add_argument(firefox_arg_item)
|
|
if firefox_pref:
|
|
# Can be a comma-separated list of Firefox preference:value pairs
|
|
firefox_pref_list = firefox_pref.split(",")
|
|
for firefox_pref_item in firefox_pref_list:
|
|
f_pref = None
|
|
f_pref_value = None
|
|
needs_conversion = False
|
|
if firefox_pref_item.count(":") == 0:
|
|
f_pref = firefox_pref_item
|
|
f_pref_value = True
|
|
elif firefox_pref_item.count(":") == 1:
|
|
f_pref = firefox_pref_item.split(":")[0]
|
|
f_pref_value = firefox_pref_item.split(":")[1]
|
|
needs_conversion = True
|
|
else: # More than one ":" in the set. (Too many!)
|
|
raise Exception(
|
|
'Incorrect formatting for Firefox "pref:value" set!'
|
|
)
|
|
if needs_conversion:
|
|
if f_pref_value.lower() == "true" or len(f_pref_value) == 0:
|
|
f_pref_value = True
|
|
elif f_pref_value.lower() == "false":
|
|
f_pref_value = False
|
|
elif f_pref_value.isdigit():
|
|
f_pref_value = int(f_pref_value)
|
|
elif f_pref_value.isdecimal():
|
|
f_pref_value = float(f_pref_value)
|
|
else:
|
|
pass # keep as string
|
|
if len(f_pref) >= 1:
|
|
options.set_preference(f_pref, f_pref_value)
|
|
return options
|
|
|
|
|
|
def display_proxy_warning(proxy_string):
|
|
message = (
|
|
'\n\nWARNING: Proxy String ["%s"] is NOT in the expected '
|
|
'"ip_address:port" or "server:port" format, '
|
|
"(OR the key does not exist in "
|
|
"seleniumbase.config.proxy_list.PROXY_LIST)." % proxy_string
|
|
)
|
|
if settings.RAISE_INVALID_PROXY_STRING_EXCEPTION:
|
|
raise Exception(message)
|
|
else:
|
|
message += " *** DEFAULTING to NOT USING a Proxy Server! ***"
|
|
warnings.simplefilter("always", Warning) # See Warnings
|
|
warnings.warn(message, category=Warning, stacklevel=2)
|
|
warnings.simplefilter("default", Warning) # Set Default
|
|
|
|
|
|
def validate_proxy_string(proxy_string):
|
|
from seleniumbase.config import proxy_list
|
|
from seleniumbase.fixtures import page_utils
|
|
|
|
if proxy_string in proxy_list.PROXY_LIST.keys():
|
|
proxy_string = proxy_list.PROXY_LIST[proxy_string]
|
|
if not proxy_string:
|
|
return None
|
|
valid = False
|
|
val_ip = re.match(
|
|
r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$", proxy_string
|
|
)
|
|
if not val_ip:
|
|
if proxy_string.startswith("http://"):
|
|
proxy_string = proxy_string.split("http://")[1]
|
|
elif proxy_string.startswith("https://"):
|
|
proxy_string = proxy_string.split("https://")[1]
|
|
elif "://" in proxy_string:
|
|
if not proxy_string.startswith("socks4://") and not (
|
|
proxy_string.startswith("socks5://")
|
|
):
|
|
proxy_string = proxy_string.split("://")[1]
|
|
chunks = proxy_string.split(":")
|
|
if len(chunks) == 2:
|
|
if re.match(r"^\d+$", chunks[1]):
|
|
if page_utils.is_valid_url("http://" + proxy_string):
|
|
valid = True
|
|
elif len(chunks) == 3:
|
|
if re.match(r"^\d+$", chunks[2]):
|
|
if page_utils.is_valid_url("http:" + ":".join(chunks[1:])):
|
|
if chunks[0] == "http":
|
|
valid = True
|
|
elif chunks[0] == "https":
|
|
valid = True
|
|
elif chunks[0] == "socks4":
|
|
valid = True
|
|
elif chunks[0] == "socks5":
|
|
valid = True
|
|
else:
|
|
proxy_string = val_ip.group()
|
|
valid = True
|
|
if not valid:
|
|
display_proxy_warning(proxy_string)
|
|
proxy_string = None
|
|
return proxy_string
|
|
|
|
|
|
def get_driver(
|
|
browser_name,
|
|
headless=False,
|
|
locale_code=None,
|
|
use_grid=False,
|
|
protocol="http",
|
|
servername="localhost",
|
|
port=4444,
|
|
proxy_string=None,
|
|
proxy_bypass_list=None,
|
|
proxy_pac_url=None,
|
|
user_agent=None,
|
|
cap_file=None,
|
|
cap_string=None,
|
|
recorder_ext=None,
|
|
disable_csp=None,
|
|
enable_ws=None,
|
|
enable_sync=None,
|
|
use_auto_ext=None,
|
|
no_sandbox=None,
|
|
disable_gpu=None,
|
|
incognito=None,
|
|
guest_mode=None,
|
|
devtools=None,
|
|
remote_debug=None,
|
|
swiftshader=None,
|
|
ad_block_on=None,
|
|
block_images=None,
|
|
chromium_arg=None,
|
|
firefox_arg=None,
|
|
firefox_pref=None,
|
|
user_data_dir=None,
|
|
extension_zip=None,
|
|
extension_dir=None,
|
|
external_pdf=None,
|
|
test_id=None,
|
|
mobile_emulator=False,
|
|
device_width=None,
|
|
device_height=None,
|
|
device_pixel_ratio=None,
|
|
):
|
|
proxy_auth = False
|
|
proxy_user = None
|
|
proxy_pass = None
|
|
if proxy_string:
|
|
username_and_password = None
|
|
if "@" in proxy_string:
|
|
# Format => username:password@hostname:port
|
|
try:
|
|
username_and_password = proxy_string.split("@")[0]
|
|
proxy_string = proxy_string.split("@")[1]
|
|
proxy_user = username_and_password.split(":")[0]
|
|
proxy_pass = username_and_password.split(":")[1]
|
|
except Exception:
|
|
raise Exception(
|
|
"The format for using a proxy server with authentication "
|
|
'is: "username:password@hostname:port". If using a proxy '
|
|
'server without auth, the format is: "hostname:port".'
|
|
)
|
|
if browser_name != constants.Browser.GOOGLE_CHROME and (
|
|
browser_name != constants.Browser.EDGE
|
|
):
|
|
raise Exception(
|
|
"Chrome or Edge is required when using a proxy server "
|
|
"that has authentication! (If using a proxy server "
|
|
"without auth, Chrome, Edge, or Firefox may be used.)"
|
|
)
|
|
proxy_string = validate_proxy_string(proxy_string)
|
|
if proxy_string and proxy_user and proxy_pass:
|
|
proxy_auth = True
|
|
elif proxy_pac_url:
|
|
username_and_password = None
|
|
if "@" in proxy_pac_url:
|
|
# Format => username:password@PAC_URL.pac
|
|
try:
|
|
username_and_password = proxy_pac_url.split("@")[0]
|
|
proxy_pac_url = proxy_pac_url.split("@")[1]
|
|
proxy_user = username_and_password.split(":")[0]
|
|
proxy_pass = username_and_password.split(":")[1]
|
|
except Exception:
|
|
raise Exception(
|
|
"The format for using a PAC URL with authentication "
|
|
'is: "username:password@PAC_URL.pac". If using a PAC '
|
|
'URL without auth, the format is: "PAC_URL.pac".'
|
|
)
|
|
if browser_name != constants.Browser.GOOGLE_CHROME and (
|
|
browser_name != constants.Browser.EDGE
|
|
):
|
|
raise Exception(
|
|
"Chrome or Edge is required when using a PAC URL "
|
|
"that has authentication! (If using a PAC URL "
|
|
"without auth, Chrome, Edge, or Firefox may be used.)"
|
|
)
|
|
if not proxy_pac_url.lower().endswith(".pac"):
|
|
raise Exception('The proxy PAC URL must end with ".pac"!')
|
|
if proxy_pac_url and proxy_user and proxy_pass:
|
|
proxy_auth = True
|
|
if browser_name == "chrome" and user_data_dir and len(user_data_dir) < 3:
|
|
raise Exception(
|
|
"Name length of Chrome's User Data Directory must be >= 3."
|
|
)
|
|
if use_grid:
|
|
return get_remote_driver(
|
|
browser_name,
|
|
headless,
|
|
locale_code,
|
|
protocol,
|
|
servername,
|
|
port,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
cap_file,
|
|
cap_string,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
test_id,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
else:
|
|
return get_local_driver(
|
|
browser_name,
|
|
headless,
|
|
locale_code,
|
|
servername,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
|
|
|
|
def get_remote_driver(
|
|
browser_name,
|
|
headless,
|
|
locale_code,
|
|
protocol,
|
|
servername,
|
|
port,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
cap_file,
|
|
cap_string,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
test_id,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
):
|
|
# Construct the address for connecting to a Selenium Grid
|
|
if servername.startswith("https://"):
|
|
protocol = "https"
|
|
servername = servername.split("https://")[1]
|
|
elif "://" in servername:
|
|
servername = servername.split("://")[1]
|
|
server_with_port = ""
|
|
if ":" not in servername:
|
|
col_port = ":" + str(port)
|
|
first_slash = servername.find("/")
|
|
if first_slash != -1:
|
|
server_with_port = (
|
|
servername[:first_slash] + col_port + servername[first_slash:]
|
|
)
|
|
else:
|
|
server_with_port = servername + col_port
|
|
else:
|
|
server_with_port = servername
|
|
address = "%s://%s" % (protocol, server_with_port)
|
|
if not address.endswith("/wd/hub"):
|
|
if address.endswith("/"):
|
|
address += "wd/hub"
|
|
else:
|
|
address += "/wd/hub"
|
|
downloads_path = download_helper.get_downloads_folder()
|
|
desired_caps = {}
|
|
extra_caps = {}
|
|
if cap_file:
|
|
from seleniumbase.core import capabilities_parser
|
|
|
|
desired_caps = capabilities_parser.get_desired_capabilities(cap_file)
|
|
if cap_string:
|
|
import json
|
|
|
|
try:
|
|
extra_caps = json.loads(str(cap_string))
|
|
except Exception as e:
|
|
p1 = "Invalid input format for --cap-string:\n %s" % e
|
|
p2 = "The --cap-string input was: %s" % cap_string
|
|
p3 = (
|
|
"Enclose cap-string in SINGLE quotes; "
|
|
"keys and values in DOUBLE quotes."
|
|
)
|
|
p4 = (
|
|
"""Here's an example of correct cap-string usage:\n """
|
|
"""--cap-string='{"browserName":"chrome","name":"test1"}'"""
|
|
)
|
|
raise Exception("%s\n%s\n%s\n%s" % (p1, p2, p3, p4))
|
|
for cap_key in extra_caps.keys():
|
|
desired_caps[cap_key] = extra_caps[cap_key]
|
|
if cap_file or cap_string:
|
|
if "name" in desired_caps.keys():
|
|
if desired_caps["name"] == "*":
|
|
desired_caps["name"] = test_id
|
|
if browser_name == constants.Browser.GOOGLE_CHROME:
|
|
chrome_options = _set_chrome_options(
|
|
browser_name,
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
servername,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
capabilities = None
|
|
if selenium4:
|
|
capabilities = webdriver.ChromeOptions().to_capabilities()
|
|
else:
|
|
capabilities = chrome_options.to_capabilities()
|
|
# Set custom desired capabilities
|
|
selenoid = False
|
|
selenoid_options = None
|
|
screen_resolution = None
|
|
browser_version = None
|
|
platform_name = None
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
if key == "selenoid:options":
|
|
selenoid = True
|
|
selenoid_options = desired_caps[key]
|
|
elif key == "screenResolution":
|
|
screen_resolution = desired_caps[key]
|
|
elif key == "version" or key == "browserVersion":
|
|
browser_version = desired_caps[key]
|
|
elif key == "platform" or key == "platformName":
|
|
platform_name = desired_caps[key]
|
|
if selenium4:
|
|
chrome_options.set_capability("cloud:options", capabilities)
|
|
if selenoid:
|
|
snops = selenoid_options
|
|
chrome_options.set_capability("selenoid:options", snops)
|
|
if screen_resolution:
|
|
scres = screen_resolution
|
|
chrome_options.set_capability("screenResolution", scres)
|
|
if browser_version:
|
|
br_vers = browser_version
|
|
chrome_options.set_capability("browserVersion", br_vers)
|
|
if platform_name:
|
|
plat_name = platform_name
|
|
chrome_options.set_capability("platformName", plat_name)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=chrome_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.FIREFOX:
|
|
firefox_options = _set_firefox_options(
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
disable_csp,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
)
|
|
capabilities = None
|
|
if selenium4:
|
|
capabilities = webdriver.FirefoxOptions().to_capabilities()
|
|
else:
|
|
capabilities = firefox_options.to_capabilities()
|
|
capabilities["marionette"] = True
|
|
if "linux" in PLATFORM:
|
|
if headless:
|
|
capabilities["moz:firefoxOptions"] = {"args": ["-headless"]}
|
|
# Set custom desired capabilities
|
|
selenoid = False
|
|
selenoid_options = None
|
|
screen_resolution = None
|
|
browser_version = None
|
|
platform_name = None
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
if key == "selenoid:options":
|
|
selenoid = True
|
|
selenoid_options = desired_caps[key]
|
|
elif key == "screenResolution":
|
|
screen_resolution = desired_caps[key]
|
|
elif key == "version" or key == "browserVersion":
|
|
browser_version = desired_caps[key]
|
|
elif key == "platform" or key == "platformName":
|
|
platform_name = desired_caps[key]
|
|
if selenium4:
|
|
firefox_options.set_capability("cloud:options", capabilities)
|
|
if selenoid:
|
|
snops = selenoid_options
|
|
firefox_options.set_capability("selenoid:options", snops)
|
|
if screen_resolution:
|
|
scres = screen_resolution
|
|
firefox_options.set_capability("screenResolution", scres)
|
|
if browser_version:
|
|
br_vers = browser_version
|
|
firefox_options.set_capability("browserVersion", br_vers)
|
|
if platform_name:
|
|
plat_name = platform_name
|
|
firefox_options.set_capability("platformName", plat_name)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=firefox_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.INTERNET_EXPLORER:
|
|
capabilities = webdriver.DesiredCapabilities.INTERNETEXPLORER
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
remote_options.set_capability("cloud:options", desired_caps)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.EDGE:
|
|
capabilities = webdriver.DesiredCapabilities.EDGE
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
remote_options.set_capability("cloud:options", desired_caps)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.SAFARI:
|
|
capabilities = webdriver.DesiredCapabilities.SAFARI
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
remote_options.set_capability("cloud:options", desired_caps)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.OPERA:
|
|
opera_options = _set_chrome_options(
|
|
browser_name,
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
servername,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
capabilities = None
|
|
if selenium4:
|
|
capabilities = webdriver.DesiredCapabilities.OPERA
|
|
else:
|
|
opera_options = webdriver.opera.options.Options()
|
|
capabilities = opera_options.to_capabilities()
|
|
# Set custom desired capabilities
|
|
selenoid = False
|
|
selenoid_options = None
|
|
screen_resolution = None
|
|
browser_version = None
|
|
platform_name = None
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
if key == "selenoid:options":
|
|
selenoid = True
|
|
selenoid_options = desired_caps[key]
|
|
elif key == "screenResolution":
|
|
screen_resolution = desired_caps[key]
|
|
elif key == "version" or key == "browserVersion":
|
|
browser_version = desired_caps[key]
|
|
elif key == "platform" or key == "platformName":
|
|
platform_name = desired_caps[key]
|
|
if selenium4:
|
|
opera_options.set_capability("cloud:options", capabilities)
|
|
if selenoid:
|
|
snops = selenoid_options
|
|
opera_options.set_capability("selenoid:options", snops)
|
|
if screen_resolution:
|
|
scres = screen_resolution
|
|
opera_options.set_capability("screenResolution", scres)
|
|
if browser_version:
|
|
br_vers = browser_version
|
|
opera_options.set_capability("browserVersion", br_vers)
|
|
if platform_name:
|
|
plat_name = platform_name
|
|
opera_options.set_capability("platformName", plat_name)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=opera_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.PHANTOM_JS:
|
|
if selenium4:
|
|
message = (
|
|
"\n"
|
|
"PhantomJS is no longer available for Selenium 4!\n"
|
|
'Try using "--headless" mode with Chrome instead!'
|
|
)
|
|
raise Exception(message)
|
|
capabilities = webdriver.DesiredCapabilities.PHANTOMJS
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
with warnings.catch_warnings():
|
|
# Ignore "PhantomJS has been deprecated" UserWarning
|
|
warnings.simplefilter("ignore", category=UserWarning)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.ANDROID:
|
|
capabilities = webdriver.DesiredCapabilities.ANDROID
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
remote_options.set_capability("cloud:options", desired_caps)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.IPHONE:
|
|
capabilities = webdriver.DesiredCapabilities.IPHONE
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
remote_options.set_capability("cloud:options", desired_caps)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.IPAD:
|
|
capabilities = webdriver.DesiredCapabilities.IPAD
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
remote_options.set_capability("cloud:options", desired_caps)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
for key in desired_caps.keys():
|
|
capabilities[key] = desired_caps[key]
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=capabilities,
|
|
keep_alive=True,
|
|
)
|
|
elif browser_name == constants.Browser.REMOTE:
|
|
if selenium4:
|
|
remote_options = ArgOptions()
|
|
# shovel caps into remote options.
|
|
for cap_name, cap_value in desired_caps.items():
|
|
remote_options.set_capability(cap_name, cap_value)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
options=remote_options,
|
|
keep_alive=True,
|
|
)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Remote(
|
|
command_executor=address,
|
|
desired_capabilities=desired_caps,
|
|
keep_alive=True,
|
|
)
|
|
|
|
|
|
def get_local_driver(
|
|
browser_name,
|
|
headless,
|
|
locale_code,
|
|
servername,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
):
|
|
"""
|
|
Spins up a new web browser and returns the driver.
|
|
Can also be used to spin up additional browsers for the same test.
|
|
"""
|
|
downloads_path = download_helper.get_downloads_folder()
|
|
|
|
if browser_name == constants.Browser.FIREFOX:
|
|
firefox_options = _set_firefox_options(
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
disable_csp,
|
|
firefox_arg,
|
|
firefox_pref,
|
|
)
|
|
if LOCAL_GECKODRIVER and os.path.exists(LOCAL_GECKODRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_GECKODRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make geckodriver"
|
|
" executable: %s" % e
|
|
)
|
|
elif not is_geckodriver_on_path():
|
|
from seleniumbase.console_scripts import sb_install
|
|
|
|
args = " ".join(sys.argv)
|
|
if not ("-n" in sys.argv or " -n=" in args or args == "-c"):
|
|
# (Not multithreaded)
|
|
sys_args = sys.argv # Save a copy of current sys args
|
|
print("\nWarning: geckodriver not found. Getting it now:")
|
|
try:
|
|
sb_install.main(override="geckodriver")
|
|
except Exception as e:
|
|
print("\nWarning: Could not install geckodriver: %s" % e)
|
|
sys.argv = sys_args # Put back the original sys args
|
|
else:
|
|
import fasteners
|
|
|
|
geckodriver_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with geckodriver_fixing_lock:
|
|
if not is_geckodriver_on_path():
|
|
sys_args = sys.argv # Save a copy of sys args
|
|
print(
|
|
"\nWarning: geckodriver not found. "
|
|
"Getting it now:"
|
|
)
|
|
sb_install.main(override="geckodriver")
|
|
sys.argv = sys_args # Put back original sys args
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
if "linux" in PLATFORM:
|
|
from selenium.webdriver.common.desired_capabilities import (
|
|
DesiredCapabilities,
|
|
)
|
|
|
|
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
|
|
firefox_capabilities["marionette"] = True
|
|
if headless:
|
|
firefox_capabilities["moz:firefoxOptions"] = {
|
|
"args": ["-headless"]
|
|
}
|
|
return webdriver.Firefox(
|
|
capabilities=firefox_capabilities, options=firefox_options
|
|
)
|
|
else:
|
|
if os.path.exists(LOCAL_GECKODRIVER):
|
|
if selenium4:
|
|
service = FirefoxService(
|
|
executable_path=LOCAL_GECKODRIVER,
|
|
log_path=os.path.devnull,
|
|
)
|
|
try:
|
|
return webdriver.Firefox(
|
|
service=service,
|
|
options=firefox_options,
|
|
)
|
|
except Exception as e:
|
|
if "Process unexpectedly closed" in e.msg:
|
|
# Firefox probably just auto-updated itself.
|
|
# Trying again right after that often works.
|
|
return webdriver.Firefox(
|
|
service=service,
|
|
options=firefox_options,
|
|
)
|
|
else:
|
|
raise Exception(e.msg) # Not an obvious fix.
|
|
else:
|
|
return webdriver.Firefox(
|
|
executable_path=LOCAL_GECKODRIVER,
|
|
service_log_path=os.path.devnull,
|
|
options=firefox_options,
|
|
)
|
|
else:
|
|
if selenium4:
|
|
service = FirefoxService(log_path=os.path.devnull)
|
|
return webdriver.Firefox(
|
|
service=service, options=firefox_options
|
|
)
|
|
else:
|
|
return webdriver.Firefox(
|
|
service_log_path=os.path.devnull,
|
|
options=firefox_options,
|
|
)
|
|
elif browser_name == constants.Browser.INTERNET_EXPLORER:
|
|
if not IS_WINDOWS:
|
|
raise Exception(
|
|
"IE Browser is for Windows-based operating systems only!"
|
|
)
|
|
from selenium.webdriver.ie.options import Options
|
|
|
|
ie_options = Options()
|
|
ie_options.ignore_protected_mode_settings = True
|
|
ie_options.ignore_zoom_level = True
|
|
ie_options.require_window_focus = False
|
|
ie_options.native_events = True
|
|
ie_options.full_page_screenshot = True
|
|
ie_options.persistent_hover = True
|
|
ie_capabilities = ie_options.to_capabilities()
|
|
if LOCAL_IEDRIVER and os.path.exists(LOCAL_IEDRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_IEDRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make IEDriver executable: %s" % e
|
|
)
|
|
elif not is_iedriver_on_path():
|
|
from seleniumbase.console_scripts import sb_install
|
|
|
|
args = " ".join(sys.argv)
|
|
if not ("-n" in sys.argv or " -n=" in args or args == "-c"):
|
|
# (Not multithreaded)
|
|
sys_args = sys.argv # Save a copy of current sys args
|
|
print("\nWarning: IEDriver not found. Getting it now:")
|
|
sb_install.main(override="iedriver")
|
|
sys.argv = sys_args # Put back the original sys args
|
|
if LOCAL_HEADLESS_IEDRIVER and os.path.exists(LOCAL_HEADLESS_IEDRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_HEADLESS_IEDRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make HeadlessIEDriver executable: %s"
|
|
% e
|
|
)
|
|
elif not is_headless_iedriver_on_path():
|
|
from seleniumbase.console_scripts import sb_install
|
|
|
|
args = " ".join(sys.argv)
|
|
if not ("-n" in sys.argv or " -n=" in args or args == "-c"):
|
|
# (Not multithreaded)
|
|
sys_args = sys.argv # Save a copy of current sys args
|
|
print("\nWarning: HeadlessIEDriver not found. Getting it now:")
|
|
sb_install.main(override="iedriver")
|
|
sys.argv = sys_args # Put back the original sys args
|
|
if not headless:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Ie(capabilities=ie_capabilities)
|
|
else:
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Ie(
|
|
executable_path=LOCAL_HEADLESS_IEDRIVER,
|
|
capabilities=ie_capabilities,
|
|
)
|
|
elif browser_name == constants.Browser.EDGE:
|
|
prefs = {
|
|
"download.default_directory": downloads_path,
|
|
"local_discovery.notifications_enabled": False,
|
|
"credentials_enable_service": False,
|
|
"download.prompt_for_download": False,
|
|
"download.directory_upgrade": True,
|
|
"safebrowsing.enabled": False,
|
|
"safebrowsing.disable_download_protection": True,
|
|
"default_content_setting_values.notifications": 0,
|
|
"default_content_settings.popups": 0,
|
|
"managed_default_content_settings.popups": 0,
|
|
"content_settings.exceptions.automatic_downloads.*.setting": 1,
|
|
"profile.password_manager_enabled": False,
|
|
"profile.default_content_setting_values.notifications": 2,
|
|
"profile.default_content_settings.popups": 0,
|
|
"profile.managed_default_content_settings.popups": 0,
|
|
"profile.default_content_setting_values.automatic_downloads": 1,
|
|
}
|
|
if LOCAL_EDGEDRIVER and os.path.exists(LOCAL_EDGEDRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_EDGEDRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make edgedriver"
|
|
" executable: %s" % e
|
|
)
|
|
elif not is_edgedriver_on_path():
|
|
from seleniumbase.console_scripts import sb_install
|
|
|
|
args = " ".join(sys.argv)
|
|
if not ("-n" in sys.argv or " -n=" in args or args == "-c"):
|
|
# (Not multithreaded)
|
|
sys_args = sys.argv # Save a copy of current sys args
|
|
print("\nWarning: msedgedriver not found. Getting it now:")
|
|
sb_install.main(override="edgedriver")
|
|
sys.argv = sys_args # Put back the original sys args
|
|
else:
|
|
import fasteners
|
|
|
|
edgedriver_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with edgedriver_fixing_lock:
|
|
if not is_edgedriver_on_path():
|
|
sys_args = sys.argv # Save a copy of sys args
|
|
print(
|
|
"\nWarning: msedgedriver not found. "
|
|
"Getting it now:"
|
|
)
|
|
sb_install.main(override="edgedriver")
|
|
sys.argv = sys_args # Put back original sys args
|
|
|
|
# For Microsoft Edge (Chromium) version 80 or higher
|
|
if selenium4:
|
|
Edge = webdriver.edge.webdriver.WebDriver
|
|
EdgeOptions = webdriver.edge.webdriver.Options
|
|
else:
|
|
from msedge.selenium_tools import Edge, EdgeOptions
|
|
|
|
if LOCAL_EDGEDRIVER and os.path.exists(LOCAL_EDGEDRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_EDGEDRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make edgedriver"
|
|
" executable: %s" % e
|
|
)
|
|
edge_options = EdgeOptions()
|
|
edge_options.use_chromium = True
|
|
if locale_code:
|
|
prefs["intl.accept_languages"] = locale_code
|
|
if block_images:
|
|
prefs["profile.managed_default_content_settings.images"] = 2
|
|
if external_pdf:
|
|
prefs["plugins.always_open_pdf_externally"] = True
|
|
edge_options.add_experimental_option("prefs", prefs)
|
|
edge_options.add_experimental_option("w3c", True)
|
|
edge_options.add_argument(
|
|
"--disable-blink-features=AutomationControlled"
|
|
)
|
|
edge_options.add_experimental_option("useAutomationExtension", False)
|
|
edge_options.add_experimental_option(
|
|
"excludeSwitches", ["enable-automation", "enable-logging"]
|
|
)
|
|
if not enable_sync:
|
|
edge_options.add_argument("--disable-sync")
|
|
if guest_mode:
|
|
edge_options.add_argument("--guest")
|
|
if headless:
|
|
edge_options.add_argument("--headless")
|
|
if mobile_emulator:
|
|
emulator_settings = {}
|
|
device_metrics = {}
|
|
if (
|
|
type(device_width) is int
|
|
and type(device_height) is int
|
|
and type(device_pixel_ratio) is int
|
|
):
|
|
device_metrics["width"] = device_width
|
|
device_metrics["height"] = device_height
|
|
device_metrics["pixelRatio"] = device_pixel_ratio
|
|
else:
|
|
device_metrics["width"] = 360
|
|
device_metrics["height"] = 640
|
|
device_metrics["pixelRatio"] = 2
|
|
emulator_settings["deviceMetrics"] = device_metrics
|
|
if user_agent:
|
|
emulator_settings["userAgent"] = user_agent
|
|
edge_options.add_experimental_option(
|
|
"mobileEmulation", emulator_settings
|
|
)
|
|
if user_data_dir:
|
|
abs_path = os.path.abspath(user_data_dir)
|
|
edge_options.add_argument("user-data-dir=%s" % abs_path)
|
|
if extension_zip:
|
|
# Can be a comma-separated list of .ZIP or .CRX files
|
|
extension_zip_list = extension_zip.split(",")
|
|
for extension_zip_item in extension_zip_list:
|
|
abs_path = os.path.abspath(extension_zip_item)
|
|
edge_options.add_extension(abs_path)
|
|
if extension_dir:
|
|
# load-extension input can be a comma-separated list
|
|
abs_path = os.path.abspath(extension_dir)
|
|
edge_options.add_argument("--load-extension=%s" % abs_path)
|
|
edge_options.add_argument("--disable-infobars")
|
|
edge_options.add_argument("--disable-notifications")
|
|
edge_options.add_argument("--disable-save-password-bubble")
|
|
edge_options.add_argument("--disable-single-click-autofill")
|
|
edge_options.add_argument(
|
|
"--disable-autofill-keyboard-accessory-view[8]"
|
|
)
|
|
edge_options.add_argument("--disable-translate")
|
|
if not enable_ws:
|
|
edge_options.add_argument("--disable-web-security")
|
|
edge_options.add_argument("--homepage=about:blank")
|
|
edge_options.add_argument("--dns-prefetch-disable")
|
|
edge_options.add_argument("--dom-automation")
|
|
edge_options.add_argument("--disable-hang-monitor")
|
|
edge_options.add_argument("--disable-prompt-on-repost")
|
|
if (settings.DISABLE_CSP_ON_CHROME or disable_csp) and not headless:
|
|
# Headless Edge doesn't support extensions, which are required
|
|
# for disabling the Content Security Policy on Edge
|
|
edge_options = _add_chrome_disable_csp_extension(edge_options)
|
|
if ad_block_on and not headless:
|
|
edge_options = _add_chrome_ad_block_extension(edge_options)
|
|
if recorder_ext and not headless:
|
|
edge_options = _add_chrome_recorder_extension(edge_options)
|
|
if proxy_string:
|
|
if proxy_auth:
|
|
edge_options = _add_chrome_proxy_extension(
|
|
edge_options, proxy_string, proxy_user, proxy_pass
|
|
)
|
|
edge_options.add_argument("--proxy-server=%s" % proxy_string)
|
|
if proxy_bypass_list:
|
|
edge_options.add_argument(
|
|
"--proxy-bypass-list=%s" % proxy_bypass_list
|
|
)
|
|
elif proxy_pac_url:
|
|
if proxy_auth:
|
|
edge_options = _add_chrome_proxy_extension(
|
|
edge_options, None, proxy_user, proxy_pass
|
|
)
|
|
edge_options.add_argument("--proxy-pac-url=%s" % proxy_pac_url)
|
|
edge_options.add_argument("--test-type")
|
|
edge_options.add_argument("--log-level=3")
|
|
edge_options.add_argument("--no-first-run")
|
|
edge_options.add_argument("--ignore-certificate-errors")
|
|
if devtools and not headless:
|
|
edge_options.add_argument("--auto-open-devtools-for-tabs")
|
|
edge_options.add_argument("--allow-file-access-from-files")
|
|
edge_options.add_argument("--allow-insecure-localhost")
|
|
edge_options.add_argument("--allow-running-insecure-content")
|
|
if user_agent:
|
|
edge_options.add_argument("--user-agent=%s" % user_agent)
|
|
edge_options.add_argument("--no-sandbox")
|
|
if remote_debug:
|
|
# To access the Remote Debugger, go to: http://localhost:9222
|
|
# while a Chromium driver is running.
|
|
# Info: https://chromedevtools.github.io/devtools-protocol/
|
|
edge_options.add_argument("--remote-debugging-port=9222")
|
|
if swiftshader:
|
|
edge_options.add_argument("--use-gl=swiftshader")
|
|
else:
|
|
edge_options.add_argument("--disable-gpu")
|
|
if "linux" in PLATFORM:
|
|
edge_options.add_argument("--disable-dev-shm-usage")
|
|
if chromium_arg:
|
|
# Can be a comma-separated list of Chromium args
|
|
chromium_arg_list = chromium_arg.split(",")
|
|
for chromium_arg_item in chromium_arg_list:
|
|
chromium_arg_item = chromium_arg_item.strip()
|
|
if not chromium_arg_item.startswith("--"):
|
|
if chromium_arg_item.startswith("-"):
|
|
chromium_arg_item = "-" + chromium_arg_item
|
|
else:
|
|
chromium_arg_item = "--" + chromium_arg_item
|
|
if len(chromium_arg_item) >= 3:
|
|
edge_options.add_argument(chromium_arg_item)
|
|
if selenium4:
|
|
try:
|
|
service = EdgeService(
|
|
executable_path=LOCAL_EDGEDRIVER, log_path=os.path.devnull
|
|
)
|
|
driver = Edge(service=service, options=edge_options)
|
|
except Exception as e:
|
|
auto_upgrade_edgedriver = False
|
|
edge_version = None
|
|
if "This version of MSEdgeDriver only supports" in e.msg:
|
|
if "Current browser version is " in e.msg:
|
|
auto_upgrade_edgedriver = True
|
|
edge_version = e.msg.split(
|
|
"Current browser version is "
|
|
)[1].split(" ")[0]
|
|
elif "only supports MSEdge version " in e.msg:
|
|
auto_upgrade_edgedriver = True
|
|
edge_version = e.msg.split(
|
|
"only supports MSEdge version "
|
|
)[1].split(" ")[0]
|
|
if not auto_upgrade_edgedriver:
|
|
raise Exception(e.msg) # Not an obvious fix. Raise.
|
|
else:
|
|
pass # Try upgrading EdgeDriver to match Edge.
|
|
args = " ".join(sys.argv)
|
|
if "-n" in sys.argv or " -n=" in args or args == "-c":
|
|
import fasteners
|
|
|
|
edgedriver_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with edgedriver_fixing_lock:
|
|
if not _was_driver_repaired():
|
|
_repair_edgedriver(edge_version)
|
|
_mark_driver_repaired()
|
|
else:
|
|
if not _was_driver_repaired():
|
|
_repair_edgedriver(edge_version)
|
|
_mark_driver_repaired()
|
|
service = EdgeService(
|
|
executable_path=LOCAL_EDGEDRIVER, log_path=os.path.devnull
|
|
)
|
|
driver = Edge(service=service, options=edge_options)
|
|
return driver
|
|
else:
|
|
capabilities = edge_options.to_capabilities()
|
|
capabilities["platform"] = ""
|
|
try:
|
|
driver = Edge(
|
|
executable_path=LOCAL_EDGEDRIVER,
|
|
service_log_path=os.path.devnull,
|
|
capabilities=capabilities,
|
|
)
|
|
except Exception as e:
|
|
auto_upgrade_edgedriver = False
|
|
edge_version = None
|
|
if "This version of MSEdgeDriver only supports" in e.msg:
|
|
if "Current browser version is " in e.msg:
|
|
auto_upgrade_edgedriver = True
|
|
edge_version = e.msg.split(
|
|
"Current browser version is "
|
|
)[1].split(" ")[0]
|
|
elif "only supports MSEdge version " in e.msg:
|
|
auto_upgrade_edgedriver = True
|
|
edge_version = e.msg.split(
|
|
"only supports MSEdge version "
|
|
)[1].split(" ")[0]
|
|
if not auto_upgrade_edgedriver:
|
|
raise Exception(e.msg) # Not an obvious fix. Raise.
|
|
else:
|
|
pass # Try upgrading EdgeDriver to match Edge.
|
|
args = " ".join(sys.argv)
|
|
if "-n" in sys.argv or " -n=" in args or args == "-c":
|
|
import fasteners
|
|
|
|
edgedriver_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with edgedriver_fixing_lock:
|
|
if not _was_driver_repaired():
|
|
_repair_edgedriver(edge_version)
|
|
_mark_driver_repaired()
|
|
else:
|
|
if not _was_driver_repaired():
|
|
_repair_edgedriver(edge_version)
|
|
_mark_driver_repaired()
|
|
driver = Edge(
|
|
executable_path=LOCAL_EDGEDRIVER,
|
|
service_log_path=os.path.devnull,
|
|
capabilities=capabilities,
|
|
)
|
|
return driver
|
|
elif browser_name == constants.Browser.SAFARI:
|
|
arg_join = " ".join(sys.argv)
|
|
if ("-n" in sys.argv) or (" -n=" in arg_join) or (arg_join == "-c"):
|
|
# Skip if multithreaded
|
|
raise Exception("Can't run Safari tests in multi-threaded mode!")
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.safari.webdriver.WebDriver(quiet=False)
|
|
elif browser_name == constants.Browser.OPERA:
|
|
try:
|
|
if LOCAL_OPERADRIVER and os.path.exists(LOCAL_OPERADRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_OPERADRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make operadriver"
|
|
" executable: %s" % e
|
|
)
|
|
opera_options = _set_chrome_options(
|
|
browser_name,
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
servername,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
opera_options.headless = False # No support for headless Opera
|
|
warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
return webdriver.Opera(options=opera_options)
|
|
except Exception:
|
|
return webdriver.Opera()
|
|
elif browser_name == constants.Browser.PHANTOM_JS:
|
|
if selenium4:
|
|
message = (
|
|
"\n"
|
|
"PhantomJS is no longer available for Selenium 4!\n"
|
|
'Try using "--headless" mode with Chrome instead!'
|
|
)
|
|
raise Exception(message)
|
|
with warnings.catch_warnings():
|
|
# Ignore "PhantomJS has been deprecated" UserWarning
|
|
warnings.simplefilter("ignore", category=UserWarning)
|
|
return webdriver.PhantomJS()
|
|
elif browser_name == constants.Browser.GOOGLE_CHROME:
|
|
try:
|
|
chrome_options = _set_chrome_options(
|
|
browser_name,
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
servername,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
if LOCAL_CHROMEDRIVER and os.path.exists(LOCAL_CHROMEDRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_CHROMEDRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make chromedriver"
|
|
" executable: %s" % e
|
|
)
|
|
elif not is_chromedriver_on_path():
|
|
from seleniumbase.console_scripts import sb_install
|
|
|
|
args = " ".join(sys.argv)
|
|
if not ("-n" in sys.argv or " -n=" in args or args == "-c"):
|
|
# (Not multithreaded)
|
|
sys_args = sys.argv # Save a copy of current sys args
|
|
print("\nWarning: chromedriver not found. Getting it now:")
|
|
sb_install.main(override="chromedriver latest")
|
|
sys.argv = sys_args # Put back the original sys args
|
|
else:
|
|
import fasteners
|
|
|
|
chromedriver_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with chromedriver_fixing_lock:
|
|
if not is_chromedriver_on_path():
|
|
sys_args = sys.argv # Save a copy of sys args
|
|
print(
|
|
"\nWarning: chromedriver not found. "
|
|
"Getting it now:"
|
|
)
|
|
sb_install.main(override="chromedriver latest")
|
|
sys.argv = sys_args # Put back original sys args
|
|
if not headless or "linux" not in PLATFORM:
|
|
try:
|
|
if os.path.exists(LOCAL_CHROMEDRIVER):
|
|
if selenium4:
|
|
service = ChromeService(
|
|
executable_path=LOCAL_CHROMEDRIVER,
|
|
log_path=os.path.devnull,
|
|
)
|
|
driver = webdriver.Chrome(
|
|
service=service,
|
|
options=chrome_options,
|
|
)
|
|
else:
|
|
driver = webdriver.Chrome(
|
|
executable_path=LOCAL_CHROMEDRIVER,
|
|
service_log_path=os.path.devnull,
|
|
options=chrome_options,
|
|
)
|
|
else:
|
|
if selenium4:
|
|
service = ChromeService(log_path=os.path.devnull)
|
|
driver = webdriver.Chrome(
|
|
service=service, options=chrome_options
|
|
)
|
|
else:
|
|
driver = webdriver.Chrome(
|
|
options=chrome_options,
|
|
service_log_path=os.path.devnull,
|
|
)
|
|
except Exception as e:
|
|
auto_upgrade_chromedriver = False
|
|
if "This version of ChromeDriver only supports" in e.msg:
|
|
auto_upgrade_chromedriver = True
|
|
elif "Chrome version must be between" in e.msg:
|
|
auto_upgrade_chromedriver = True
|
|
if not auto_upgrade_chromedriver:
|
|
raise Exception(e.msg) # Not an obvious fix. Raise.
|
|
else:
|
|
pass # Try upgrading ChromeDriver to match Chrome.
|
|
mcv = None # Major Chrome Version
|
|
if "Current browser version is " in e.msg:
|
|
line = e.msg.split("Current browser version is ")[1]
|
|
browser_version = line.split(" ")[0]
|
|
major_chrome_version = browser_version.split(".")[0]
|
|
if (
|
|
major_chrome_version.isnumeric()
|
|
and int(major_chrome_version) >= 86
|
|
):
|
|
mcv = major_chrome_version
|
|
headless = True
|
|
headless_options = _set_chrome_options(
|
|
browser_name,
|
|
downloads_path,
|
|
headless,
|
|
locale_code,
|
|
proxy_string,
|
|
proxy_auth,
|
|
proxy_user,
|
|
proxy_pass,
|
|
proxy_bypass_list,
|
|
proxy_pac_url,
|
|
user_agent,
|
|
recorder_ext,
|
|
disable_csp,
|
|
enable_ws,
|
|
enable_sync,
|
|
use_auto_ext,
|
|
no_sandbox,
|
|
disable_gpu,
|
|
incognito,
|
|
guest_mode,
|
|
devtools,
|
|
remote_debug,
|
|
swiftshader,
|
|
ad_block_on,
|
|
block_images,
|
|
chromium_arg,
|
|
user_data_dir,
|
|
extension_zip,
|
|
extension_dir,
|
|
external_pdf,
|
|
servername,
|
|
mobile_emulator,
|
|
device_width,
|
|
device_height,
|
|
device_pixel_ratio,
|
|
)
|
|
args = " ".join(sys.argv)
|
|
if "-n" in sys.argv or " -n=" in args or args == "-c":
|
|
import fasteners
|
|
|
|
chromedriver_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with chromedriver_fixing_lock:
|
|
if not _was_driver_repaired():
|
|
_repair_chromedriver(
|
|
chrome_options, headless_options, mcv
|
|
)
|
|
_mark_driver_repaired()
|
|
else:
|
|
if not _was_driver_repaired():
|
|
_repair_chromedriver(
|
|
chrome_options, headless_options, mcv
|
|
)
|
|
_mark_driver_repaired()
|
|
if os.path.exists(LOCAL_CHROMEDRIVER):
|
|
if selenium4:
|
|
service = ChromeService(
|
|
executable_path=LOCAL_CHROMEDRIVER
|
|
)
|
|
driver = webdriver.Chrome(
|
|
service=service,
|
|
options=chrome_options,
|
|
)
|
|
else:
|
|
driver = webdriver.Chrome(
|
|
executable_path=LOCAL_CHROMEDRIVER,
|
|
options=chrome_options,
|
|
)
|
|
else:
|
|
driver = webdriver.Chrome(options=chrome_options)
|
|
return driver
|
|
else: # Running headless on Linux
|
|
try:
|
|
return webdriver.Chrome(options=chrome_options)
|
|
except Exception as e:
|
|
auto_upgrade_chromedriver = False
|
|
if "This version of ChromeDriver only supports" in e.msg:
|
|
auto_upgrade_chromedriver = True
|
|
elif "Chrome version must be between" in e.msg:
|
|
auto_upgrade_chromedriver = True
|
|
mcv = None # Major Chrome Version
|
|
if "Current browser version is " in e.msg:
|
|
line = e.msg.split("Current browser version is ")[1]
|
|
browser_version = line.split(" ")[0]
|
|
major_chrome_version = browser_version.split(".")[0]
|
|
if (
|
|
major_chrome_version.isnumeric()
|
|
and int(major_chrome_version) >= 86
|
|
):
|
|
mcv = major_chrome_version
|
|
if auto_upgrade_chromedriver:
|
|
args = " ".join(sys.argv)
|
|
if "-n" in sys.argv or " -n=" in args or args == "-c":
|
|
import fasteners
|
|
|
|
chromedr_fixing_lock = fasteners.InterProcessLock(
|
|
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
)
|
|
with chromedr_fixing_lock:
|
|
if not _was_driver_repaired():
|
|
try:
|
|
_repair_chromedriver(
|
|
chrome_options, chrome_options, mcv
|
|
)
|
|
_mark_driver_repaired()
|
|
except Exception:
|
|
pass
|
|
else:
|
|
if not _was_driver_repaired():
|
|
try:
|
|
_repair_chromedriver(
|
|
chrome_options, chrome_options, mcv
|
|
)
|
|
except Exception:
|
|
pass
|
|
_mark_driver_repaired()
|
|
try:
|
|
return webdriver.Chrome(options=chrome_options)
|
|
except Exception:
|
|
pass
|
|
# Use the virtual display on Linux during headless errors
|
|
logging.debug(
|
|
"\nWarning: Chrome failed to launch in"
|
|
" headless mode. Attempting to use the"
|
|
" SeleniumBase virtual display on Linux..."
|
|
)
|
|
chrome_options.headless = False
|
|
return webdriver.Chrome(options=chrome_options)
|
|
except Exception as e:
|
|
try:
|
|
# Try again if Chrome didn't launch
|
|
return webdriver.Chrome(options=chrome_options)
|
|
except Exception:
|
|
pass
|
|
if headless:
|
|
raise Exception(e)
|
|
if LOCAL_CHROMEDRIVER and os.path.exists(LOCAL_CHROMEDRIVER):
|
|
try:
|
|
make_driver_executable_if_not(LOCAL_CHROMEDRIVER)
|
|
except Exception as e:
|
|
logging.debug(
|
|
"\nWarning: Could not make chromedriver"
|
|
" executable: %s" % e
|
|
)
|
|
return webdriver.Chrome()
|
|
else:
|
|
raise Exception(
|
|
"%s is not a valid browser option for this system!" % browser_name
|
|
)
|