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

  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"方法,如果能弹出如下界面,则说明类封装成功

封装成功

相关推荐
ch3nyuyu2 小时前
静态库和动态库的制作
linux·运维·开发语言
程序员老邢2 小时前
【产品底稿 07】商助慧 Admin 运维模块落地:从 “能跑” 到 “能运维”,3 个页面搞定日常排障
java·运维·经验分享·spring boot·后端
一口Linux2 小时前
Linux C编程 | 从0实现telnet获取程序终端控制权
linux·运维·c语言
风翼靓崽4 小时前
linux命令杂记 - 杂乱无章
linux·运维·服务器
域中四大5 小时前
rk3568中修改波特率
linux·运维
互联网推荐官5 小时前
大模型应用开发的上下文工程与推理链路深度拆解
大数据·运维·人工智能
风曦Kisaki5 小时前
# Linux Shell 编程入门 Day01:Shell 基础认知、脚本编写规范、变量四大类型、数值运算
linux·运维·chrome
云智慧AIOps社区5 小时前
云智慧亮相第二十八届智能体驱动的GOPS全球运维大会2026 · 深圳站!以运维智能体 Castrel AI (SRE Agent)保障系统稳定可靠!
运维·人工智能·ai agent·运维自动化·sre 智能体
校羽干5 小时前
ubuntu22.04 安装卸载更新 ollama
运维·服务器