selenium-封装一个browser

  • browser: 浏览器
  • 封装了浏览器相关操作
  • 创建一个默认浏览器:Browser()
  • 浏览器默认配置:Browser.DEFAULT_CONFIG
  • 创建自定义浏览器:Browser(config=config),config根据默认配置的数据结构传入即可
import importlib
from selenium.webdriver import Chrome, ChromeOptions, ActionChains
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec

from loguru import logger
from collections import namedtuple, defaultdict

Locator = namedtuple('Locator', ('type', 'value'))


class Browser:
    MAX_TIMEOUT = 30
    DEFAULT_CONFIG = {
        'browser': 'Chrome',
        # 显示等待超时时间
        'timeout': MAX_TIMEOUT,
        # 地址栏搜索页面加载超时时间
        'page_max_load_time': MAX_TIMEOUT,
        'browser_options':{
            # 浏览器-无界面模式
            '--headless': False,
            # 浏览器-root权限
            '--no-sandbox': True,
            # 浏览器-禁用共享内存
            '--disable-dev-shm-usage': True
        }

    }

    def __init__(self, config=None):
        # 加载配置
        config = config or {}
        self.config = {**Browser.DEFAULT_CONFIG, **config}
        # 创建驱动
        self.driver = Browser.create_driver(self.config)
        # 全屏
        self.driver.maximize_window()
        # 隐式等待
        self.driver.implicitly_wait(self.config.get('timeout'))
        # 显示等待
        self.waiter = WebDriverWait(self.driver, timeout=self.config.get('timeout'))
        # 元素操作
        self.action = ActionChains(self.driver)
        logger.info(f'初始化浏览器配置 => {self.config}')

    @staticmethod
    def create_driver(config) -> WebDriver:
        # 获取配置信息
        browser_name = config.get('browser')
        browser_options_name = browser_name + 'Options'
        browser_options_kwargs = config.get('browser_options')

        # 动态导入模块
        webdriver = importlib.import_module('selenium.webdriver.__init__')

        # 根据配置创建浏览器驱动和配置
        browser_class = getattr(webdriver, browser_name)

        browser_options = getattr(webdriver, browser_options_name)()
        for k, v in browser_options_kwargs.items():
            if v is True:
                browser_options.add_argument(k)

        return browser_class(options=browser_options)


    # js操作
    def js(self, script: str, *args):
        logger.info(f'js操作 => {script}({args})')
        self.driver.execute_script(script, *args)

    # 页面级操作

    def search(self, url):
        logger.info(f'当前页面地址栏输入 => {url}')
        self.driver.set_page_load_timeout(self.config.get('page_max_load_time'))
        self.driver.get(url)

    def f5(self):
        logger.info('刷新当前页面')
        self.driver.refresh()

    def close_window(self):
        logger.info('关闭当前窗口')
        self.driver.close()

    def quit_browser(self):
        logger.info('关闭浏览器')
        self.driver.quit()

    @property
    def html(self):
        _ = self.driver.page_source
        logger.info(f'源码 => {_}')
        return _

    def to_window(self, handle):
        logger.info(f'跳转到指定窗口 => {handle}')
        self.driver.switch_to.window(handle)

    def current_window(self):
        _ = self.driver.current_window_handle
        logger.info(f'当前窗口 => {_}')
        return self.driver.current_window_handle

    def all_window(self):
        _ = self.driver.window_handles
        logger.info(f'所有窗口 => {_}')
        return _

    def to_frame_by_element(self, locator):
        # 这里只支持通过子元素进入,如果需要通过引用则重写
        logger.info(f'进入{locator}元素所在frame => {locator}')
        self.driver.switch_to.frame(self.find_elements(locator))

    def move_to_by_element(self, locator):
        logger.info(f'窗口显示位置移到到{locator}')
        self.action.move_to_element(self.find_element(locator))

    def move_to_by_js(self, x=100000, y=100000):
        # 未传参 或 超出了范围 则 滑到末尾
        logger.info(f'js滑动窗口 => window.scrollTo({x},{y})')
        x = x if 0<=x<=100000 else 100000
        y = y if 0<=x<=100000 else 100000
        self.js(f'window.scrollTo({x},{y})')

    # 元素级操作

    def _accord_wait(self, scanner):
        return self.waiter.until(scanner)

    def find_element(self, locator: Locator):
        logger.info(f'显示等待获取一个元素 => {locator}')
        return self._accord_wait(ec.presence_of_element_located(locator))

    def find_elements(self, locator):
        logger.info(f'显示等待获取一组元素 => {locator}')
        return self._accord_wait(ec.presence_of_all_elements_located(locator))

    def input(self, locator: Locator, text):
        logger.info(f'输入文本 => {locator} => {text}')
        ele = self.find_element(locator)
        ele.clear()
        ele.send_keys(text)

    def click(self, locator: Locator):
        logger.info(f'点击元素 => {locator}')
        self.find_element(locator).click()

    def text(self, locator: Locator):
        _ = self.find_element(locator).text
        logger.info(f'获取元素文本 => {locator} => {repr(_)}')
        return _


def test():
    # 创建浏览器1
    browser1 = Browser()
    # 创建浏览器2
    browser2 = Browser()
    # 浏览器搜索
    browser.search('http://www.baidu.com')
    # 浏览器搜索
    browser.search('https://www.cnblogs.com/yufeihlf/p/5689042.html')


if __name__ == '__main__':
    test()

原文地址:https://www.cnblogs.com/bonus_scene/p/15214810.html