diff --git a/README.md b/README.md index b0133bd..9e66ffc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ -# selenium-tools +# Stool + +stool is an wrapper over selenium to perform various task. -## TODO +## Features +- [X] Manage multiple webdrivers + +## TODO - [ ] Manage multiple webdrivers diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..80f1c62 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +certifi==2021.5.30 +chardet==4.0.0 +colorama==0.4.4 +configparser==5.0.2 +crayons==0.4.0 +idna==2.10 +requests==2.25.1 +selenium==3.141.0 +urllib3==1.26.6 +webdriver-manager==3.4.2 diff --git a/stool/driver.py b/stool/driver.py new file mode 100644 index 0000000..6c44a24 --- /dev/null +++ b/stool/driver.py @@ -0,0 +1,88 @@ +from functools import partial + +from selenium import webdriver +from webdriver_manager.chrome import ChromeDriverManager +from webdriver_manager.firefox import GeckoDriverManager +from webdriver_manager.utils import ChromeType + +from utils import (SToolException, current_url, get_element, get_session, + page_source, visit) + + +class SeleniumDriver: + + def __init__(self, browser=None, headless=False): + self.browser_list = ['chrome', 'chromium', 'firefox'] + self.driver = None + self.browser = browser + self.headless = headless + + self._load_driver() + self._load_methods() + + def close(self): + """will stop driver after program execution + """ + if self.driver: + self.driver.quit() + + def __exit__(self, type, value, traceback): + """release the resources occupied with the current session + """ + self.close() + + def __enter__(self): + return self._load_driver() + + def _load_driver(self): + """Create Selenium webdriver object + """ + self.close() + browser = self.browser.lower() + if browser not in self.browser_list: + raise SToolException( + f"provided browser {browser} doesn't exists. available brower list:{self.browser_list}") + + # add chrome and firefox different options + options = getattr(webdriver, browser if browser != + 'chromium' else 'chrome').options.Options() + if self.headless: + options.add_argument('--headless') + + if browser in ['chrome', 'chromium']: + browser_type = ChromeType.CHROMIUM if browser == 'chromium' else ChromeType.GOOGLE + self.driver = webdriver.Chrome(ChromeDriverManager( + chrome_type=browser_type).install(), + options=options) + + if browser == "firefox": + self.driver = webdriver.Firefox( + executable_path=GeckoDriverManager().install(), + options=options) + + # Maximize window to give normal browser feel + self.driver.maximize_window() + + # Load all modules and methods + self._load_methods() + + return self + + def _load_methods(self): + self.session = partial(get_session, self.driver) + self.visit = partial(visit, self.driver) + self.text = partial(page_source, self.driver) + self.url = partial(current_url, self.driver) + self.element = partial(get_element, self.driver) + + +if __name__ == '__main__': + + # Create A Driver Object + with SeleniumDriver('firefox', headless=False) as obj: + # visit https:example.com + obj.visit(r'https://quotes.toscrape.com/') + + # for all quotes obj.element('class_name', 'quote',1) + result = obj.element('class_name', 'quote') + print(result) diff --git a/stool/parser.py b/stool/parser.py new file mode 100644 index 0000000..13d402c --- /dev/null +++ b/stool/parser.py @@ -0,0 +1,6 @@ +class Parser(object): + """Parse data from webdriver + """ + + def __init__(self, driver): + self.driver = driver diff --git a/stool/utils/__init__.py b/stool/utils/__init__.py new file mode 100644 index 0000000..c6f3b41 --- /dev/null +++ b/stool/utils/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +from utils.driver_exceptions import SToolException +from utils.driver_utils import (current_url, get_element, get_session, + page_source, visit) + +__all__ = ["SToolException", "current_url", "get_element", "get_session", + "page_source", "visit"] diff --git a/stool/utils/driver_exceptions.py b/stool/utils/driver_exceptions.py new file mode 100644 index 0000000..e728c95 --- /dev/null +++ b/stool/utils/driver_exceptions.py @@ -0,0 +1,12 @@ + + +class SToolException(Exception): + """ + Base Class for selenium tools Exceptions + """ + + def __init__(self, message): + self.message = message + + def __str__(self): + return str(self.message) diff --git a/stool/utils/driver_utils.py b/stool/utils/driver_utils.py new file mode 100644 index 0000000..a672102 --- /dev/null +++ b/stool/utils/driver_utils.py @@ -0,0 +1,73 @@ +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.common.by import By + +from utils.driver_exceptions import SToolException + + +def get_session(driver): + """Return Selenium Driver session id + """ + return driver.session_id + + +def visit(driver, url): + """visit given url + """ + driver.get(url) + + +def page_source(driver): + """Return html page source + """ + return driver.page_source + + +def current_url(driver): + """Return current url + """ + return driver.current_url + + +def get_locator(locator_type, locator_text): + """Return element locator + + Args: + locator_type : provide any attribute type + id,class_name,tag_name + xpath, css_selector + + locator_text : attribute value + """ + return getattr(By, locator_type), locator_text + + +def get_element(driver, locator_type, locator_text, many=None): + """Get element using locator type and locator text + + Args: + locator_type : provide any attribute type + id,class_name,tag_name + xpath, css_selector + + locator_text : attribute value + + many : optional default None, + 1: select multiple element + 0: select single element + + Returns: + Return an element object if found otherwise + return None + """ + + locator_type = locator_type.upper() + if hasattr(By, locator_type): + try: + locator = get_locator(locator_type, locator_text) + is_multiple = 's' if many else '' + func = getattr(driver, f'find_element{is_multiple}') + return func(*locator) + except NoSuchElementException as _: + return None + else: + raise SToolException("INVALID_SELECTOR")