web自动化(4)——POM设计重构

news2024/11/28 13:46:05

1. 什么是POM

Page Object Model 是ui自动化测试中常见的封装方式。

原理:将页面封装为PO对象,然后通过面向对象的方式实现UI自动化

2. 封装原则

  1. PO无需包含全部UI元素
  2. PO应当验证元素
  3. PO不应该包含断言
  4. PO不应该暴露元素

3. 怎么进行POM封装

面向对象:属性和方法

封装步骤:

  1. 创建类,代表页面
  2. 创建类的属性,代表页面中的元素
  3. 创建类的方法,代表页面中的交互动作

在项目新建文件user_po.py

from selenium.webdriver import Chrome

from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


# 1.创建类
class IndexPage:
    """首页:登录页面"""

    def __init__(self, driver: Chrome):  # 在进行实例化是被自动调用,可以接收参数
        self.driver = driver

    # 2.类的属性,即页面元素
    btn_login = (By.XPATH, '//*[@id="user_head_tip"]/a[1]')  # 立即登录按钮
    ipt_username = (By.XPATH, '//*[@id="login-email-address"]')  # 账号输入框
    ipt_password = (By.XPATH, '//*[@id="login-password"]')  # 密码输入框
    btn_submit = (By.XPATH, '//*[@id="ajax-login-submit"]')  # 登录按钮
    msg = (By.XPATH, '//*[starts-with(@id,"fanwe_")]/table/tbody/tr/td[2]/div[2]')  # 登录结果

    # 3.类的方法,即交互动作
    def login(self, username, password):
        self.driver.find_element(*self.btn_login).click()  # *表示元组解包
        self.driver.find_element(*self.ipt_username).send_keys(username)
        self.driver.find_element(*self.ipt_password).send_keys(password)
        self.driver.find_element(*self.btn_submit).click()
        # 显示等待:系统提示里不包含忘记密码并且系统系统不为空
        WebDriverWait(self.driver, 10).until(
            lambda x: "忘记密码?" not in self.driver.find_element(*self.msg).text and self.driver.find_element(
                *self.msg).text != ""
        )
        msg = self.driver.find_element(*self.msg).text
        return msg


# 1.一个页面一个类
class DealPage:
    """交易页面:投资"""
    # 2.类的属性,即页面元素
    ipt_money = (By.XPATH, '//*[@id="J_BIDMONEY"]')  # 投资金额
    btn_tz_submit = (By.XPATH, '//*[@id="tz_link"]')  # 立即投资
    ipt_pay_password = (By.XPATH, '//*[@id="J_bid_password"]')  # 支付密码
    btn_pay_submit = (By.XPATH, '//*[@id="J_bindpassword_btn"]')  # 确定
    msg = (By.XPATH, '//*[@id="fanwe_success_box"]/table/tbody/tr/td[2]/div[2]')

    def __init__(self, driver: Chrome):  # 在进行实例化是被自动调用,可以接收参数
        self.driver = driver

    # 3.类的方法,即交互动作
    def pay(self, money, pay_password):
        self.driver.find_element(*self.ipt_money).send_keys(money)
        self.driver.find_element(*self.btn_tz_submit).click()
        self.driver.find_element(*self.ipt_pay_password).send_keys(pay_password)
        self.driver.find_element(*self.btn_pay_submit).click()
        msg = WebDriverWait(self.driver, 10).until(
            lambda x: self.driver.find_element(
                By.XPATH, '//*[@id="fanwe_success_box"]/table/tbody/tr/td[2]/div[2]'
            ).text
        )
        return msg


if __name__ == '__main__':
    driver = Chrome()
    driver.implicitly_wait(10)  # 隐式等待
    driver.get('http://47.107.116.139/fangwei/index.php')
    page = IndexPage(driver)
    msg = page.login('admin', 'msjy123')
    print(msg)
    driver.get('http://47.107.116.139/fangwei/index.php?ctl=deal&id=25370&preview=1')
    page = DealPage(driver)
    msg = page.pay(100, 'msjy123')
    print(msg)
    driver.quit()

4. 引入pytest

  1. 自动判断用例执行结果
  2. 统计用例成功数量
  3. 统一形成测试报告

4.1 安装

pip install pytest

4.2 编写夹具fixture

测试用例所依赖的一些组件应该在夹具中设置就绪:例如启动浏览器,最大化浏览器等。在根目录创建conftest.py文件,在该文件中写夹具

import pytest
from selenium.webdriver import Chrome


# scope用来指定夹具作用域,function指函数,module指模块,如果设置scope=function表示每执行一个函数都会进行浏览器重启和关闭
@pytest.fixture(scope='module')  # 这里设置scope=module是因为如果为函数级别的话,我们在test_user中第1个用例如果关闭了浏览器第二个用例就需要重新登录
def driver():
    driver = Chrome()
    driver.implicitly_wait(5)
    driver.maximize_window()
    yield driver
    driver.quit()

创建test_user.py,代码如下:

from user_po import IndexPage, DealPage


# 在用例中使用夹具:将夹具名称写在参数当中
def test_login(driver):
    driver.get('http://47.107.116.139/fangwei/index.php')
    page = IndexPage(driver)
    msg = page.login('admin', 'msjy123')
    assert msg == '成功登录'


def test_deal(driver):
    driver.get('http://47.107.116.139/fangwei/index.php?ctl=deal&id=25370&preview=1')
    page = DealPage(driver)
    msg = page.pay(100, 'msjy123')
    assert msg == '投标成功!'

在pycharm终端输入pytest即可自动执行test_user.py中的两个测试用例。

4.3 编写测试用例

以登录功能为例,存在以下几种情况,不同的输入会有不同的输出结果,

  • 用户名密码为空:Email格式错误,请重新输入或者昵称格式错误,请重新输入
  • 用户名正确,密码为空:密码格式错误,请重新输入
  • 错误用户名,密码正确:用户不存在
  • 正确用户名,错误密码:密码错误
  • 正确用户名,正确密码:成功登录
  • 首先新建ddt_login.csv,用于存放我们的用例数据,做参数化使用
用户名,密码,登录结果
,,Email格式错误,请重新输入或者昵称格式错误,请重新输入
admin,,密码格式错误,请重新输入
asasasddd,msjy123,用户不存在
admin,msjy123456,密码错误
admin,msjy123,成功登录

接下来将我们的test_user.py代码修改一下,因为输入不再是固定的,所以使用参数传入:

import csv

import pytest

from user_po import IndexPage, DealPage


# 读取csv文件数据作为参数化数据,使用装饰器进行参数化
@pytest.mark.parametrize("data", csv.DictReader(open("ddt_login.csv", encoding="utf-8-sig")))
# 在用例中使用夹具:将夹具名称写在参数当中
def test_login(driver, data):
    driver.get('http://47.107.116.139/fangwei/index.php')
    page = IndexPage(driver)
    msg = page.login(data["用户名"], data["密码"])
    assert msg == data["登录结果"]


def test_deal(driver):
    driver.get('http://47.107.116.139/fangwei/index.php?ctl=deal&id=25370&preview=1')
    page = DealPage(driver)
    msg = page.pay(100, 'msjy123')
    assert msg == '投标成功!'

5. po封装管理后台

要封装后台管理的po,如果新建po文件,如果每个po都新建一个文件会导致文件过多,因此我们需要将原来的user_po.py文件名修改为pages.py,然后在里面添加类就可以了。然后添加类的时候我们可以发现每个类都有一个init方法,造成了代码重复,因此我们使用BasePage抽象类,它表示所有页面共用的代码,我们将init方法写在BasePage类中,后续使用时只需要继承即可。修改后代码如下:

from selenium.webdriver import Chrome

from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


# 抽象类,所有页面的公共代码,需要使用时继承即可
class BasePage:
    def __init__(self, driver: Chrome):  # 在进行实例化是被自动调用,可以接收参数
        self.driver = driver


# 1.创建类
class IndexPage(BasePage):
    """首页:登录页面"""

    # 2.类的属性,即页面元素
    btn_login = (By.XPATH, '//*[@id="user_head_tip"]/a[1]')  # 立即登录按钮
    ipt_username = (By.XPATH, '//*[@id="login-email-address"]')  # 账号输入框
    ipt_password = (By.XPATH, '//*[@id="login-password"]')  # 密码输入框
    btn_submit = (By.XPATH, '//*[@id="ajax-login-submit"]')  # 登录按钮
    msg = (By.XPATH, '//*[starts-with(@id,"fanwe_")]/table/tbody/tr/td[2]/div[2]')  # 登录结果

    # 3.类的方法,即交互动作
    def login(self, username, password):
        self.driver.find_element(*self.btn_login).click()  # *表示元组解包
        self.driver.find_element(*self.ipt_username).send_keys(username)
        self.driver.find_element(*self.ipt_password).send_keys(password)
        self.driver.find_element(*self.btn_submit).click()
        # 显示等待:系统提示里不包含忘记密码并且系统系统不为空
        WebDriverWait(self.driver, 10).until(
            lambda x: "忘记密码?" not in self.driver.find_element(*self.msg).text and self.driver.find_element(
                *self.msg).text != ""
        )
        msg = self.driver.find_element(*self.msg).text
        return msg


# 1.一个页面一个类
class DealPage(BasePage):
    """交易页面:投资"""
    # 2.类的属性,即页面元素
    ipt_money = (By.XPATH, '//*[@id="J_BIDMONEY"]')  # 投资金额
    btn_tz_submit = (By.XPATH, '//*[@id="tz_link"]')  # 立即投资
    ipt_pay_password = (By.XPATH, '//*[@id="J_bid_password"]')  # 支付密码
    btn_pay_submit = (By.XPATH, '//*[@id="J_bindpassword_btn"]')  # 确定
    msg = (By.XPATH, '//*[@id="fanwe_success_box"]/table/tbody/tr/td[2]/div[2]')

    # 3.类的方法,即交互动作
    def pay(self, money, pay_password):
        self.driver.find_element(*self.ipt_money).send_keys(money)
        self.driver.find_element(*self.btn_tz_submit).click()
        self.driver.find_element(*self.ipt_pay_password).send_keys(pay_password)
        self.driver.find_element(*self.btn_pay_submit).click()
        msg = WebDriverWait(self.driver, 10).until(
            lambda x: self.driver.find_element(
                By.XPATH, '//*[@id="fanwe_success_box"]/table/tbody/tr/td[2]/div[2]'
            ).text
        )
        return msg


然后我们将之前写的admin.py中管理后台的代码进行po封装,同样是创建类,属性和方法,写入pages.py,如下:

import time

from selenium.webdriver import Chrome

from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait

from funcs import img1code, is_login


# 抽象类,所有页面的公共代码,需要使用时继承即可
class BasePage:
    def __init__(self, driver: Chrome):  # 在进行实例化是被自动调用,可以接收参数
        self.driver = driver


# 1.创建类
class IndexPage(BasePage):
    """首页:登录页面"""

    # 2.类的属性,即页面元素
    btn_login = (By.XPATH, '//*[@id="user_head_tip"]/a[1]')  # 立即登录按钮
    ipt_username = (By.XPATH, '//*[@id="login-email-address"]')  # 账号输入框
    ipt_password = (By.XPATH, '//*[@id="login-password"]')  # 密码输入框
    btn_submit = (By.XPATH, '//*[@id="ajax-login-submit"]')  # 登录按钮
    msg = (By.XPATH, '//*[starts-with(@id,"fanwe_")]/table/tbody/tr/td[2]/div[2]')  # 登录结果

    # 3.类的方法,即交互动作
    def login(self, username, password):
        self.driver.find_element(*self.btn_login).click()  # *表示元组解包
        self.driver.find_element(*self.ipt_username).send_keys(username)
        self.driver.find_element(*self.ipt_password).send_keys(password)
        self.driver.find_element(*self.btn_submit).click()
        # 显示等待:系统提示里不包含忘记密码并且系统系统不为空
        WebDriverWait(self.driver, 10).until(
            lambda x: "忘记密码?" not in self.driver.find_element(*self.msg).text and self.driver.find_element(
                *self.msg).text != ""
        )
        msg = self.driver.find_element(*self.msg).text
        return msg


# 1.一个页面一个类
class DealPage(BasePage):
    """交易页面:投资"""
    # 2.类的属性,即页面元素
    ipt_money = (By.XPATH, '//*[@id="J_BIDMONEY"]')  # 投资金额
    btn_tz_submit = (By.XPATH, '//*[@id="tz_link"]')  # 立即投资
    ipt_pay_password = (By.XPATH, '//*[@id="J_bid_password"]')  # 支付密码
    btn_pay_submit = (By.XPATH, '//*[@id="J_bindpassword_btn"]')  # 确定
    msg = (By.XPATH, '//*[@id="fanwe_success_box"]/table/tbody/tr/td[2]/div[2]')

    # 3.类的方法,即交互动作
    def pay(self, money, pay_password):
        self.driver.find_element(*self.ipt_money).send_keys(money)
        self.driver.find_element(*self.btn_tz_submit).click()
        self.driver.find_element(*self.ipt_pay_password).send_keys(pay_password)
        self.driver.find_element(*self.btn_pay_submit).click()
        msg = WebDriverWait(self.driver, 10).until(
            lambda x: self.driver.find_element(
                By.XPATH, '//*[@id="fanwe_success_box"]/table/tbody/tr/td[2]/div[2]'
            ).text
        )
        return msg


class AdminLoginPage(BasePage):
    """后台管理登录页面"""
    ipt_username = (By.XPATH, '/html/body/form/table/tbody/tr/td[3]/table/tbody/tr[2]/td[2]/input')
    ipt_password = (By.XPATH, '/html/body/form/table/tbody/tr/td[3]/table/tbody/tr[3]/td[2]/input')
    ipt_verify = (By.XPATH, '/html/body/form/table/tbody/tr/td[3]/table/tbody/tr[5]/td[2]/input')
    img_verify = (By.XPATH, '//*[@id="verify"]')
    btn_submit = (By.XPATH, '//*[@id="login_btn"]')

    def login(self, username, password):
        self.driver.find_element(*self.img_verify).screenshot("../temp/code.png")
        code = img1code("../temp/code.png")
        self.driver.find_element(*self.ipt_username).send_keys(username)
        self.driver.find_element(*self.ipt_password).send_keys(password)
        self.driver.find_element(*self.ipt_verify).send_keys(code)
        self.driver.find_element(*self.btn_submit).click()
        time.sleep(1)
        return is_login(self.driver)  # 使用is_login函数返回值作为交互返回值


class AdminIndexPage(BasePage):
    """后台管理首页"""
    ifm_top = (By.XPATH, '/html/frameset/frame[1]')
    ifm_left = (By.XPATH, '//*[@id="menu-frame"]')
    ifm_main = (By.XPATH, '//*[@id="main-frame"]')

    def to_deal(self):
        self.driver.refresh()
        # 进入框架
        iframe = self.driver.find_element(*self.ifm_top)
        self.driver.switch_to.frame(iframe)
        self.driver.find_element(By.LINK_TEXT, '贷款管理').click()  # 点击贷款管理
        self.driver.switch_to.default_content()  # 退出框架

        iframe = self.driver.find_element(*self.ifm_left)
        self.driver.switch_to.frame(iframe)
        self.driver.find_element(By.LINK_TEXT, '全部贷款').click()  # 点击全部贷款
        self.driver.switch_to.default_content()  # 退出框架

        iframe = self.driver.find_element(*self.ifm_main)
        self.driver.switch_to.frame(iframe)

        return AdminDealPage(self.driver)


class AdminDealPage(BasePage):
    """贷款管理页面"""
    btn_new_deal = (By.XPATH, '/html/body/div[2]/div[3]/input[1]')  # 新增贷款按钮
    tr_deal = (By.XPATH, '//tr[contains(@class,"row")]')  # 列表所有

    def new_deal(self):
        self.driver.find_element(*self.btn_new_deal).click()
        return AdminNewDealPage(self.driver)  # 返回po表示已经进入新增贷款页面


class AdminNewDealPage(BasePage):
    """新增贷款页面"""
    ipt_name = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[4]/td[2]/input')  # 贷款名称
    ipt_shor_name = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[5]/td[2]/input')  # 简短名称
    ipt_username = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[6]/td[2]/input[1]')  # 会员名称
    btn_username = (By.XPATH, '//strong[text()="beifan"]')
    btn_city = (By.XPATH, '//*[@id="citys_box"]/div[1]/div[2]/input[1]')  # 所在城市
    sel_cate = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[8]/td[2]/select')  # 分类-房产抵押
    btn_show_upload = (By.XPATH,
                       '/html/body/div[2]/form/table[1]/tbody/tr[14]/td[2]/span/div[1]/div/div/button')  # 图片上传按钮
    btn_show_local_upload = (By.XPATH, '/html/body/div[6]/div[1]/div[2]/div/div[1]/ul/li[2]')  # 本地上传按钮
    ipt_upload = (By.XPATH, '//input[@type="file"]')  # 发送文件
    btn_submit_upload = (By.XPATH, '/html/body/div[6]/div[1]/div[3]/span[1]/input')  # 确定上传按钮
    sel_type = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[15]/td[2]/select')  # 借款用途
    sel_contract = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[17]/td[2]/select')  # 借款合同范本
    sel_tcontract = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[18]/td[2]/select')  # 转让合同范本
    ipt_amount = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[19]/td[2]/input')  # 借款金额
    ipt_rate = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[27]/td[2]/input')  # 年利率
    ipt_enddate = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[28]/td[2]/input')  # 筹标期限
    btn_status = (By.XPATH, '/html/body/div[2]/form/table[1]/tbody/tr[33]/td[2]/label[1]/input')  # 借款状态
    ipt_start_time = (By.XPATH, '//*[@id="start_time"]')  # 开始时间
    btn_submit = (By.XPATH, '/html/body/div[2]/form/table[6]/tbody/tr[2]/td[2]/input[4]')  # 新增提交按钮
    msg=(By.XPATH, '/html/body/div/table/tbody/tr[3]/td')

    def submit(self, data):  # data是包含了多个参数的字典
        """提交新的贷款"""
        # 贷款名称
        self.driver.find_element(*self.ipt_name).send_keys(data['name'])
        # 简短名称
        self.driver.find_element(*self.ipt_shor_name).send_keys(data['shor_name'])
        # 会员名称
        self.driver.find_element(*self.ipt_username).send_keys(data['username'])
        self.driver.find_element(*self.btn_username).click()
        # 城市
        self.driver.find_element(*self.btn_city).click()
        # 分类-房产抵押
        el = self.driver.find_element(*self.sel_cate)
        Select(el).select_by_visible_text(data['cate'])
        # 图片上传
        self.driver.find_element(*self.btn_show_upload).click()
        self.driver.find_element(*self.btn_show_local_upload).click()
        self.driver.find_element(*self.ipt_upload).send_keys(data['upload'])
        self.driver.find_element(*self.btn_submit_upload).click()
        # 借款用途
        el = self.driver.find_element(*self.sel_type)
        Select(el).select_by_visible_text(data['type'])
        # 借款合同范本
        el = self.driver.find_element(*self.sel_contract)
        Select(el).select_by_visible_text(data['contract'])
        # 转让合同
        el = self.driver.find_element(*self.sel_tcontract)
        Select(el).select_by_visible_text(data['tcontract'])
        # 借款金额
        el = self.driver.find_element(*self.ipt_amount)
        el.clear()
        el.send_keys(data['amount'])
        # 年利率
        el = self.driver.find_element(*self.ipt_rate)
        el.clear()
        el.send_keys(data['rate'])
        # 筹标期限
        el = self.driver.find_element(*self.ipt_enddate)
        el.clear()
        el.send_keys(data['enddate'])
        # 借款状态
        self.driver.find_element(*self.btn_status).click()
        # 开始时间
        el = self.driver.find_element(*self.ipt_start_time)
        self.driver.execute_script("arguments[0].scrollIntoView()", el)
        self.driver.execute_script(f"arguments[0].value='{data['start_time']}'", el)
        # 新增提交
        self.driver.find_element(*self.btn_submit).click()
        # 系统提示
        el = self.driver.find_element(*self.msg)
        return el.text

完成后我们创建test_admin.py文件,去编写测试用例,我们在编写新增贷款流程的测试用例的时候,首先需要登录,我们可以在conftest.py中新建一个fixture夹具,如下:

import pytest
from selenium.webdriver import Chrome

from funcs import save_cookies, load_cookies,is_login
from pages import AdminLoginPage


# scope用来指定夹具作用域,function指函数,module指模块,如果设置scope=function表示每执行一个函数都会进行浏览器重启和关闭
@pytest.fixture(scope='module')  # 这里设置scope=module是因为如果为函数级别的话,我们在test_user中第1个用例如果关闭了浏览器第二个用例就需要重新登录
def driver():
    driver = Chrome()
    driver.implicitly_wait(5)
    driver.maximize_window()
    yield driver
    driver.quit()


@pytest.fixture(scope='session')
def admin_driver():
    """已经登陆的浏览器,给test_admin使用"""
    driver = Chrome()
    driver.implicitly_wait(5)
    driver.maximize_window()
    load_cookies(driver)
    # 判断:只有未登录才进行登录流程
    if is_login(driver) is False:
        page = AdminLoginPage(driver)  # 实例化
        assert page.login('admin', 'msjy123') is True

    yield driver

    save_cookies(driver)
    driver.quit()

这样我们在test_admin.py中就可以使用admin_driver

from pages import *


def test_new_deal(admin_driver):
    """已经登录成功状态"""
    page = AdminIndexPage(admin_driver)
    page = page.to_deal()  # 跳转到贷款管理
    page = page.new_deal()  # 跳转到新增贷款
    # data表示输入的数据
    data = {
        'name': '借款1亿买别墅',
        'shor_name': '买别墅',
        'username': 'beifan',
        'cate': '|--房产抵押标',
        'upload': r'D:\pythonProject2\code.png',
        'type': '个人消费',
        'contract': '等额本息合同范本【担保】',
        'tcontract': '付息还本合同范本【普通】',
        'amount': '100000000',
        'rate': '5',
        'enddate': '30',
        'start_time': '2023-12-25 18:02:02'
    }
    msg = page.submit(data)
    assert msg == '添加成功'

也可以在test_admin.py中继续添加测试用例,测试不同的输入数据和结果。这里不再举例。最后在终端运行可以看到测试通过,也可以创建main.py进行运行

import pytest

if __name__ == '__main__':
    pytest.main()

写到这里POM封装就基本完成了,整理下项目目录,如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1341432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

<JavaEE> TCP 的通信机制(五) -- 延时应答、捎带应答、面向字节流

目录 TCP的通信机制的核心特性 七、延时应答 1)什么是延时应答? 2)延时应答的作用 八、捎带应答 1)什么是捎带应答? 2)捎带应答的作用 九、面向字节流 1)沾包问题 2)“沾包…

用ChatGPT挑选钻石!著名珠宝商推出-珠宝GPT

根据Salesforce最新发布的第五版《互联网购物报告》显示,ChatGPT等生成式AI的出现、快速发展,对零售行业和购物者产生了较大影响。可有效简化业务流程实现降本增效,并改善购物体验。 著名珠宝商James Allen为了积极拥抱生成式AI全面提升销售…

Redis 是如何执行的?

文章目录 命令执行流程步骤一:用户输入一条命令步骤二:客户端先将命令转换成 Redis 协议,然后再通过 socket 连接发送给服务器端步骤三:服务器端接收到命令步骤四:执行前准备步骤五:执行最终命令&#xff0…

HTML5+CSS3+JS小实例:网站实现一键切换暗色主题

实例:网站实现一键切换暗色主题 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge&…

V-rep(CoppeliaSim)添加相机,与python联合仿真,并使用python读取V-rep中的RGB图与深度图

目录 前言在V-rep中构建场景建立python与V-rep通信 前言 本文主要介绍了如何使用python与V-rep联合仿真&#xff0c;并用OpenCV可视化V-rep中视觉传感器所能看到的 RGB图和深度图&#xff0c;效果图如下。 在V-rep中构建场景 本文使用的V-rep版本是3.5&#xff1a; 打开V-…

深度学习在语义分割中的进展与应用

埃弗顿戈梅德&#xff08;Everton Gomede&#xff09; 一、说明 语义分割是计算机视觉领域的一项关键任务&#xff0c;涉及将图像中的每个像素分类为预定义的类。这项任务在从自动驾驶汽车到医学成像的各种应用中都具有深远的影响。深度学习的出现显著提高了语义分割模型的功能…

小型企业成为网络犯罪分子获取数据的目标

在过去十年的大部分时间里&#xff0c;网络犯罪的巨额资金来自针对大型组织的勒索软件攻击。这种威胁仍然存在。但犯罪分子可能会将注意力转向中小企业 (SMB)。这对消费者的影响将是巨大的。 将软件即服务 (SaaS) 技术用于核心业务功能继续将中小企业整合到全球供应链中。由于…

kubeSphere集群部署nacos

kubeSphere部署nacos 个人环境说明执行nacos数据脚本kubeSphere添加配置创建有状态副本集修改集群配置文件 创建外部访问服务访问 个人环境说明 由于我之前这个项目就是dockerjenkins部署的,只是现在升级到k8skubeSphere所有下面有些操作我可能不同,例如我的nacos配置文件就是d…

论文阅读:Blind Super-Resolution Kernel Estimation using an Internal-GAN

这是发表在 2019 年 NIPS 上的一篇文章&#xff0c;那个时候还叫 NIPS&#xff0c;现在已经改名为 NeurIPS 了。文章中的其中一个作者 Michal Irani 是以色 Weizmann Institute of Science (魏茨曼科学研究学院) 的一名教授&#xff0c;对图像纹理的内在统计规律有着很深入的研…

UG NX二次开发(C#)-Ufun和NXOpen混合编程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、Ufun函数3、 NXOpen4、混合编程实现1、前言 在UG NX二次开发过程中,采用Ufun功能比较简单,能用比较少的代码实现我们需要的功能,但是ufun函数的功能不是很强大,尤其随着UG NX的版本…

中央集成式架构量产时代,openVOC方案将引发软件开发模式变革

2024年&#xff0c;中央计算区域控制架构正式进入规模化量产周期&#xff0c;汽车智能化正式迈入2.0时代&#xff0c;产业生态、应用创新、开发模式都将迎来巨大变革。 同时&#xff0c;随着ChatGPT引发的AIGC领域的爆发式增长&#xff0c;人工智能技术掀起全球万亿级信息化应…

开箱即用的企业级数据和业务管理中后台前端框架Ant Design Pro 5的开箱使用和偏好配置

Ant Design Pro 介绍 Ant Design Pro 是一个开箱即用的企业级前端解决方案&#xff0c;基于 Ant Design 设计体系&#xff0c;提供了丰富的组件和功能&#xff0c;帮助开发者更快速地开发和部署企业级应用。 Ant Design Pro 使用 React、umi 和 dva 这三个主要的前端开发技术…

天翼云云间高速实现租户跨地域内网互通

一、业务需求 用户业务在襄阳、武汉两个云池部署&#xff0c;希望通过云间高速产品将两个资源池云内资源通过云内专网实现内网互通。要求内网双向互通。 二、测试环境配置 云池vpc名称vpc网段子网内网ip/gweip主机名互联网带宽襄阳ceshi192.168.0.0/16192.168.1.0/24192.168.…

基于element ui封装table组件

效果图&#xff1a; 1.封装表格代码如下 <template> <div><div class"TableList"><el-tablev-loading"loading"selection-change"selectionChange"class"table":data"tableData":border"hasBorde…

阿里云数据库PolarDB费用价格_MySQL版_PolarDB_分布式版

阿里云数据库PolarDB租用价格表&#xff0c;云数据库PolarDB MySQL版2核4GB&#xff08;通用&#xff09;、2个节点、60 GB存储空间55元5天&#xff0c;云数据库 PolarDB 分布式版标准版2核16G&#xff08;通用&#xff09;57.6元3天&#xff0c;阿里云百科aliyunbaike.com分享…

OpenCV-Python(21):OpenCV中的轮廓性质

3.轮廓的性质 本文我们将主要学习基于轮廓来提取一些经常使用的对象特征。 3.1 长宽比 边界矩形的宽高比&#xff1a; x,y,w,h cv2.boundingRect(cnt) aspect_ratio float(w)/h 3.2 Extent 轮廓面积与边界矩形面积的比。 area cv2.contourArea(cnt) x,y,w,h cv2.bounding…

EXPLORING DIFFUSION MODELS FOR UNSUPERVISED VIDEO ANOMALY DETECTION 论文阅读

EXPLORING DIFFUSION MODELS FOR UNSUPERVISED VIDEO ANOMALY DETECTION 论文阅读 ABSTRACT1. INTRODUCTION2. RELATEDWORK3. METHOD4. EXPERIMENTAL ANALYSIS AND RESULTS4.1. Comparisons with State-Of-The-Art (SOTA)4.2. Diffusion Model Analysis4.3. Qualitative Result…

Apache Commons JCS缓存解决方案

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff01;今天&#xff0c;咱们来聊聊Apache Commons JCS&#xff0c;一个Java界里的缓存大杀器。缓存技术&#xff0c;对于提高应用性能来说&#xff0c;就像是给它加了一剂兴奋剂&#xff0c;能让数据访问变得快如闪电。…

Idea如何从磁盘中应用 下载好的插件流程,安装zip压缩包。

1、将下载的插件文件&#xff08;通常是一个ZIP文件&#xff09;复制到IntelliJ IDEA的“plugins”文件夹中。 IDEA版本 2、重启IntelliJ IDEA。 3、在设置窗口中&#xff0c;选择左侧的“Plugins”。 4、选择之前复制到“plugins”文件夹中的插件文件&#xff0c;点击“OK”按…

Android---Kotlin 学习013

互操作性和可空性 Java 世界里所有对象都可能是 null&#xff0c;而 kotlin 里面不能随便给一个变量赋空值的。所有&#xff0c;kotlin 取调用 java 的代码就很容易出现返回一个 null&#xff0c;而 Kotlin 的接收对象不能为空&#xff0c;你不能想当然地认为 java 的返回值就…