当前位置: 首页 > article >正文

12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建

文章目录

      • 一、如何实现一条用例,实现覆盖所有用例的测试
        • 1、结合数据驱动:编辑一条用例,外部导入数据实现循环测试
        • 2、用例体:实现不同用例的操作步骤+对应的断言
      • 二、实战
        • 1、项目路径总览
        • 2、common 文件夹下的代码文件
        • 3、keywords 文件夹下的代码文件
        • 4、testcases 文件夹下的代码文件
        • 4、testdata 文件夹下的 case_data.xlsx 文件
        • 5、config.py 文件
      • 三、web 自动化测试完结-项目代码(总)

一、如何实现一条用例,实现覆盖所有用例的测试

1、结合数据驱动:编辑一条用例,外部导入数据实现循环测试
2、用例体:实现不同用例的操作步骤+对应的断言
  • 封装对应的方法,可以执行所有用例的操作步骤+断言

二、实战

通过读取 excel 数据,进行数据驱动自动化测试
通过反射函数,实现关键字驱动
即使不懂代码的人,也能通过编辑 excel 数据进行测试

1、项目路径总览

2、common 文件夹下的代码文件

2.1 excel_operator.py 文件
是对 excel 操作进行封装的方法

import os.path
import timeimport openpyxl
from TestKDT import config
from openpyxl.styles import Font,PatternFill,colorsclass ExcelOperator:"""操作 excel 文件"""def __init__(self,filename=os.path.join(config.testdata_dir,"case_data.xlsx")):# 获取到测试用例 excel 的文件路径self.file_path = filename# 获取到测试用例 excel 工作簿self.wk = openpyxl.load_workbook(filename)def get_case_data(self):# """获取 excel 工作簿中所有工作表的数据"""# self.sheetnames = self.wk.sheetnames"""获取 excel 工作簿中要执行的用例工作表的数据"""self.sheetnames = self.get_cases_name()values= []# 循环每个工作表for sheet_name in self.sheetnames:# 获取某个工作表某个区间列的数据value = self.get_startcol_endcol_value(sheet_name)case_data = {'case_name': sheet_name, 'steps_data': value}values.append(case_data)return values# 获取执行用例的工作表名称def get_cases_name(self):# 获取汇总用例的工作表cases_sheet = self.wk[config.cases_sheet_name]cases_name = []# 根据是否执行,取到用例的名称for row in range(2,cases_sheet.max_row+1):# 循环汇总表每一行数据is_execute = cases_sheet.cell(row, config.case_is_execute).valueif is_execute=="y":case_name = cases_sheet.cell(row, config.case_name).valuecases_name.append(case_name)return cases_name# 获取某个工作表某个区间列的数据def get_startcol_endcol_value(self,sheetname,startcol=config.keyword_col,endcol=config.action_col):# 获取工作表sheet = self.wk[sheetname]values = []# 循环对应工作表中的每一行数据for row in range(2,sheet.max_row+1):step_data = []for col in range(startcol,endcol+1):value = sheet.cell(row=row,column=col).valueif value is not None:step_data.append(value)values.append(step_data)return values# 将测试步骤的结果写入 excel 文件的用例工作表中def write_step_result(self, sheet_name, row, col, result):"""写入测试步骤的结果"""case_sheet = self.wk[sheet_name]# 写入每步操作步骤结束时间self.write_current_time(case_sheet,row,config.step_end_time)# 写入测试步骤的结果case_sheet.cell(row, col).value = result# 颜色填充 绿色通过 红色失败red_fill = PatternFill(fill_type="solid", fgColor="00FF0000")green_fill = PatternFill(fill_type="solid", fgColor="0000FF00")if result == 'FAIL':case_sheet.cell(row, col).fill = red_fillelse:case_sheet.cell(row, col).fill = green_fillself.wk.save(self.file_path)# 将测试用例的结果写入 excel 文件的用例汇总表中def write_cases_result(self, case_name, sheet_name=config.cases_sheet_name, col=config.case_result,):"""写入测试用例的结果"""cases_sheet = self.wk[sheet_name]for row in range(2,cases_sheet.max_row+1):# 循环汇总表的每一行col_case_name = cases_sheet.cell(row, config.case_name).valueif col_case_name == case_name:# 获取执行的用例case_name = cases_sheet.cell(row, config.case_name).valuesheet = self.wk[case_name]# 写入每条测试用例的结束时间self.write_current_time(cases_sheet, row, config.case_end_time)# 获取每条执行用例的结果steps_result = self.get_sheet_col_value(sheet=sheet, col=config.step_result)# 颜色填充 绿色通过 红色失败red_fill = PatternFill(fill_type="solid", fgColor="00FF0000")green_fill = PatternFill(fill_type="solid", fgColor="0000FF00")# 将结果写入汇总表中if 'FAIL' in steps_result:cases_sheet.cell(row, col).value = 'FAIL'cases_sheet.cell(row, col).fill = red_fillelse:cases_sheet.cell(row, col).value = 'PASS'cases_sheet.cell(row, col).fill = green_fillself.wk.save(self.file_path)def get_sheet_col_value(self, sheet, col):"""获取某个工作表某列的所有数据"""values = []for row in range(2, sheet.max_row + 1):step_col_value = sheet.cell(row, col).valuevalues.append(step_col_value)return valuesdef write_current_time(self, sheet, row, col):"""将当前时间写入某个表格中"""current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())sheet.cell(row, col).value = current_timeif __name__ == '__main__':# print(ExcelOperator().get_startcol_endcol_value("登录",3,6))print(ExcelOperator().get_cases_name())

2.2、logger.py 文件
和之前 POM 的日志一样

import logging
import os
import time
from TestKDT import configclass FrameLogger:def get_logger(self):# 创建日志器logger = logging.getLogger("logger")# 日志输出当前级别及以上级别的信息,默认日志输出最低级别是warningif not logger.handlers:logger.setLevel(logging.INFO)# 创建控制台处理器----》输出控制台SH = logging.StreamHandler()# 创建文件处理器----》输出文件log_path = os.path.join(config.logs_dir, f"log_{time.strftime('%Y%m%d%H%M%S', time.localtime())}.txt")FH = logging.FileHandler(log_path,mode="w",encoding="utf-8")# 日志包含哪些内容    时间  文件  日志级别 :事件描述/问题描述formatter = logging.Formatter(fmt="[%(asctime)s] [%(filename)s] %(levelname)s :%(message)s",datefmt='%Y/%m/%d %H:%M:%S')logger.addHandler(SH)logger.addHandler(FH)SH.setFormatter(formatter)FH.setFormatter(formatter)return logger
3、keywords 文件夹下的代码文件

3.1 library.py 文件
是对各种关键字函数的封装

import os
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from TestKDT import config
from TestKDT.common.logger import FrameLogger as logclass Library:# 登录用例 = 多个操作步骤组成 基于每个操作步骤封装对应的关键字函数# 登录用例:# 1、打开浏览器- 关键字函数- open_browser()# 2、加载项目地址- 关键字函数- load_url()# 3、输入用户名- 关键字函数- input()# 4、输入密码- 关键字函数- input()# 5、点击登录- 关键字函数- click()def __init__(self):self.logger = log().get_logger()def open_browser(self,browser):"""打开浏览器"""# 传入的浏览器参数保持首字母大写browser = browser.capitalize()# 获取不同类型的浏览器驱动try:self.driver = getattr(webdriver, browser)()self.logger.info(f"打开{browser}浏览器成功")except:self.logger.error(f"打开{browser}浏览器失败")raisedef load_url(self, url):"""加载地址"""try:self.driver.get(url)self.logger.info(f"加载项目地址{url}成功")except:self.logger.error(f"加载项目地址{url}失败")raise# 等待元素可见def wait_ele_visibility(self, page_name, loc, timeout=15, poll_fre=0.5):try:WebDriverWait(self.driver, timeout, poll_fre).until(EC.visibility_of_element_located(loc))# WebElement对象self.logger.info(f"在[{page_name}]页面,找到元素:{loc}可见")except:self.logger.error(f"在[{page_name}]页面,未找到元素:{loc}可见!!!")raise# 等待元素存在def wait_ele_presence(self, page_name, loc, timeout=15, poll_fre=0.5):try:WebDriverWait(self.driver, timeout, poll_fre).until(EC.presence_of_element_located(loc))self.logger.info(f"在[{page_name}]页面,找到元素:{loc}存在")except:self.logger.error(f"在[{page_name}]页面,未找到元素:{loc}存在!!!")raisedef locator(self, page_name, by_type, express):# 定位元素try:el = self.driver.find_element(by_type, express)self.logger.info(f"在[{page_name}]页面,通过[{by_type}]方法和[{express}]语句,定位元素成功")except:self.save_screenshot(by_type)self.logger.error(f"在[{page_name}]页面,通过[{by_type}]方法和[{express}]语句,定位元素失败!!!")raisereturn eldef input(self, page_name, by_type, express, text):"""输入"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)self.locator(page_name,by_type, express).send_keys(text)self.logger.info(f"在[{page_name}]页面,元素{loc}输入:{text} 成功!")except:self.logger.error(f"在[{page_name}]页面,元素{loc}输入失败!")# 失败截图self.save_screenshot(page_name)raisedef click(self, page_name, by_type, express):"""点击"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)self.locator(page_name,by_type, express).click()self.logger.info(f"在[{page_name}]页面,元素{loc}点击成功!")except:self.logger.error(f"在[{page_name}]页面,元素{loc}点击失败!")# 失败截图self.save_screenshot(page_name)raisedef move_element(self, page_name, by_type, express):"""移动鼠标"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)el = self.locator(page_name, by_type, express)# 将鼠标移到元素上ActionChains(self.driver).move_to_element(el).perform()self.logger.info(f"在[{page_name}]页面,鼠标移到元素{loc}成功!")except:self.logger.error(f"在[{page_name}]页面,鼠标移到元素{loc}失败!")# 失败截图self.save_screenshot(page_name)raisedef assert_text(self,page_name, by_type, express, expect):"""断言"""loc = (by_type, express)try:self.wait_ele_visibility(page_name, loc)el = self.locator(page_name, by_type, express)fact = el.textself.logger.info(f"在[{page_name}]页面,元素{loc}文本内容获取成功!")except:self.logger.error(f"在[{page_name}]页面,元素{loc}文本内容获取失败!")# 失败截图self.save_screenshot(page_name)raiseif fact == expect:passelse:raise Exception(f"在[{page_name}]页面,断言失败,assertText:{fact} != {expect}")def save_screenshot(self,img_name):file_name = os.path.join(config.screenshots_dir, img_name+'.png')self.driver.save_screenshot(file_name)self.logger.error(f"失败截图,截取当前网页,存储的路径:{file_name}")# 封装方法,可以调用当前类下的所有关键字函数# *args:不定长参数def run(self,keyword,*args):print(keyword, args)# 实现打开浏览器# keyword = "open_browser"# args = ("edge",)# 调用关键字函数,基于反射getattr(self, keyword)(*args)
4、testcases 文件夹下的代码文件

4.1 test_case.py 文件
编写测试用例

import time
import unittest
from selenium.webdriver.common.by import By
from TestKDT.keywords.library import Library
from ddt import ddt,data,file_data,unpack
from TestKDT.common.excel_operator import ExcelOperator
from TestKDT import config@ddt
class TestCase01(unittest.TestCase):# 如何实现一条用例,实现覆盖所有用例的测试# 每条用例的数据: 关键字函数 + 测试数据# case_data = [["open_browser","edge"],["load_url","http://116.62.63.211/shop/user/logininfo.html"],#               ["input",(By.NAME, "accounts"), "hc_test"],#               ["input",(By.XPATH, '//input[@type="password"]'),"hctest123"],#               ["click",(By.XPATH, '//button[text()="登录"]')]]excel = ExcelOperator()case_data = excel.get_case_data()@data(*case_data)def test_cases(self,case_data):# 打印每条用例的数据print(case_data)case_name = case_data['case_name']steps_data = case_data['steps_data']# 用例体 = 操作步骤+ 断言# 封装对应的方法,可以执行所有用例的操作步骤 + 断言lib = Library()for index, step_data in enumerate(steps_data):try:# 执行用例的操作步骤lib.run(*step_data)# 当前执行步骤为 PASS# index  0  行数 2  因为第一行不是测试数据,而是列说明self.excel.write_step_result(sheet_name=case_name, row=index+2, col=config.step_result, result="PASS")except Exception as error:# 当前执行步骤为 FAILself.excel.write_step_result(sheet_name=case_name, row=index+2, col=config.step_result, result="FAIL")self.excel.write_cases_result(case_name)
4、testdata 文件夹下的 case_data.xlsx 文件
  • 4.1 用例汇总统计
  • 4.2 登录成功
  • 4.3 登录失败-1
  • 4.4 登录失败-2
5、config.py 文件

是项目的路径以及其他数据内容

import os# 根路径
base_dir = os.path.dirname(os.path.abspath(__file__))
# 用例路径
testcases_dir = os.path.join(base_dir, 'testcases')
# 数据路径
testdata_dir = os.path.join(base_dir, 'testdata')
# 测试报告路径
reports_dir = os.path.join(base_dir, 'outputs/reports')
# 日志路径
logs_dir = os.path.join(base_dir, 'outputs/logs')
# 失败截图
screenshots_dir = os.path.join(base_dir, 'outputs/screenshots')
# 测试用例 excel 中关键字所在列
keyword_col = 3
# 测试用例 excel 中操作值所在列
action_col = 7
# 用例汇总表名称
cases_sheet_name = "用例汇总统计"
# 用例汇总表中是否执行所在列数
case_is_execute = 5
# 用例汇总表中用例名所在列数
case_name = 2
# 用例汇总表中测试结果所在列数
case_result = 7
# 用例汇总表中测试结束时间所在列数
case_end_time = 6
# 用例工作表中执行结果所在列数
step_result = 9
# 用例工作表中执行时间所在列数
step_end_time = 8# ---调试
print(testdata_dir)

三、web 自动化测试完结-项目代码(总)

Test-Web.zip

相关文章:

12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建

文章目录 一、如何实现一条用例,实现覆盖所有用例的测试1、结合数据驱动:编辑一条用例,外部导入数据实现循环测试2、用例体:实现不同用例的操作步骤对应的断言 二、实战1、项目路径总览2、common 文件夹下的代码文件3、keywords 文…...

动态IP赋能业务增效:技术解构与实战应用指南

在数字化转型加速的今天,IP地址作为网络通信的基础设施,其技术特性正深刻影响着企业业务架构的效率与安全性。动态IP(Dynamic IP)作为互联网资源分配的核心机制,早已突破传统认知中的"临时地址"定位&#xf…...

【Java ee初阶】http(1)

HTTP 全称为“超文本传输协议”,由名字可知,这是一个基于文本格式的协议,而TCP,UDP,以太网,IP...都是基于二进制格式的协议。 如何区别该协议是基于哪种格式的协议? 形如这种协议格式&#xf…...

OkHttp用法-Java调用http服务

特点:高性能,支持异步请求,连接池优化 官方文档:提供快速入门指南和高级功能(如拦截器、连接池)的详细说明,GitHub仓库包含丰富示例。 社区资源:中文教程丰富,GitHub高…...

day18-数据结构引言

一、 概述 数据结构:相互之间存在一种或多种特定关系的数据元素的集合。 1.1 特定关系: 1. 逻辑结构 2.物理结构(在内存当中的存储关系) 逻辑结构物理结构集合,所有数据在同一个集合中,关系平等顺…...

我开源了一个免费在线工具!UIED Tools

UIED Tools - 免费在线工具集合 最近更新:修改了文档说明,优化了项目结构介绍 这是设计师转开发的第一个开源项目,bug和代码规范可能有些欠缺。 这是一个功能丰富的免费在线工具集合网站,集成了多种实用工具,包括 AI …...

什么时候可以开始学习深度学习?

咱们先来聊聊机器学习和深度学习的关系~ 这个问题其实挺常见的,之前我也跟不少同事、同学聊过。最近有好几个同学也聊过。 简单说,深度学习是机器学习的一个子集,两者不是并列关系,而是“包含”关系。 你可以这么理解&#xff…...

初学python的我开始Leetcode题8-5

提示:100道LeetCode热题-8-5主要是二叉树相关,包括三题:路径总和 III、二叉树的最近公共祖先、二叉树中的最大路径和。由于初学,所以我的代码部分仅供参考。 前言 二叉树完结撒花~ 下一次的图论会是一些有趣的应用案例~ 提示&am…...

构建RAG混合开发---PythonAI+JavaEE+Vue.js前端的实践

写在前文:之所以设计这一套流程,是因为 Python在前沿的科技前沿的生态要比Java好,而Java在企业级应用层开发比较活跃; 毕竟许多企业的后端服务、应用程序均采用Java开发,涵盖权限管理、后台应用、缓存机制、中间件集成…...

08.webgl_buffergeometry_attributes_none ,three官方示例+编辑器+AI快速学习

本实例主要讲解内容 这个Three.js示例展示了无属性几何体渲染技术,通过WebGL 2的gl_VertexID特性和伪随机数生成算法,在着色器中动态计算顶点位置和颜色,而不需要在CPU端预先定义几何体数据。 核心技术包括: WebGL 2的顶点ID特…...

26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述

26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述 文章目录 26考研 | 王道 | 计算机组成原理 | 一、计算机系统概述1.1 计算机的发展1.2 计算机硬件和软件1.2.1 计算机硬件的基本组成1.2.2 各个硬件的工作原理1.2.3 计算机软件1.2.4 计算机系统的层次结构1.2.5 计算机系统…...

转换算子介绍

### 转换算子的定义与用法 #### 定义 转换算子(Transformation Operators)是指用于处理分布式数据集的操作符,在大数据框架中广泛使用,例如Apache Flink和Apache Spark。这些操作符允许开发者对数据集执行各种变换操作&#xff0…...

Android学习总结之Glide自定义三级缓存(实战篇)

一、为什么需要三级缓存 内存缓存(Memory Cache) 内存缓存旨在快速显示刚浏览过的图片,例如在滑动列表时来回切换的图片。在 Glide 中,内存缓存使用 LruCache 算法(最近最少使用),能自动清理长…...

单片机开发软件

目录 纯编码 vscode Ardunio Keil 1. 集成化开发环境(IDE) 2. 多架构芯片支持 3. 高效的代码生成与优化 4. 强大的调试与仿真功能 5. 丰富的库函数与生态系统 6. 教育与企业级适用性 典型应用场景 半编码半图形化 STM32CUBEIED 1. 图形化配置…...

LeetCode100.2 字母异位词分组

观察题目&#xff0c;需要把strs中的元素按照字母进行归类&#xff0c;一个朴素的思路是&#xff1a;遍历strs&#xff0c;对每个元素排序后插入哈希表中&#xff0c;随后再遍历一遍表将其转化为vector<vector<string>>。 class Solution { public:vector<vect…...

深入了解 Stable Diffusion:AI 图像生成的奥秘

一、引言 AI 艺术与图像生成技术的兴起改变了我们创造和体验视觉内容的方式。在过去几年里&#xff0c;深度学习模型已经能够创造出令人惊叹的艺术作品&#xff0c;这些作品不仅模仿了人类艺术家的风格&#xff0c;甚至还能创造出前所未有的新风格。在这个领域&#xff0c;Sta…...

Python爬虫实战:研究ajax异步渲染加密

一、引言 在当今数字化时代,数据已成为推动各行业发展的核心驱动力。网络爬虫作为一种高效的数据采集工具,能够从互联网上自动获取大量有价值的信息。然而,随着 Web 技术的不断发展,越来越多的网站采用了 AJAX(Asynchronous JavaScript and XML)异步渲染技术来提升用户体…...

大语言模型训练的两个阶段

先说结论&#xff1a;第一阶段在云平台训练至收敛 第二阶段本地GPU微调 一、阶段划分的核心逻辑 阶段目标资源特点典型耗时占比成本敏感度预训练获取通用表征能力需要大规模分布式计算70-90%高&#xff08;追求每美元算力&#xff09;微调适配特定任务需要领域数据安全/低延迟…...

显示的图标跟UI界面对应不上。

图片跟UI界面不符合。 要找到对应dp的值。UI的dp要跟代码里的xml文件里的dp要对应起来。 蓝湖里设置一个宽度给对应上。然后把对应的值填入xml. 一个屏幕上的图片到底是用topmarin来设置&#xff0c;还是用bottommarin来设置。 因为第一节&#xff0c;5&#xff0c;7 车厢的…...

OJ判题系统第6期之判题逻辑开发——设计思路、实现步骤、代码实现(策略模式)

在看这期之前&#xff0c;建议先看前五期&#xff1a; Java 原生实现代码沙箱&#xff08;OJ判题系统第1期&#xff09;——设计思路、实现步骤、代码实现-CSDN博客 Java 原生实现代码沙箱之Java 程序安全控制&#xff08;OJ判题系统第2期&#xff09;——设计思路、实现步骤…...

css中的 vertical-align与line-height作用详解

一、vertical-align 详解 作用对象&#xff1a;行内元素&#xff08;inline/inline-block&#xff09;或表格单元格内容核心功能&#xff1a;控制元素在行框内的垂直对齐方式常用取值&#xff1a; baseline&#xff08;默认&#xff09;&#xff1a;基线与父元素基线对齐top&a…...

vue数据可视化开发echarts等组件、插件的使用及建议-浅看一下就行

在 Vue 项目中使用 ECharts 进行数据可视化开发时&#xff0c;可以结合 Vue 的响应式特性和 ECharts 的强大功能&#xff0c;实现动态、交互式的图表展示。 一、ECharts 基础使用 1. 安装 ECharts npm install echarts2. 在 Vue 组件中使用 ECharts <template><div…...

高并发内存池(三):TLS无锁访问以及Central Cache结构设计

目录 前言&#xff1a; 一&#xff0c;thread cache线程局部存储的实现 问题引入 概念说明 基本使用 thread cache TLS的实现 二&#xff0c;Central Cache整体的结构框架 大致结构 span结构 span结构的实现 三&#xff0c;Central Cache大致结构的实现 单例模式 thr…...

在Taro中开发一个跨端Svg组件,同时支持小程序、H5、React Native

Taro系列中一直没有跨端的绘图工具&#xff0c;小程序端支持canvas但是不支持svg&#xff0c;RN端有 react-native-svg 支持svg&#xff0c;但是没有很好原生的canvas插件&#xff0c;社区的canvas都是基于WebView实现的&#xff0c;或者skia&#xff0c;这个插件的书写方式和c…...

【办公类-100-01】20250515手机导出教学照片,自动上传csdn+最大化、最小化Vs界面

背景说明&#xff1a; 每次把教学照片上传csdn&#xff0c;都需要打开相册&#xff0c;一张张截图&#xff0c;然后ctrlV黏贴到CSDN内&#xff0c;我觉得太烦了。 改进思路&#xff1a; 是否可以先把所有照片都上传到csdn&#xff0c;然后再一张张的截图&#xff08;去掉幼儿…...

SIP协议栈--osip源码梳理

文章目录 osiposip主体结构体code main函数 状态机转化结构体code状态转换 sip事务结构体code osip_dialog结构体code 创建并发送200 OK响应 osip_message结构体code osip_eventcode 打印接收到的SIP消息 osip OSIP&#xff08;Open Source Implementation of SIP&#xff09;…...

Python零基础入门到高手8.4节: 元组与列表的区别

目录 8.4.1 不可变数据类型 8.4.2 可变数据类型 8.4.3 元组与列表的区别 8.4.4 今天彩票没中奖 8.4.1 不可变数据类型 不可变数据类型是指不可以对该数据类型进行原地修改&#xff0c;即只读的数据类型。迄今为止学过的不可变数据类型有字符串&#xff0c;元组。 在使用[]…...

深度学习入门:深度学习(完结)

目录 1、加深网络1.1 向更深的网络出发1.2 进一步提高识别精度1.3 加深层的动机 2、深度学习的小历史2.1 ImageNet2.2 VGG2.3 GoogleNet2.4 ResNet 3、深度学习的高速化3.1 需要努力解决的问题3.2 基于GPU的高速化3.3 分布式学习3.4 运算精度的位数缩减 4、深度学习的应用案例4…...

OpenCV CUDA模块中矩阵操作------矩阵元素求和

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在OpenCV的CUDA模块中&#xff0c;矩阵元素求和类函数主要用于计算矩阵元素的总和、绝对值之和以及平方和。这些操作对于图像处理中的特征提取、…...

使用Scrapeless Scraping Browser的自动化和网页抓取最佳实践

引言&#xff1a;人工智能时代浏览器自动化和数据收集的新范式 随着生成性人工智能、人工智能代理和数据密集型应用程序的快速崛起&#xff0c;浏览器正在从传统的“用户互动工具”演变为智能系统的“数据执行引擎”。在这一新范式中&#xff0c;许多任务不再依赖单一的API端点…...