Path: blob/trunk/py/selenium/webdriver/firefox/webdriver.py
4020 views
# Licensed to the Software Freedom Conservancy (SFC) under one1# or more contributor license agreements. See the NOTICE file2# distributed with this work for additional information3# regarding copyright ownership. The SFC licenses this file4# to you under the Apache License, Version 2.0 (the5# "License"); you may not use this file except in compliance6# with the License. You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing,11# software distributed under the License is distributed on an12# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13# KIND, either express or implied. See the License for the14# specific language governing permissions and limitations15# under the License.1617import base6418import os19import warnings20import zipfile21from contextlib import contextmanager22from io import BytesIO2324from selenium.webdriver.common.driver_finder import DriverFinder25from selenium.webdriver.common.webdriver import LocalWebDriver26from selenium.webdriver.firefox.options import Options27from selenium.webdriver.firefox.remote_connection import FirefoxRemoteConnection28from selenium.webdriver.firefox.service import Service293031class WebDriver(LocalWebDriver):32"""Controls the GeckoDriver and allows you to drive the browser."""3334CONTEXT_CHROME = "chrome"35CONTEXT_CONTENT = "content"3637def __init__(38self,39options: Options | None = None,40service: Service | None = None,41keep_alive: bool = True,42) -> None:43"""Create a new instance of the Firefox driver, start the service, and create new instance.4445Args:46options: Instance of Options.47service: Service object for handling the browser driver if you need to pass extra details.48keep_alive: Whether to configure FirefoxRemoteConnection to use HTTP keep-alive.49"""50self.service = service if service else Service()51self.options = options if options else Options()5253finder = DriverFinder(self.service, self.options)54if finder.get_browser_path():55self.options.binary_location = finder.get_browser_path()56self.options.browser_version = None5758self.service.path = self.service.env_path() or finder.get_driver_path()59self.service.start()6061executor = FirefoxRemoteConnection(62remote_server_addr=self.service.service_url,63keep_alive=keep_alive,64ignore_proxy=self.options._ignore_local_proxy,65)6667try:68super().__init__(command_executor=executor, options=self.options)69except Exception:70self.quit()71raise7273def set_context(self, context) -> None:74"""Sets the context that Selenium commands are running in.7576Args:77context: Context to set, should be one of CONTEXT_CHROME or CONTEXT_CONTENT.78"""79self.execute("SET_CONTEXT", {"context": context})8081@contextmanager82def context(self, context):83"""Set the context that Selenium commands are running in using a `with` statement.8485The state of the context on the server is saved before entering the block,86and restored upon exiting it.8788Args:89context: Context, may be one of the class properties90`CONTEXT_CHROME` or `CONTEXT_CONTENT`.9192Example:93with selenium.context(selenium.CONTEXT_CHROME):94# chrome scope95... do stuff ...96"""97initial_context = self.execute("GET_CONTEXT").pop("value")98self.set_context(context)99try:100yield101finally:102self.set_context(initial_context)103104def install_addon(self, path, temporary=False) -> str:105"""Installs Firefox addon.106107Returns identifier of installed addon. This identifier can later108be used to uninstall addon.109110Args:111path: Absolute path to the addon that will be installed.112temporary: Allows you to load browser extensions temporarily during a session.113114Returns:115Identifier of installed addon.116117Example:118driver.install_addon("/path/to/firebug.xpi")119"""120if os.path.isdir(path):121fp = BytesIO()122# filter all trailing slash found in path123path = os.path.normpath(path)124# account for trailing slash that will be added by os.walk()125path_root = len(path) + 1126with zipfile.ZipFile(fp, "w", zipfile.ZIP_DEFLATED, strict_timestamps=False) as zipped:127for base, _, files in os.walk(path):128for fyle in files:129filename = os.path.join(base, fyle)130zipped.write(filename, filename[path_root:])131addon = base64.b64encode(fp.getvalue()).decode("UTF-8")132else:133with open(path, "rb") as file:134addon = base64.b64encode(file.read()).decode("UTF-8")135136payload = {"addon": addon, "temporary": temporary}137return self.execute("INSTALL_ADDON", payload)["value"]138139def uninstall_addon(self, identifier) -> None:140"""Uninstalls Firefox addon using its identifier.141142Args:143identifier: The addon identifier to uninstall.144145Example:146driver.uninstall_addon("[email protected]")147"""148self.execute("UNINSTALL_ADDON", {"id": identifier})149150def get_full_page_screenshot_as_file(self, filename) -> bool:151"""Save a full document screenshot of the current window to a PNG image file.152153Args:154filename: The full path you wish to save your screenshot to. This155should end with a `.png` extension.156157Returns:158False if there is any IOError, else returns True. Use full paths in your filename.159160Example:161driver.get_full_page_screenshot_as_file("/Screenshots/foo.png")162"""163if not filename.lower().endswith(".png"):164warnings.warn(165"name used for saved screenshot does not match file type. It should end with a `.png` extension",166UserWarning,167)168png = self.get_full_page_screenshot_as_png()169try:170with open(filename, "wb") as f:171f.write(png)172except OSError:173return False174finally:175del png176return True177178def save_full_page_screenshot(self, filename) -> bool:179"""Save a full document screenshot of the current window to a PNG image file.180181Args:182filename: The full path you wish to save your screenshot to. This183should end with a `.png` extension.184185Returns:186False if there is any IOError, else returns True. Use full paths in your filename.187188Example:189driver.save_full_page_screenshot("/Screenshots/foo.png")190"""191return self.get_full_page_screenshot_as_file(filename)192193def get_full_page_screenshot_as_png(self) -> bytes:194"""Get the full document screenshot of the current window as binary data.195196Returns:197Binary data of the screenshot.198199Example:200driver.get_full_page_screenshot_as_png()201"""202return base64.b64decode(self.get_full_page_screenshot_as_base64().encode("ascii"))203204def get_full_page_screenshot_as_base64(self) -> str:205"""Get the full document screenshot of the current window as a base64-encoded string.206207Returns:208Base64 encoded string of the screenshot.209210Example:211driver.get_full_page_screenshot_as_base64()212"""213return self.execute("FULL_PAGE_SCREENSHOT")["value"]214215216