自动化教程-封装浏览器驱动

  1. 封装之前需要下载好(浏览器驱动)和(浏览器启动文件),并将其放置到data/browser_driver目录下

下载链接:https://googlechromelabs.github.io/chrome-for-testing/#stable

  1. 创建common目录(公共工具层),在这之下创建browser_start_config.py文件(浏览器启动配置)
  1. 统一封装 WebDriver对象,并配置浏览器启动所需的参数

● 安装依赖库:Options、

● 首先先创建一个BrowserStartConfig类(名称自定义),然后创建一个browser_config方法(名称自定义),传参使用"**dada"(方便后续传多个参数)

python 复制代码
"""
    浏览器启动参数配置:统一封装 WebDriver(网页自动化)和 AppiumDriver(移动端自动化)的启动、关闭、复用逻辑,给框架提供一个"标准的驱动入口"。
"""
import time

# 导入Chrome驱动
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
# 共同工具类
from common.utils import Utils
# 文件操作类
from common.file_operations import FileOperations


class BrowserStartConfig:
    utils = Utils()
    file_operations = FileOperations()

    # WebDriver--------------------------------------------------------------------------------------------------------
    def browser_config(self, **data):
        """
        简化版 browser_config,所有可选参数通过 **data 传入。

        支持的键(都为可选):
          - add_argument (bool) : 是否开启无痕模式(兼容你原名),默认 False
          - binary_location (str): Chrome 可执行文件路径
        返回:
          - webdriver.Chrome 实例(并把它绑定到 self.driver)
        """
        # 获取项目所在路径
        project_path = self.utils.get_project_root()

        # 创建一个ChromeOptions对象,用于指定Chrome浏览器的启动选项
        chrome_options = Options()

        # 1. 是否开启无痕, 默认不开启,True开启, False不开启
        if data.get('add_argument', False):
            # 开启无痕
            chrome_options.add_argument('--incognito')

        # 2. 指定浏览器的启动文件路径,如果不传入,就指定默认路径【注意不是驱动路径,而是浏览器软件的启动文件】
        binary_location = data.get('binary_location', rf"{project_path}\data\Browser_related_files\chrome-win64\chrome.exe")
        chrome_options.binary_location = binary_location

        # 3. 禁用提示
        # 隐藏"Chrome正受到自动测试软件控制"提示
        chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
        # 当启动 Chrome 时,默认会自动加载一个名为 "自动化扩展" 的内部插件。这个插件的作用是帮助 WebDriver 控制浏览器,但会带来两个问题:顶部会显示一条提示、暴露出自动化特征,容易被反爬
        chrome_options.add_experimental_option('useAutomationExtension', False)
        # 告诉 Chrome 启动时不要检查它是否被设置为系统的默认浏览器
        chrome_options.add_argument("--no-default-browser-check")
        # 禁用通知:谷歌浏览器默认会让网站弹出通知权限,这在自动化中会变成意外的弹窗,干扰流程或导致元素无法操作
        chrome_options.add_argument("--disable-notifications")
        # 禁用提示:"Chrome 测试版vxxx仅适用于自动测试。若要进行常规浏览,请使用可自动更新的标准版 Chrome。"
        chrome_options.add_argument('--test-type=gpu')

        # 4. 浏览器文件下载默认目录
        download_subdir = rf"{self.utils.get_project_root()}\data\浏览器文件下载目录\{self.utils.data_skew(data_format='%Y%m%d')}"
        # 将浏览器的默认下载目录写入yaml文件中,以防后续会有用例用到
        self.file_operations.update_yaml(file_name='config.yaml',
                                      update_data_dict={'浏览器下载文件默认路径': download_subdir})
        # 5. 浏览器配置项(用户偏好)
        prefs = {
             'profile': {'password_manager_enabled': False},  # 也是禁用密码保存提示框,确保密码管理彻底关闭

             # 是否允许网站自动连续下载多个文件。1允许,0不允许。
             "profile.default_content_setting_values.automatic_downloads": 1,
            # 是否弹出"保存文件"提示框。False不弹出,True弹出
            "download.prompt_for_download": False,

             # 指定浏览器下载文件时所保存的目录。
             "download.default_directory": download_subdir,
             # 这个设置用于升级下载目录的权限。在某些情况下,如果下载目录的权限不足,这个选项可以帮助确保下载能够成功进行。
             "download.directory_upgrade": True,

             # 这个设置用于控制是否启用安全浏览功能,该功能可以检测并警告用户潜在的恶意网页。在这个场景中,禁用它可以防止下载安全浏览相关的警告或干扰。
             "safebrowsing.enabled": False
             }
        # 将配置项应用到浏览器启动项中
        chrome_options.add_experimental_option('prefs', prefs)

        # 6. 浏览器窗口最大化
        chrome_options.add_argument('--start-maximized')

        # 7. 定义(浏览器驱动)文件所在目录
        service = Service(executable_path=rf'{project_path}\data\Browser_related_files\chromedriver-win64\chromedriver.exe')

        # 8. 设置驱动能力,隐藏自动化特征
        driver_s = webdriver.Chrome(service=service, options=chrome_options)

        # 另一种隐藏浏览器自动化特征的方法(JS注入)【备用的冗余】
        driver_s.execute_script("""
         Object.defineProperty(navigator, 'webdriver', {
           get: () => undefined
         })
         """)

        # 返回配置项
        return driver_s
  1. 创建utils文件(通用工具类),创建"获取项目所在路径"方法
python 复制代码
    # 获取当前项目根目录: 这个函数不要动,所在文件夹名称也不要修改,否则会获取不到
    def get_project_root(self):
        # 获取当前脚本文件的完整路径
        current_file_path = __file__

        # 获取当前脚本文件所在的目录路径
        current_directory = os.path.dirname(current_file_path)

        parts = current_directory.rsplit(os.path.sep, 1)  # 分割一次
        if len(parts) == 2:
            # 如果确实存在分隔符,则parts[0]是除了最后一部分之外的所有路径
            new_path = parts[0]
        else:
            # 如果没有找到分隔符(比如路径是根目录或只有一个部分),则path就是new_path
            new_path = current_directory
        # 返回项目路径
        return new_path
  1. 创建file_operations文件(文件操作类),创建(读取Yaml、指定读取data目录Yaml、写入Yaml、更新Yam)4个方法
python 复制代码
    # 读取yaml文件
    def read_yaml(self, yaml_path):
        """
        :param yaml_path: yaml文件路径
        :return:
        """
        # 打开yaml文件
        file = open(yaml_path, 'r', encoding='utf-8')
        # 读取yaml文件
        data = yaml.load(file, Loader=yaml.SafeLoader)
        return data


    # 写入Yaml文件: 会覆盖整个文件中的数据。输入data目录下的文件名称, 返回该文件内指定文件名的文件中【特殊方法】
    def write_data_folder(self, file_name, data):
        """
        :param file_name: 文件名称【该文件需要再data目录下】
        :param data: 需要写入的数据【需字典格式】
        :return:
        """
        # 通过文件名称获取(文件路径)
        file_path = self.utils.search_file(rf'{self.utils.get_project_root()}\data', rf'{file_name}')

        # 打开文件
        with open(file_path, 'w', encoding='utf-8') as f:
            # 写入文件
            yaml.dump(data=data, stream=f, allow_unicode=True)
        print('------写入yaml文件成功')

    # 更新yaml
    # 不会覆盖文件中原有数据,存在则更新,不存在则新增
    def update_yaml(self, file_name, update_data_dict):
        """
        :param file_name: 需要写入的文件名称, 注意,该文件必须在data目录下才行
        :param update_data_dict: 需要写入的数据字典, 如:{'token>uuc_token': '666'...}, token代表父级, uuc_token代表子级,666代表值
        :return:
        """
        # 读取yaml文件(这个函数是读取yaml函数,可以看上面的)
        data = self.read_data_yaml_file(file_name)

        # 更新数据
        for key, value in update_data_dict.items():
            # 将层级管理用>符号分隔开
            parts = key.split('>')
            current = data

            for part in parts[:-1]:
                if part not in current:
                    current[part] = {}
                current = current[part]
            current[parts[-1]] = value

        # 写入yaml文件
        self.write_data_folder(file_name, data)

在utils文件补上(通过文件名称获取文件路径)方法

python 复制代码
    # 搜索某个文件夹下所有文件, 输入文件名,可以获取该文件的所在绝对路径
    def search_file(self, dir_path, file_name):
        """ 可以层层往下找
        :param dir_path: 文件夹路径
        :param file_name:  文件夹内文件的名称,需要加后缀

        :return:
        """
        for root, dirs, files in os.walk(dir_path):
            for file in files:
                if file == file_name:
                    return os.path.join(root, file)
        return None
  1. 测试浏览器驱动类是否配置成功,运行"browser_start_config.py"文件里面的"browser_config"方法,如果能弹出如下界面,则说明类封装成功

封装成功

相关推荐
发光小北2 分钟前
单通道串口服务器如何应用?
运维·服务器·单片机
.千余4 分钟前
【Linux】Socket编程UDP
linux·运维·服务器·开发语言·网络协议·学习·udp
开开心心_Every13 分钟前
支持自定义名单的实用随机抽签工具
运维·服务器·pdf·电脑·excel·启发式算法·宽度优先
Harm灬小海15 分钟前
【云计算学习之路】企业常用服务搭建:构建Apache WEB服务器
运维·服务器·学习·云计算·apache
大江东去浪淘尽千古风流人物21 分钟前
【Polaris-VIO】Docker 镜像跨硬件分发的隐藏陷阱:AVX-512、-march=native 与 CPU 指令集解耦边界
运维·docker·容器·slam·vio·avx-512
工业机器人销售服务21 分钟前
攻克大型钣金搬运难题:伯朗特高负载机型完成重型工件精准移栽,保障作业全程安全
机器人·自动化
十子木22 分钟前
SSH 反向端口转发 (Remote Port Forwarding)
运维·ssh
AI云原生26 分钟前
远程控制软件进入协作阶段:ToDesk、向日葵、AnyDesk、RustDesk怎么选?
运维·服务器·网络·windows·docker·云原生·开源软件
测试员周周7 小时前
【Appium 系列】第16节-WebView-H5上下文切换 — 混合应用的自动化难点
运维·开发语言·人工智能·功能测试·appium·自动化·测试用例
北京耐用通信10 小时前
全域适配工业场景耐达讯自动化Modbus TCP 转 PROFIBUS 网关轻松实现以太网与现场总线互通
网络·人工智能·网络协议·自动化·信息与通信