# coding=utf-8 import time import platform import warnings from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.select import Select from selenium.webdriver.common.action_chains import ActionChains from seldom.logging import log from seldom.running.config import Seldom from seldom.logging.exceptions import NotFindElementError LOCATOR_LIST = { 'css': By.CSS_SELECTOR, 'id_': By.ID, 'name': By.NAME, 'xpath': By.XPATH, 'link_text': By.LINK_TEXT, 'partial_link_text': By.PARTIAL_LINK_TEXT, 'tag': By.TAG_NAME, 'class_name': By.CLASS_NAME, } def find_element(elem): """ Find if the element exists. """ for i in range(Seldom.timeout): elems = Seldom.driver.find_elements(by=elem[0], value=elem[1]) if len(elems) == 1: log.info("✅ Find element: {by}={value} ".format( by=elem[0], value=elem[1])) break elif len(elems) > 1: log.info("❓ Find {n} elements through: {by}={value}".format( n=len(elems), by=elem[0], value=elem[1])) break else: time.sleep(1) else: error_msg = "❌ Find 0 elements through: {by}={value}".format( by=elem[0], value=elem[1]) log.error(error_msg) raise NotFindElementError(error_msg) def get_element(**kwargs): """ Judge element positioning way, and returns the element. """ if not kwargs: raise ValueError("Please specify a locator") if len(kwargs) > 1: raise ValueError("Please specify only one locator") by, value = next(iter(kwargs.items())) try: LOCATOR_LIST[by] except KeyError: raise ValueError("Element positioning of type '{}' is not supported. ".format(by)) if by == "id_": find_element((By.ID, value)) elem = Seldom.driver.find_elements_by_id(value) elif by == "name": find_element((By.NAME, value)) elem = Seldom.driver.find_elements_by_name(value) elif by == "class_name": find_element((By.CLASS_NAME, value)) elem = Seldom.driver.find_elements_by_class_name(value) elif by == "tag": find_element((By.TAG_NAME, value)) elem = Seldom.driver.find_elements_by_tag_name(value) elif by == "link_text": find_element((By.LINK_TEXT, value)) elem = Seldom.driver.find_elements_by_link_text(value) elif by == "partial_link_text": find_element((By.PARTIAL_LINK_TEXT, value)) elem = Seldom.driver.find_elements_by_partial_link_text(value) elif by == "xpath": find_element((By.XPATH, value)) elem = Seldom.driver.find_elements_by_xpath(value) elif by == "css": find_element((By.CSS_SELECTOR, value)) elem = Seldom.driver.find_elements_by_css_selector(value) else: raise NameError( "Please enter the correct targeting elements,'id_/name/class_name/tag/link_text/xpath/css'.") return elem def show_element(elem): """ Show the elements of the operation :param elem: """ style_red = 'arguments[0].style.border="2px solid #FF0000"' style_blue = 'arguments[0].style.border="2px solid #00FF00"' style_null = 'arguments[0].style.border=""' if Seldom.debug is True: for _ in range(3): Seldom.driver.execute_script(style_red, elem) time.sleep(0.2) Seldom.driver.execute_script(style_blue, elem) time.sleep(0.2) Seldom.driver.execute_script(style_blue, elem) time.sleep(2) Seldom.driver.execute_script(style_null, elem) else: for _ in range(2): Seldom.driver.execute_script(style_red, elem) time.sleep(0.1) Seldom.driver.execute_script(style_blue, elem) time.sleep(0.1) Seldom.driver.execute_script(style_blue, elem) time.sleep(0.3) Seldom.driver.execute_script(style_null, elem) class WebDriver(object): """ Seldom framework for the main class, the original selenium provided by the method of the two packaging, making it easier to use. """ original_window = None class Keys: """ Achieve keyboard shortcuts Usage: self.Keys(id_="kw").enter() """ def __init__(self, index=0, **kwargs): self.elem = get_element(**kwargs)[index] show_element(self.elem) def input(self, text=""): self.elem.send_keys(text) def enter(self): self.elem.send_keys(Keys.ENTER) def select_all(self): if platform.system().lower() == "darwin": self.elem.send_keys(Keys.COMMAND, "a") else: self.elem.send_keys(Keys.CONTROL, "a") def cut(self): if platform.system().lower() == "darwin": self.elem.send_keys(Keys.COMMAND, "x") else: self.elem.send_keys(Keys.CONTROL, "x") def copy(self): if platform.system().lower() == "darwin": self.elem.send_keys(Keys.COMMAND, "c") else: self.elem.send_keys(Keys.CONTROL, "c") def paste(self): if platform.system().lower() == "darwin": self.elem.send_keys(Keys.COMMAND, "v") else: self.elem.send_keys(Keys.CONTROL, "v") def backspace(self): self.elem.send_keys(Keys.BACKSPACE) def delete(self): self.elem.send_keys(Keys.DELETE) def tab(self): self.elem.send_keys(Keys.TAB) def space(self): self.elem.send_keys(Keys.SPACE) def get(self, url): """ get url. Usage: self.get("https://www.baidu.com") """ Seldom.driver.get(url) def open(self, url): """ open url. Usage: self.open("https://www.baidu.com") """ self.get(url) def max_window(self): """ Set browser window maximized. Usage: self.max_window() """ Seldom.driver.maximize_window() def set_window(self, wide, high): """ Set browser window wide and high. Usage: self.set_window(wide,high) """ Seldom.driver.set_window_size(wide, high) def type(self, text, clear=False, index=0, **kwargs): """ Operation input box. Usage: self.type(css="#el", text="selenium") """ if clear is True: self.clear(index, **kwargs) elem = get_element(**kwargs)[index] show_element(elem) log.info("🖋 input '{text}'.".format(text=text)) elem.send_keys(text) def type_enter(self, text, clear=False, index=0, **kwargs): """ Enter text and enter directly. Usage: self.type_enter(css="#el", text="selenium") """ if clear is True: self.clear(index, **kwargs) elem = get_element(**kwargs)[index] show_element(elem) log.info("🖋 ➕ 🖱 input '{text}' and enter.".format(text=text)) elem.send_keys(text) elem.send_keys(Keys.ENTER) def clear(self, index=0, **kwargs): """ Clear the contents of the input box. Usage: self.clear(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) elem.clear() def click(self, index=0, **kwargs): """ It can click any text / image can be clicked Connection, check box, radio buttons, and even drop-down box etc.. Usage: self.click(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) log.info("🖱 click.") elem.click() def slow_click(self, index=0, **kwargs): """ Moving the mouse to the middle of an element. and click element. Usage: self.slow_click(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) ActionChains(Seldom.driver).move_to_element(elem).click(elem).perform() def right_click(self, index=0, **kwargs): """ Right click element. Usage: self.right_click(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) ActionChains(Seldom.driver).context_click(elem).perform() def move_to_element(self, index=0, **kwargs): """ Mouse over the element. Usage: self.move_to_element(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) ActionChains(Seldom.driver).move_to_element(elem).perform() def click_and_hold(self, index=0, **kwargs): """ Mouse over the element. Usage: self.move_to_element(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) ActionChains(Seldom.driver).click_and_hold(elem).perform() def double_click(self, index=0, **kwargs): """ Double click element. Usage: self.double_click(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) ActionChains(Seldom.driver).double_click(elem).perform() def click_text(self, text): """ Click the element by the link text Usage: self.click_text("新闻") """ find_element((By.LINK_TEXT, text)) Seldom.driver.find_element_by_link_text(text).click() def close(self): """ Simulates the user clicking the "close" button in the titlebar of a popup window or tab. Usage: self.close() """ Seldom.driver.close() def quit(self): """ Quit the driver and close all the windows. Usage: self.quit() """ Seldom.driver.quit() def submit(self, index=0, **kwargs): """ Submit the specified form. Usage: driver.submit(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) elem.submit() def refresh(self): """ Refresh the current page. Usage: self.refresh() """ Seldom.driver.refresh() def execute_script(self, script, *args): """ Execute JavaScript scripts. Usage: self.execute_script("window.scrollTo(200,1000);") """ return Seldom.driver.execute_script(script, *args) def window_scroll(self, width=None, height=None): """ Setting width and height of window scroll bar. Usage: self.window_scroll(width=300, height=500) """ if width is None: width = "0" if height is None: height = "0" js = "window.scrollTo({w},{h});".format(w=str(width), h=str(height)) self.execute_script(js) def element_scroll(self, css, width=None, height=None): """ Setting width and height of element scroll bar. Usage: self.element_scroll(css=".class", width=300, height=500) """ if width is None: width = "0" if height is None: height = "0" scroll_life = 'document.querySelector("{css}").scrollLeft = {w};'.format(css=css, w=width) scroll_top = 'document.querySelector("{css}").scrollTop = {h};'.format(css=css, h=height) self.execute_script(scroll_life) self.execute_script(scroll_top) def get_attribute(self, attribute=None, index=0, **kwargs): """ Gets the value of an element attribute. Usage: self.get_attribute(css="#el", attribute="type") """ if attribute is None: raise ValueError("attribute is not None") elem = get_element(**kwargs)[index] show_element(elem) return elem.get_attribute(attribute) def get_text(self, index=0, **kwargs): """ Get element text information. Usage: self.get_text(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) return elem.text def get_display(self, index=0, **kwargs): """ Gets the element to display,The return result is true or false. Usage: self.get_display(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) return elem.is_displayed() @property def get_title(self): """ Get window title. Usage: self.get_title() """ return Seldom.driver.title @property def get_url(self): """ Get the URL address of the current page. Usage: self.get_url() """ return Seldom.driver.current_url @property def get_alert_text(self): """ Gets the text of the Alert. Usage: self.get_alert_text() """ return Seldom.driver.switch_to.alert.text def wait(self, secs=10): """ Implicitly wait.All elements on the page. Usage: self.wait(10) """ Seldom.driver.implicitly_wait(secs) def accept_alert(self): """ Accept warning box. Usage: self.accept_alert() """ Seldom.driver.switch_to.alert.accept() def dismiss_alert(self): """ Dismisses the alert available. Usage: self.dismiss_alert() """ Seldom.driver.switch_to.alert.dismiss() def switch_to_frame(self, index=0, **kwargs): """ Switch to the specified frame. Usage: self.switch_to_frame(css="#el") """ elem = get_element(**kwargs)[index] show_element(elem) Seldom.driver.switch_to.frame(elem) def switch_to_frame_out(self): """ Returns the current form machine form at the next higher level. Corresponding relationship with switch_to_frame () method. Usage: self.switch_to_frame_out() """ Seldom.driver.switch_to.default_content() def open_new_window(self, index=0, **kwargs): """ Open the new window and switch the handle to the newly opened window. Usage: self.open_new_window(link_text="注册") """ warnings.warn("This method is not recommended", DeprecationWarning, stacklevel=2) original_window = Seldom.driver.current_window_handle elem = get_element(**kwargs)[index] show_element(elem) elem.click() all_handles = Seldom.driver.window_handles for handle in all_handles: if handle != original_window: Seldom.driver.switch_to.window(handle) @property def current_window_handle(self): """ Returns the handle of the current window. :Usage: self.current_window_handle """ return Seldom.driver.current_window_handle @property def new_window_handle(self): """ Returns the handle of the new window. :Usage: self.new_window_handle """ new_handle = self.window_handles return new_handle[-1] @property def window_handles(self): """ Returns the handles of all windows within the current session. :Usage: self.window_handles """ all_handles = Seldom.driver.window_handles return all_handles def switch_to_window(self, window_name): """ Switches focus to the specified window. :Args: - window_name: The name or window handle of the window to switch to. :Usage: self.switch_to_window('main') """ Seldom.driver.switch_to.window(window_name) def screenshots(self, file_path): """ Saves a screenshots of the current window to a PNG image file. Usage: self.screenshots('/Screenshots/foo.png') """ Seldom.driver.save_screenshot(file_path) def select(self, value=None, text=None, index=None, **kwargs): """ Constructor. A check is made that the given element is, indeed, a SELECT tag. If it is not, then an UnexpectedTagNameException is thrown. :Args: - css - element SELECT element to wrap - value - The value to match against Usage: <select name="NR" id="nr"> <option value="10" selected="">每页显示10条</option> <option value="20">每页显示20条</option> <option value="50">每页显示50条</option> </select> self.select(css="#nr", value='20') self.select(css="#nr", text='每页显示20条') self.select(css="#nr", index=2) """ elem = get_element(**kwargs)[index] show_element(elem) if value is not None: Select(elem).select_by_value(value) elif text is not None: Select(elem).select_by_visible_text(text) elif index is not None: Select(elem).select_by_index(index) else: raise ValueError( '"value" or "text" or "index" options can not be all empty.') def get_cookies(self): """ Returns a set of dictionaries, corresponding to cookies visible in the current session. Usage: self.get_cookies() """ return Seldom.driver.get_cookies() def get_cookie(self, name): """ Returns information of cookie with ``name`` as an object. Usage: self.get_cookie() """ return Seldom.driver.get_cookie(name) def add_cookie(self, cookie_dict): """ Adds a cookie to your current session. Usage: self.add_cookie({'name' : 'foo', 'value' : 'bar'}) """ if isinstance(cookie_dict, dict): Seldom.driver.add_cookie(cookie_dict) else: raise TypeError("Wrong cookie type.") def add_cookies(self, cookie_list): """ Adds a cookie to your current session. Usage: cookie_list = [ {'name' : 'foo', 'value' : 'bar'}, {'name' : 'foo', 'value' : 'bar'} ] self.add_cookie(cookie_list) """ if isinstance(cookie_list, list): for cookie in cookie_list: if isinstance(cookie, dict): Seldom.driver.add_cookie(cookie) else: raise TypeError("Wrong cookie type.") else: raise TypeError("Wrong cookie type.") def delete_cookie(self, name): """ Deletes a single cookie with the given name. Usage: self.delete_cookie('my_cookie') """ Seldom.driver.delete_cookie(name) def delete_all_cookies(self): """ Delete all cookies in the scope of the session. Usage: self.delete_all_cookies() """ Seldom.driver.delete_all_cookies() @staticmethod def sleep(sec): """ Usage: self.sleep(seconds) """ time.sleep(sec) def check_element(self, css=None): """ Check that the element exists Usage: self.check_element(css="#el") """ if css is None: raise NameError("Please enter a CSS selector") log.info("👀 check element.") js = 'return document.querySelectorAll("{css}")'.format(css=css) ret = Seldom.driver.execute_script(js) if len(ret) > 0: for i in range(len(ret)): js = 'return document.querySelectorAll("{css}")[{i}].outerHTML;'.format(css=css, i=i) ret = Seldom.driver.execute_script(js) print("{} ->".format(i), ret) else: log.warn("No elements were found.") def get_elements(self, **kwargs): """ Get a set of elements Usage: ret = self.get_elements(css="#el") print(len(ret)) """ return get_element(**kwargs)