コード例 #1
0
def setup_login(base_url, selenium: Remote):
    selenium.get(base_url)
    selenium.delete_all_cookies()
    file = join(dirname(dirname(__file__)), 'cookies.pkl')
    cookies = load(open(file, "rb"))
    for cookie in cookies:
        selenium.add_cookie(cookie)
コード例 #2
0
class Browser:
    """Class for housekeeping of remote Selenium interactions.

    Initializes the session with the remote Selenium Grid node
    and properly closes it on instance destruction. Also allows
    to wait for specific HTML element and get its attribute.

    Attributes
    ----------
    _logger : :class:`~logging.Logger`
        Channel to be used for log output specific to the module.

    _browser : :obj:`WebDriver <selenium:selenium.webdriver.remote.webdriver>`
        Handle to operate remote Selenium Grid node (web browser).

    """
    def __init__(
        self,
        se_endpoint="http://localhost:4444/wd/hub",
        se_capabilities=DesiredCapabilities.CHROME,
        page_load_timeout=10,
    ):
        """Initialize connection to remote Selenium node with right capabilities.

        Parameters
        ----------
        se_endpoint : :obj:`str`, optional
            URL for Selenium Grid hub.
            (default 'http://localhost:4444/wd/hub')

        se_capabilities : :obj:`~selenium:selenium.webdriver.common.desired_capabilities.DesiredCapabilities`, optional  # noqa
            Capabilities of Selenium node indicating necessary browser type
            and configuration.
            (default ``DesiredCapabilities.CHROME``)

        page_load_timeout : :obj:`int`, optional
            Seconds to wait for page to load.
            (default 10)

        """
        self._logger = getLogger(__name__)
        self._browser = None

        # prepare to request headless WebDriver from Selenium
        if se_capabilities["browserName"] == "chrome":
            opts = ChromeOptions()
        elif se_capabilities["browserName"] == "firefox":
            opts = FirefoxOptions()

        opts.headless = True

        # connect to available Selenium node with correct capabilities
        try:
            self._browser = Remote(
                options=opts,
                command_executor=se_endpoint,
                desired_capabilities=se_capabilities,
            )
        except Exception:
            self._logger.exception(
                "Exception: failed to connect to remote Selenium instance")
        else:
            # set page load timeout once for the whole session duration
            self._browser.set_page_load_timeout(page_load_timeout)

            self._logger.debug(
                "Created instance from %s(%s)",
                self.__class__.__name__,
                ", ".join("{}='{}'".format(key, value)
                          for key, value in locals().items()),
            )

    def __enter__(self):
        """Return class instance."""
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        """Gracefully close connection to Selenium on instance destruction."""
        if isinstance(self._browser, Remote):
            self._logger.debug("Delete all cookies and close Selenium session")

            self._browser.delete_all_cookies()
            self._browser.quit()

    @property
    def webdriver(self):
        """Return handler for remote Selenium WebDriver."""
        return self._browser

    def check_title(self, expected_title=None):
        """Check current browser title.

        Returns :obj:`True`, if `expected_title` string is in the browser's page title.
        If `expected_title` is not defined, just logs the title and returns :obj:`True`.

        Parameters
        ----------
        expected_title : :obj:`str`, optional
            String or sub-strng expected to be in the page title.
            (default :obj:`None`)

        Returns
        -------
        :obj:`bool`
            Check result (:obj:`True`, if match is found)

        """
        self._logger.info("page title: '%s'", self._browser.title)

        if expected_title is None:
            return True

        elif expected_title in self._browser.title:
            self._logger.info("page title match: '%s'", expected_title)
            return True

        else:
            self._logger.warning("page title DOES NOT match: '%s'",
                                 expected_title)
            return False

    def check_url(self, expected_url=None):
        """Check current browser URL.

        Returns :obj:`True`, if `expected_url` string is in the browser's current URL.
        If `expected_url` is not defined, just logs the URL and returns :obj:`True`.

        Parameters
        ----------
        expected_url : :obj:`str`, optional
            String or sub-strng expected to be in the current browser's URL.
            (default :obj:`None`)

        Returns
        -------
        :obj:`bool`
            Check result (:obj:`True`, if match is found)

        """
        self._logger.info("page url: '%s'", self._browser.current_url)

        if expected_url is None:
            return True

        elif expected_url in self._browser.current_url:
            self._logger.info("page url match: '%s'", expected_url)
            return True

        else:
            self._logger.warning("page url DOES NOT match: '%s'", expected_url)
            return False

    def wait_for_element_get_attribute(
        self,
        element_xpath="/html/head/title",
        element_attribute="innerHTML",
        wait_timeout=10,
    ):
        """Find element in browser DOM and get specified attribute/property from it.

        Waits for ``element_xpath`` to appear in DOM (i.e. after page load
        or some JavaScript action) in ``wait_timeout`` seconds, then returns
        ``element_attribute`` if element exists.

        Note
        ----
        With default parameters waits 10 sec for ``/html/head/title`` element to be
        present before capturing its property ``innerHTML``.

        In effect, waiting 10 sec for page to load and getting current title

        Parameters
        ----------
        element_xpath : :obj:`str`, optional
            XPATH of element to be located
            (default ``/html/head/title``)

        element_attribute : :obj:`str`, optional
            Name of attribute or property of located element to be returned
            (default ``innerHTML``)

        wait_timeout : :obj:`int`, optional
            Seconds to wait for element to appear.
            (default 10)

        Returns
        -------
        :obj:`bool`
            success flag (:obj:`True`, if element found)
        :obj:`str`
            content of attribute, or :obj:`None` if no attribute with that name

        """
        success = False
        attribute = None

        self._logger.debug("waiting for element @XPATH '%s'", element_xpath)

        # wait for element to be located at ``element_xpath``, then get
        # specified attribute ``element_attribute``
        try:
            element = WebDriverWait(self._browser, wait_timeout).until(
                expected_conditions.presence_of_element_located(
                    (By.XPATH, element_xpath)))

        except (TimeoutException, WebDriverException):
            self._logger.exception(
                "Exception: waiting for element @XPATH '%s'", element_xpath)

        else:
            self._logger.debug(
                "found element @XPATH '%s', getting attribute '%s'",
                element_xpath,
                element_attribute,
            )

            success = True
            attribute = element.get_attribute(element_attribute)

        return success, attribute

    def wait_for_page_to_load(self):
        """Wait for page to load.

        Waiting the default timeout of :meth:`wait_for_element_get_attribute` for page
        to make the HTML title element available.

        Returns
        -------
        :obj:`bool`
            success flag (:obj:`True`, if page is loaded;
            :obj:`False`, if timeout occured)

        """
        (page_title_success,
         page_title) = self.wait_for_element_get_attribute()

        return page_title_success