UI界面自动化BagePage
常用basepage模块代码
# -*- coding: utf-8 -*-
# @Desc: UI自动化测试的一些基础浏览器操作方法# 第三方库导入
import time
from logging import config
import randomimport allure
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.select import Selectimport config
from common.utils.ReturnTime import ReturnTime
from jc_log.setting import get_logger
import pyautogui
from pywinauto.keyboard import send_keys
from selenium.common.exceptions import NoSuchElementException, InvalidSelectorException, TimeoutException
from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWaitlogger = get_logger(__name__)
g_timeout = 10
g_poll_frequency = 0.2class BasePage:"""UI自动化基础操作封装"""def __init__(self, driver):self.driver = driverself.__img_dir = config.REPORT_DIRdef refresh(self):"""刷新网页"""self.driver.refresh()def get_url(self, url):"""访问指定地址"""self.driver.get(url=url)return self.driver.current_urldef get_current_url(self):"""获取当前浏览器驱动的地址"""return self.driver.current_urldef force_click(self, locator: tuple, mode: str = "click", force=False):"""鼠标点击,当元素不可点击的时候,使用强制点击:param locator: 元素定位,元祖类型:param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击):param force: 强制点击,默认false"""try:elem = self.find_element(locator=locator, mode=mode)if not force:self.driver.execute_script("arguments[0].click()", elem)else:elem.click()self.driver.execute_script("arguments[0].click({force: true})", elem)except Exception as e:print("未找到元素:{}".format(e))raise edef wait_element_visibility(self, locator: tuple, timeout=20, poll_frequency=g_poll_frequency):"""显性等待: 等待元素可见:param locator: 元素定位,元祖类型:param timeout:param poll_frequency:return:"""page = self.get_current_url()logger.debug(f"-开始-等待页面{page}的元素:{locator}可见")try:# 获取等待开始时间的时间戳__start_time = ReturnTime.get_timestamp()rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(ec.visibility_of_element_located(locator))# 计算元素等待的时间__wait_time = ReturnTime.get_timestamp() - __start_timelogger.debug(f"页面:{page}上的元素{locator}已可见,共计等待{__wait_time:0.2f}秒")except TimeoutException:logger.error(f"页面:{page},等待元素{locator}超时")self.set_error_img()raise TimeoutException('元素等待超时')except InvalidSelectorException as e:logger.error(f"页面:{page},元素不可见或定位表达式:{locator}异常\n {e}")raise InvalidSelectorException('元素定位异常')return rtndef wait_element_clickable(self, locator: tuple, timeout=g_timeout, poll_frequency=g_poll_frequency):"""显性等待: 等待元素可点击:param locator: 元素定位,元祖类型:param timeout::param poll_frequency:return:"""page = self.get_current_url()logger.debug(f"-开始-等待页面{page}的元素:{locator}可点击")try:# 获取等待开始时间的时间戳__start_time = ReturnTime.get_timestamp()rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(ec.element_to_be_clickable(locator))# 计算元素等待的时间__wait_time = ReturnTime.get_timestamp() - __start_timelogger.debug(f"页面:{page}上的元素{locator}已可点击,共计等待{__wait_time:0.2f}秒")except TimeoutException as e:logger.error(f"页面:{page},等待元素{locator}超时")self.set_error_img()raise eexcept InvalidSelectorException as e:logger.error(f"页面:{page},元素不可点击或定位表达式:{locator}异常\n {e}")raise ereturn rtndef wait_element_presence(self, locator: tuple, timeout=g_timeout, poll_frequency=g_poll_frequency):"""显性等待: 等待元素被加载出来:param locator: 元素定位,元祖类型:param timeout:param poll_frequency:return:"""page = self.get_current_url()logger.debug(f"-开始-等待页面{page}的元素:{locator}存在")try:# 获取等待开始时间的时间戳__start_time = ReturnTime.get_timestamp()rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(ec.presence_of_all_elements_located(locator))# 计算元素等待的时间__wait_time = ReturnTime.get_timestamp() - __start_timelogger.debug(f"页面:{page}上的元素{locator}已存在,共计等待{__wait_time:0.2f}秒")except TimeoutException as e:logger.error(f"页面:{page},等待元素{locator}超时")self.set_error_img()raise eexcept InvalidSelectorException as e:logger.error(f"页面:{page},元素不存在或定位表达式:{locator}异常\n {e}")raise ereturn rtndef wait_element_not_visible(self, locator: tuple, timeout=g_timeout, poll_frequency=g_poll_frequency):"""等待元素不可见:param locator: 元素定位表达式:param timeout:param poll_frequency:return::return: 无返回值"""page = self.get_current_url()logger.debug(f"-开始-等待页面{page}的元素:{locator}存在")try:# 获取等待开始时间的时间戳__start_time = ReturnTime.get_timestamp()time.sleep(1)rtn = WebDriverWait(self.driver, timeout, poll_frequency).until(ec.invisibility_of_element_located(locator))# 计算元素等待的时间__wait_time = ReturnTime.get_timestamp() - __start_timelogger.debug(f"页面:{page}上的元素{locator}已经不可见,共计等待{__wait_time:0.2f}秒")except TimeoutException as e:logger.error(f"页面:{page},等待元素{locator}不可见超时")self.set_error_img()raise eexcept InvalidSelectorException as e:logger.error(f"页面:{page},元素不存在或定位表达式:{locator}异常\n {e}")raise ereturn rtndef get_element_attribute(self, locator: tuple, attr_name):"""获取元素属性值:param locator: 元素定位,元祖类型:param attr_name:return: 元素属性值"""try:return self.driver.find_element(*locator).get_attribute(attr_name)except NoSuchElementException as e:print("未找到元素:{}".format(e))raise edef get_name(self, locator: tuple):"""获取元素的name属性值"""return self.get_element_attribute(locator, "name")def get_title(self, locator: tuple):"""获取元素的title属性值"""return self.get_element_attribute(locator, "title")def get_class(self, locator: tuple):"""获取元素的class属性值"""return self.get_element_attribute(locator, "class")def switch_to_frame(self, reference=None, timeout=g_timeout, poll=g_poll_frequency):"""iframe切换:param reference: 可以是id, name,索引或者元素定位(元祖):param timeout::param poll::return:"""if not reference:return self.driver.switch_to.default_content()return WebDriverWait(self.driver, timeout, poll).until(ec.frame_to_be_available_and_switch_to_it(reference))def __get_title_handle(self, title):handles = self.driver.window_handlesfor handle in handles:self.driver.switch_to.window(handle)if self.driver.title == title:return handledef switch_to_window(self, title):"""切换到指定窗口"""self.__get_title_handle(title)return selfdef switch_next_window(self):"""切换到另一个窗口"""# 获取所有的窗口windows = self.driver.window_handlesif len(windows) >= 2:# 切换窗口self.driver.switch_to.window(self.driver.window_handles[-1])return selfdef open_new_window(self, url):"""打开一个新窗口"""# 获取所有的窗口start_window = self.driver.window_handls# 打开新窗口js = "window.open({})".format(url)self.driver.execute_script(js)# 等待新窗口出现,进行切换WebDriverWait(self.driver, 5, 0.5).until(ec.new_window_is_opened(start_window))# 切换窗口self.driver.switch_to.window(self.driver.window_handls[-1])return selfdef __select_wait_method(self, locator: tuple, mode: str = "visible") -> None:"""选择元素定位的等待方式:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param mode: visible(元素可见), exist(元素存在),click(元素可点击):return: 无返回值"""page = self.get_current_url()if mode == "visible":self.wait_element_visibility(locator=locator)elif mode == "exist":self.wait_element_presence(locator=locator)elif mode == "click":self.wait_element_clickable(locator=locator)else:logger.error(f"定位{page}页面的元素:{locator},mode参数传值异常,入参值为:{mode}")def find_element(self, locator: tuple, mode: str = "visible") -> WebElement:"""定位元素,支持所有定位单个元素的定位表达式:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param mode: visible(元素可见), exist(元素存在),click(元素可点击):return: 定位到的元素对象"""page = self.get_current_url()self.__select_wait_method(locator=locator, mode=mode)try:logger.debug(f"正在定位{page}页面的: {locator} 的元素")element = self.driver.find_element(*locator)self.element_dyeing(element=element)return elementexcept TimeoutException:logger.error(f"页面:{page},定位元素:{locator}定位超时")self.set_error_img()raise TimeoutException("元素定位超时请检查")except Exception:logger.error(f"页面:{page},定位元素:{locator}定位失败")self.set_error_img()raise Exception("元素定位失败请检查")def find_elements(self, locator: tuple, mode: str = "visible") -> list:"""定位一组元素,返回一个列表:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在):return: 返回一组元素是一个列表"""page = self.get_current_url()self.__select_wait_method(locator=locator, mode=mode)try:logger.debug(f"正在定位{page}页面的: {locator} 的元素")element_list = self.driver.find_elements(*locator)return element_listexcept NoSuchElementException as e:logger.error(f"页面:{page},定位元素:{locator}定位失败")self.set_error_img()raise edef __move_element_visible(self, locator: tuple, element: WebElement, alignment: bool = False) -> None:"""将元素移动到页面可见区域:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param alignment 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param element 需要可见的元素:return: 无返回值"""page = self.get_current_url()logger.debug(f'将{page}页面的元素:{locator}移动至浏览器可见区域')try:# 代码执行比页面渲染速度快 这里放0.5秒等待页面渲染time.sleep(0.5)self.driver.execute_script('arguments[0].scrollIntoView({0});'.format(alignment), element)# 休眠1秒让页面可以正常滚动到对应的位置再执行下去time.sleep(1)except Exception as e:logger.error(f"{page}页面的元素:{locator}移动失败\n{e}")self.set_error_img()raise edef click(self, locator: tuple, mode: str = "click", alignment: bool = False, move_element: bool = False,is_double_click: bool = False) -> None:"""点击元素:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:param is_double_click: False单击元素,传入True 双击元素:return: 无返回值"""page = self.get_current_url()element = self.find_element(locator=locator, mode=mode)if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)try:logger.debug(f"点击:{page}页面,属性为{locator}的元素")if is_double_click:ActionChains(self.driver).double_click(element).perform()else:element.click()except Exception as e:logger.error(f"页面{page}的元素: {locator} 点击失败")self.set_error_img()raise edef click_elements(self, locator: tuple, mode: str = "click", alignment: bool = False, move_element: bool = False,is_double_click: bool = False) -> None:"""点击一组元素:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param mode: visible(元素可见),notvisible(元素消失不可见), exist(元素存在),click(元素可点击):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:param is_double_click: False单击元素,传入True 双击元素:return: 无返回值"""page = self.get_current_url()elements = self.find_elements(locator=locator, mode=mode)if move_element is True:self.__move_element_visible(locator=locator, element=elements[0], alignment=alignment)try:logger.debug(f"点击:{page}页面,属性为{locator}的元素")for element in elements:if is_double_click:ActionChains(self.driver).double_click(element).perform()else:element.click()except Exception as e:logger.error(f"页面{page}的元素: {locator} 点击失败")self.set_error_img()raise edef random_click_element(self, locator: tuple, num: int, mode: str = "click", alignment: bool = False,move_element: bool = False) -> str:"""随机点击一个元素:param locator: 元素的定位表达式 例:(By.xx,'定位表达式'):param num: 从第几位元素开始点击:param mode: visible(元素可见), exist(元素存在),click(元素可点击):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:return: 点击的元素的文本"""page = self.get_current_url()elements = self.find_elements(locator=locator, mode=mode)click_num: int = random.randint(num, len(elements) - 1)try:element = elements[click_num]if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)self.element_dyeing(element)logger.debug(f"点击:{page}页面,属性为{locator}的元素中的{click_num}位")element.click()except Exception as e:logger.error(f"页面{page}的元素: {locator} 中的第{click_num}位元素点击失败")self.set_error_img()raise ereturn element.textdef input_text(self, locator: tuple, content: str or int, mode: str = "visible", alignment: bool = False,move_element: bool = False) -> WebElement:"""输入文本内容:param locator: 传入元素定位表达式:param content: 传入输入的文本内容:param mode: visible(元素可见), exist(元素存在):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:return: 无返回值"""page = self.get_current_url()element = self.find_element(locator=locator, mode=mode)if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)try:self.clear_contents(locator=locator, mode=mode, alignment=alignment)logger.debug(f"输入操作:{page}页面下的属性为:{locator}的元素,输入内容为{content}")element.send_keys(content)self.driver.execute_script("arguments[0].setAttribute('style', 'background: write; border: 1px solid black;');", element)except Exception as e:self.set_error_img()logger.error(f"页面{page}的属性: {locator} 输入操作失败")raise ereturn elementdef clear_contents(self, locator: tuple, mode: str = "visible", alignment: bool = False,move_element: bool = False) -> None:"""清除文本内容:param locator: 传入元素定位表达式:param mode: visible(元素可见), exist(元素存在):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:return: 无返回值"""page = self.get_current_url()element = self.find_element(locator=locator, mode=mode)if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)try:logger.debug(f"输入操作:{page}页面下的属性为:{locator}的元素,清除内容")# 保证正常清除time.sleep(0.2)element.clear()except Exception as e:self.set_error_img()logger.error(f"页面{page}的属性: {locator} 清除操作失败")raise edef get_element_text(self, locator: tuple, mode: str = 'visible', alignment: bool = False,move_element: bool = False) -> str:"""获取元素的文本内容:param locator: 传入元素定位表达式:param mode: visible(元素可见), exist(元素存在):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:return: 返回获取到的元素文本内容"""page = self.get_current_url()element = self.find_element(locator=locator, mode=mode)if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)try:logger.debug(f"文本获取操作:获取{page}页面下的属性为:{locator}的元素的文本内容")return element.textexcept Exception as e:logger.error(f"页面{page}的元素:{locator}获取文本操作失败")self.set_error_img()raise edef click_radios(self, locator: tuple, method: str, amount: int = None, mode: str = 'visible',alignment: bool = False, move_element: bool = False) -> WebElement:"""复选框内容点击:param locator: 传入元素定位表达式:param mode: visible(元素可见), exist(元素存在):param amount: 传入复选项的数量 例子如果是3个选项就传入3:param method: 选择对应的内容选择方式 all 点击复选框的全部内容 random 随机点击复选框的中的某一个选项 assign点击指定的某个复选项:param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用:return: 全部点击时无返回,其他返回被点击的元素"""# 定位到复选框一定是一组元素page = self.get_current_url()elements: list[WebElement] = self.find_elements(locator=locator, mode=mode)try:logger.debug('点击方式为:{}'.format(method))if method == 'all':# 点击复选项中每一个元素for ele in elements:if move_element is True:self.__move_element_visible(locator=locator, element=ele, alignment=alignment)ele.click()# 随机点击复选项中的某一个内容elif method == 'random':# 导入随机数包import random# 生成指定范围之内的随机数作为需要点击的radionum = random.randint(0, amount - 1)element = elements[num]if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)element.click()# 返回被点击的元素return element# 点击复选框中指定位置的选项elif method == 'assign':# 因为从0开始计数,所以传入的 amount-1element = elements[amount - 1]if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)element.click()return elementelse:logger.error('点击方式输入错误,请检查')except Exception as e:logger.error(f"页面{page}的元素:{locator}复选框点击操作失败")self.set_error_img()raise e@staticmethoddef element_is_selected(element: WebElement):"""判断元素是否勾选:param element: 需要校验是否勾选的元素:return: 选中是Ture 没有选择是False"""return element.is_selected()def select_contents_menu(self, locator: tuple, text: str, mode: str = 'visible', alignment: bool = False,move_element: bool = False) -> None:"""选择下拉菜单中的内容:param locator: 传入元素定位表达式:param text: 出入下拉列表需要选择的内容:param mode: visible(元素可见), exist(元素存在):param alignment: 默认对齐方式是元素和当前页面的底部对齐,可以传 alignment=''表示和顶部对齐:param move_element: 这里是布尔值 传入True 表示需要让元素滚动到页面可见区域 False 表示不用"""page = self.get_current_url()element = self.find_element(locator=locator, mode=mode)# 定义一个存储菜单内容的空列表option = []if move_element is True:self.__move_element_visible(locator=locator, element=element, alignment=alignment)try:# 获取下拉列表的内容options = element.find_elements_by_tag_name("option")for value in options:option.append(value)if text in option:Select(element).select_by_visible_text(text)else:logger.error(f"选项:{text}不在下拉列表之中请检查")except Exception as e:self.set_error_img()logger.error(f"页面{page}的元素:{locator}下拉框操作失败请检查")raise edef dispose_alert(self, action: str) -> str:"""处理页面alert:param action: 参数为 accept 点击alert的确定 dismiss点击alert的取消:return: 返回alert的文本内容 可能有些用例需要用这个参数去校验"""# 等待alert出现再去操作WebDriverWait(self.driver, 5, 0.5).until(ec.alert_is_present())alert: Alert = self.driver.switch_to.alert# 尝试点击alerttry:if action == 'accept':alert.accept()elif action == 'dismiss':alert.dismiss()else:logger.error('alert 处理参数错误请检查')return alert.textexcept Exception as e:logger.error('alert处理异常')raise edef get_text(self, locator: tuple):"""获取元素的文本值:param locator: 元素定位:return:"""try:elem = self.driver.find_element(*locator)value = elem.textreturn valueexcept NoSuchElementException as e:print(f"get未找到元素{e}")raise edef element_dyeing(self, element) -> None:"""将被操作的元素染色:return: None"""self.driver.execute_script("arguments[0].setAttribute('style', 'background: yellow; border: 2px solid red;');",element)def set_error_img(self) -> None:"""截图:return: None"""__time_tag = ReturnTime.get_timestamp()__img_path = self.__img_dir + f"/{__time_tag}.png"try:# 进行截图self.driver.save_screenshot(filename=__img_path)logger.error(f"截图成功文件名称为:{__time_tag}.png")__file = open(__img_path, "rb").read()allure.attach(__file, "用例执行失败截图", allure.attachment_type.PNG)except Exception as e:logger.error(f"执行失败截图未能正确添加进入测试报告:{e}")raise edef set_case_img(self) -> None:"""用例执行完毕截图,并且将截图加入allure测试报告中:return: 无返回值"""with allure.step("关键步骤截图"):__img_name = ReturnTime.get_timestamp()__img_path = self.__img_dir + f"/{__img_name}.png"try:# 截图前等待1秒防止图片没有正常加载time.sleep(1)self.driver.save_screenshot(filename=__img_path)logger.debug(f"用例执行完成,截图成功,文件名称为{__img_name}.png")# 读取图片信息__file = open(file=__img_path, mode="rb").read()allure.attach(__file, "关键步骤截图", allure.attachment_type.PNG)except Exception as e:logger.error(f"测试结果截图,未能正确添加进入测试报告:{e}")raise e# ------------------------ START: JS事件 ------------------------ #def execute_js(self, js, *args):"""执行javascript脚本js: 元组形式参数"""self.driver.execute_script(js, *args)return selfdef upload_file_pywinauto(self, file_path):"""使用pywinauto来上传缺点:只能在windows上使用。优点:可以选择多个文件,路径中有中文也可以。安装:pip install pywinauto -i https://mirrors.aliyun.com/pypi/simple/:param file_path: 文件绝对路径,支持传数组"""if isinstance(file_path, list):for path in file_path:# 上传文件send_keys(path)else:# 上传文件send_keys(file_path)# 点击回车send_keys("{VK_RETURN}")return selfdef upload_file_pyautogui(self, file_path):"""使用pyautogui来上传缺点:只能选择一个文件,路径中有中文会出问题。优点:跨平台。Linux, mac,windows都可以。安装:pip install pyautogui -i https://mirrors.aliyun.com/pypi/simple/:param file_path: 文件绝对路径,支持传数组"""if isinstance(file_path, list):print("只能选择一个文件,默认选择第一个")file_path = file_path[0]# 上传文件pyautogui.write(file_path)# 点击回车pyautogui.press("enter", 2)return self# ------------------------ END: JS事件 ------------------------ ## ------------------------ START: 鼠标事件:双击,悬停,拖动 ------------------------ #def double_click(self, locator):"""鼠标双击:param locator::return:"""try:elem = self.driver.find_element(*locator)action = ActionChains(self.driver)action.double_click(elem).perform()return selfexcept NoSuchElementException as e:print("未找到元素:{}".format(e))raise edef drag_and_drop(self, start_locator, end_locator):"""鼠标拖动"""elem_start = self.driver.find_element(*start_locator)elem_end = self.driver.find_element(*end_locator)action = ActionChains(self.driver)action.double_click((elem_start, elem_end)).perform()return selfdef hover(self, locator):"""鼠标悬停"""el = self.driver.find_element(*locator)action = ActionChains(self.driver)action.move_to_element(el).perform()return self
相关文章:
UI界面自动化BagePage
常用basepage模块代码 # -*- coding: utf-8 -*- # Desc: UI自动化测试的一些基础浏览器操作方法# 第三方库导入 import time from logging import config import randomimport allure from selenium.webdriver.common.alert import Alert from selenium.webdriver.remote.webe…...

北京开发APP的费用明细
开发APP项目时,在功能确定后需要知道有哪些可能的费用,安排项目预算。北京开发APP的费用明细可能会包括以下几个部分,每个部分都会产生一些费用。今天和大家分享APP费用明细有哪些,希望对大家有所帮助。北京木奇移动技术有限公司&…...
2023年MySQL核心技术第一篇
目录 一 . 存储:一个完整的数据存储过程是怎样的? 1.1 数据存储过程 1.1.1 创建MySQl 数据库 1.1.1.1 为什么我们要先创建一个数据库,而不是直接创建数据表? 1.1.1.2基本操作部分 1.2 选择索引问题 二 . 字段:这么多的…...
通讯协议056——全网独有的OPC HDA知识一之接口(十一)IOPCHDA_Playback
本文简单介绍OPC HDA规范的IOPCHDA_Playback(可选)接口方法,更多通信资源请登录网信智汇(wangxinzhihui.com)。 此接口支持历史服务器的播放功能。这提供了从历史服务器获得初始数据集的能力,然后获得历史数据的持续更新。这与异…...

数学建模:数据的预处理
🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 文章目录 数据预处理数据变换数据清洗缺失值处理异常值处理 数据预处理 数据变换 常见的数据变换的方式:通过某些简单的函数进行数据变换。 x ′ x 2 x ′ x x ′ log ( x ) ∇ f ( x k )…...

Linux土遁术之监测监测进程打开文件
分析问题过程中,追踪进程打开的文件可以在许多不同情况下有用,体现在以下几个方面: 故障排除和调试: 当程序出现问题、崩溃或异常行为时,追踪进程打开的文件可以帮助您找出问题的根本原因。这有助于快速定位错误&…...

css让多个盒子强制自动等宽
1.width: calc( 100 / n% ) 2.display:flex; flex:1;width:100px; 3.display:grid;grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); 但是其中某一个内容较长的时候 会破坏1:1:1的平衡 这个时候发现附件名字过长导致不等比例,通过查看阮一峰flex文…...

【高危】Apache Airflow Spark Provider 反序列化漏洞 (CVE-2023-40195)
zhi.oscs1024.com 漏洞类型反序列化发现时间2023-08-29漏洞等级高危MPS编号MPS-qkdx-17bcCVE编号CVE-2023-40195漏洞影响广度广 漏洞危害 OSCS 描述Apache Airflow Spark Provider是Apache Airflow项目的一个插件,用于在Airflow中管理和调度Apache Spar…...

树模型与集成学习:LightGBM
目录 树模型与集成学习 LightGBM 的贡献 LightGBM 的贡献:单边梯度抽样算法 LightGBM 的贡献:直方图算法 LightGBM 的贡献:互斥特征捆绑算法 LightGBM 的贡献:深度限制的 Leaf-wise 算法 树模型与集成学习 树模型是非常好的…...

PHP多语言代入电商平台api接口采集拼多多根据ID获取商品详情原数据示例
拼多多商品详情原数据API接口的作用是获取拼多多电商平台上某一商品的详细信息,包括商品的标题、价格、库存、图片、描述、包邮信息、销量、评价、优惠券等数据。通过该API接口可以获取到商品的原始数据,用于分析、筛选和展示商品信息。 pinduoduo.item…...

数据结构(Java实现)-二叉树(下)
获取二叉树的高度 检测值为value的元素是否存在(前序遍历) 层序遍历 判断一棵树是不是完全二叉树 获取节点的路径 二叉树的最近公共祖先...

如何利用 SmartX 存储性能测试工具 OWL 优化性能管理?
作者:深耕行业的 SmartX 金融团队 张瑞松 运维人员在日常管理集群时,有时难免会产生这样的困惑: 新业务准备上线,在具备多套存储的情况下,应如何选择承载业务的存储环境? 业务虚拟机刚上线时运行速度很快…...

固定资产管理措施怎么写
固定资产管理措施是指企业在进行固定资产管理时所采取的各种措施和方法。以下是一些常见的固定资产管理措施: 建立完善的固定资产管理制度。制定明确的资产采购、使用、维护、报废等流程和标准,确保资产管理的规范性和透明度。 采用先进的资产管理…...
C语言中typedef和const的区别
昨天面试的时候面试官问了这个问题,平时也有见过这两个类型限定词,可能是因为不怎么使用的原因,当问到它们的区别时,我不知道从哪个方面开始回答。 用 typedef 定义新的类型名 类型定义的书写格式为 typedef 类型 被定义的类型名 …...
大数据系列教程之 Kafka基础
kafka概述 一、kafka概述 1.1 定义1.2 消息队列 1.2.1 传统消息队列的应用场景1.2.2 消息队列的两种形式1.3 Kafka 基础架构二、kafka安装部署 2.1安装部署 2.1.1.jar包下载2.1.2.解压到指定的文件夹下2.1.3.创建两个文件夹以供后续使用2.1.4. 修改配置文件 (1&…...

【Go 基础篇】Go语言日期与时间函数详解:时间的掌控与转化
Go语言是一种快速、简洁且高效的编程语言,它在处理日期与时间方面提供了丰富的标准库函数。本文将详细介绍Go语言中处理日期与时间的函数,涵盖常用的日期时间操作、格式化、时区转换等内容,并介绍time.Time结构体中的相关方法。 时间的表示与…...
抽象工厂模式:创建相关对象族
欢迎阅读设计模式系列的第四篇文章!在前面的文章中,我们已经学习了设计模式的基本概念以及工厂方法模式的应用。 今天,我们将继续深入,介绍第三个模式——抽象工厂模式。 抽象工厂模式简介 抽象工厂模式是一种创建型设计模式&a…...
uniapp:安卓permission权限表及setting表
安卓permission权限表 权限名称说明android.permission.WRITE_USER_DICTIONARY允许应用程序向用户词典中写入新词android.permission.WRITE_SYNC_SETTINGS写入 Google 在线同步设置android.permission.WRITE_SOCIAL_STREAM读取用户的社交信息流android.permission.WRITE_SMS允…...

汽车服务门店小程序模板制作指南
在数字化时代,一个小程序的力量不可忽视。它不仅是展示品牌形象和提供用户服务的重要工具,更是扩大客户群体和提高营收的关键手段。对于汽车服务门店来说,拥有一个精美且功能齐全的小程序,更将成为你在竞争激烈的市场中的重要武器…...

Apache SeaTunnel 2.3.3 版本发布,CDC 支持 Schema Evolution!
时隔两个月, Apache SeaTunnel 终于迎来大版本更新。此次发布的 2.3.3 版本在功能和性能上均有较大优化改进,其中大家期待已久的 CDC Schema evolution(DDL 变更同步)、主键 Split 拆分、JDBC Sink 自动建表功能、SeaTunnel Zeta …...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...