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

Python+Selenium+Pytest+POM自动化测试框架封装详解

1、测试框架简介

1)测试框架的优点

  • 代码复用率高,如果不使用框架的话,代码会显得很冗余。
  • 可以组装日志、报告、邮件等一些高级功能。
  • 提高元素等数据的可维护性,元素发生变化时,只需要更新一下配置文件。
  • 使用更灵活的PageObject设计模式。

2)测试框架的整体目录

【注意】 init.py 文件用以标识此目录为一个python包。

2、首先时间管理

首先,因为很多的模块都会用到当前时间的时间戳,或者日期等等字符串,所以先单独把时间操作(我们需要获取的不同格式的时间信息)封装成一个模块。

然后让其他模块来调用即可。在 utils 目录新建 times.py 模块。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import time
import datetime
from functools import wrapsdef timestamp():"""时间戳"""return time.time()def dt_strftime(fmt="%Y%m"):"""datetime格式化时间:param fmt "%Y%m%d %H%M%S"""return datetime.datetime.now().strftime(fmt)def sleep(seconds=1.0):"""睡眠时间"""time.sleep(seconds)def running_time(func):"""函数运行时间"""@wraps(func)def wrapper(*args, **kwargs):start = timestamp()res = func(*args, **kwargs)print("校验元素done!用时%.3f秒!" % (timestamp() - start))return resreturn wrapperif __name__ == '__main__':print(dt_strftime("%Y%m%d%H%M%S"))

3、添加配置文件

1)conf.py

UI自动化测试框架中应该有一个文件对整体的目录进行管理;

在项目中的 config 目录创建 conf.py 文件,所有的目录配置信息写在这个文件里面。

import os
from selenium.webdriver.common.by import By
from utils.times import dt_strftimeclass ConfigManager(object):# 项目目录BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 页面元素目录ELEMENT_PATH = os.path.join(BASE_DIR, 'page_element')# 报告文件REPORT_FILE = os.path.join(BASE_DIR, 'report.html')# 元素定位的类型LOCATE_MODE = {'css': By.CSS_SELECTOR,'xpath': By.XPATH,'name': By.NAME,'id': By.ID,'class': By.CLASS_NAME}# 邮件信息EMAIL_INFO = {'username': 'xxxxxxx@qq.com',  # 切换成你自己的地址'password': 'QQ邮箱授权码','smtp_host': 'smtp.qq.com','smtp_port': 465}# 收件人ADDRESSEE = ['xxxxxxxx@qq.com',]@propertydef log_file(self):"""日志目录"""log_dir = os.path.join(self.BASE_DIR, 'logs')if not os.path.exists(log_dir):os.makedirs(log_dir)return os.path.join(log_dir, '{}.log'.format(dt_strftime()))@propertydef ini_file(self):"""配置文件"""ini_file = os.path.join(self.BASE_DIR, 'config', 'config.ini')if not os.path.exists(ini_file):raise FileNotFoundError("配置文件%s不存在!" % ini_file)return ini_filecm = ConfigManager()
if __name__ == '__main__':print(cm.BASE_DIR)

【注意】:QQ邮箱授权码:点击查看生成教程

2)config.ini

在项目 config 目录新建一个 config.ini 文件,里面暂时先放入需要测试的URL。

[HOST]
HOST = https://www.baidu.com

3)读取配置文件

①配置文件创建好了,接下来我们需要读取这个配置文件以使用里面的信息。
②使用python内置的 configparser 模块对 config.ini 文件信息进行了读取。
③对于测试url值的提取,使用python高阶语法 @property 属性值,写法更简单。
④在 common 目录中新建一个 readconfig.py 文件。

import configparser
from config.conf import cmHOST = 'HOST'class ReadConfig(object):"""配置文件"""def __init__(self):self.config = configparser.RawConfigParser()  # 当有%的符号时请使用Raw读取self.config.read(cm.ini_file, encoding='utf-8')def _get(self, section, option):"""获取"""return self.config.get(section, option)def _set(self, section, option, value):"""更新"""self.config.set(section, option, value)with open(cm.ini_file, 'w') as f:self.config.write(f)@propertydef url(self):return self._get(HOST, HOST)ini = ReadConfig()if __name__ == '__main__':print(ini.url)

4、记录操作日志

在 utils 目录中新建 logger.py 文件。

import logging
from config.conf import cmclass Log:def __init__(self):self.logger = logging.getLogger()if not self.logger.handlers:self.logger.setLevel(logging.DEBUG)# 创建一个handle写入文件fh = logging.FileHandler(cm.log_file, encoding='utf-8')fh.setLevel(logging.INFO)# 创建一个handle输出到控制台ch = logging.StreamHandler()ch.setLevel(logging.INFO)# 定义输出的格式formatter = logging.Formatter(self.fmt)fh.setFormatter(formatter)ch.setFormatter(formatter)# 添加到handleself.logger.addHandler(fh)self.logger.addHandler(ch)@propertydef fmt(self):return '%(levelname)s\t%(asctime)s\t[%(filename)s:%(lineno)d]\t%(message)s'log = Log().loggerif __name__ == '__main__':log.info('hello world')

5、项目中元素相关

POM模型:PO模式详解

元素定位:①selenium UI自动化测试xpath定位详解 ;②selenium UI自动化测试之CSS元素定位语法详解

6、管理页面元素

1)新建page_element目录并在该目录下新建search.yaml文件

①本教程选择的测试地址是百度首页,所以对应的元素也是百度首页的。
②项目框架设计中有一个page_element 目录就是专门来存放定位元素的文件的。
③通过对各种配置文件的对比,我在这里选择的是YAML文件格式。其易读,交互性好。
④在 page_element 中新建一个 search.yaml 文件。文件内容如下:

搜索框:"id==kw"
候选:"css==.bdsug-overflow"
搜索候选:"css==#form div li"
搜索按钮:"id==su"

2)在common目录中创建readelement.py文件。

①在 common 目录中创建 readelement.py 文件。实现了定位元素的存储和调用。文件内容如下:

②通过特殊方法 getitem 实现调用任意属性,读取yaml中的值。参考博客:python之__getitem__ 方法学习与使用 || python方法下划线命名规则

import os
import yaml
from config.conf import cmclass Element(object):"""获取元素"""def __init__(self, name):self.file_name = '%s.yaml' % nameself.element_path = os.path.join(cm.ELEMENT_PATH, self.file_name)if not os.path.exists(self.element_path):raise FileNotFoundError("%s 文件不存在!" % self.element_path)with open(self.element_path, encoding='utf-8') as f:self.data = yaml.safe_load(f)def __getitem__(self, item):"""获取属性"""data = self.data.get(item)if data:name, value = data.split('==')return name, valueraise ArithmeticError("{}中不存在关键字:{}".format(self.file_name, item))if __name__ == '__main__':search = Element('search')print(search['搜索框'])

3)新建script脚本文件目录并新建inspect.py文件

在 script 脚本文件目录中创建 inspect.py 文件,对所有的元素yaml文件内容进行审查。

import os
import yaml
from config.conf import cm
from utils.times import running_time@running_time
def inspect_element():"""检查所有的元素是否正确只能做一个简单的检查"""for files in os.listdir(cm.ELEMENT_PATH):_path = os.path.join(cm.ELEMENT_PATH, files)with open(_path, encoding='utf-8') as f:data = yaml.safe_load(f)for k in data.values():try:pattern, value = k.split('==')except ValueError:raise Exception("元素表达式中没有`==`")if pattern not in cm.LOCATE_MODE:raise Exception('%s中元素【%s】没有指定类型' % (_path, k))elif pattern == 'xpath':assert '//' in value,\'%s中元素【%s】xpath类型与值不配' % (_path, k)elif pattern == 'css':assert '//' not in value, \'%s中元素【%s]css类型与值不配' % (_path, k)else:assert value, '%s中元素【%s】类型与值不匹配' % (_path, k)if __name__ == '__main__':inspect_element()

7、封装Selenium基类

①工厂模式的写法:很直白,简单,又明了。

【创建driver对象,打开百度网页,搜索selenium,点击搜索,然后停留5秒,查看结果,最后关闭浏览器。】

import time
from selenium import webdriverdriver = webdriver.Chrome()
driver.get('https://www.baidu.com')
driver.find_element_by_xpath("//input[@id='kw']").send_keys('selenium')
driver.find_element_by_xpath("//input[@id='su']").click()
time.sleep(5)
driver.quit()

②那为什么要封装selenium的方法呢?

首先我们上述这种较为原始的方法,基本不适用于平时做UI自动化测试的:因为在UI界面实际运行情况远远比较复杂,可能因为网络原因,或者控件原因,我们元素还没有显示出来,就进行点击或者输入。

所以我们需要封装selenium方法,通过内置的显式等待或一定的条件语句,才能构建一个稳定的方法。而且把selenium方法封装起来,有利于平时的代码维护。

新建page目录并创建webpage.py文件

①在 page 目录创建 webpage.py 文件。文件内容如下:

②在文件中我们对主要用了显示等待对selenium的 click , send_keys 等方法,做了二次封装。提高了运行的成功率。

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutExceptionfrom config.conf import cm
from utils.times import sleep
from utils.logger import log"""
selenium基类
本文件存放了selenium基类的封装方法
"""class WebPage(object):"""selenium基类"""def __init__(self, driver):# self.driver = webdriver.Chrome()self.driver = driverself.timeout = 20self.wait = WebDriverWait(self.driver, self.timeout)def get_url(self, url):"""打开网址并验证"""self.driver.maximize_window()self.driver.set_page_load_timeout(60)try:self.driver.get(url)self.driver.implicitly_wait(10)log.info("打开网页:%s" % url)except TimeoutException:raise TimeoutException("打开%s超时请检查网络或网址服务器" % url)@staticmethoddef element_locator(func, locator):"""元素定位器"""name, value = locatorreturn func(cm.LOCATE_MODE[name], value)def find_element(self, locator):"""寻找单个元素"""return WebPage.element_locator(lambda *args: self.wait.until(EC.presence_of_element_located(args)), locator)def find_elements(self, locator):"""查找多个相同的元素"""return WebPage.element_locator(lambda *args: self.wait.until(EC.presence_of_all_elements_located(args)), locator)def elements_num(self, locator):"""获取相同元素的个数"""number = len(self.find_elements(locator))log.info("相同元素:{}".format((locator, number)))return numberdef input_text(self, locator, txt):"""输入(输入前先清空)"""sleep(0.5)ele = self.find_element(locator)ele.clear()ele.send_keys(txt)log.info("输入文本:{}".format(txt))def is_click(self, locator):"""点击"""self.find_element(locator).click()sleep()log.info("点击元素:{}".format(locator))def element_text(self, locator):"""获取当前的text"""_text = self.find_element(locator).textlog.info("获取文本:{}".format(_text))return _text@propertydef get_source(self):"""获取页面源代码"""return self.driver.page_sourcedef refresh(self):"""刷新页面F5"""self.driver.refresh()self.driver.implicitly_wait(30)

8、创建页面对象

新建page_object目录并创建一个searchpage.py文件

①在 page_object 目录下创建一个 searchpage.py 文件。

②在该文件中我们对,输入搜索关键词,点击搜索,搜索联想,进行了封装。【在平时中我们应该养成写注释的习惯,因为过一段时间后,没有注释,代码读起来很费劲。】

9、应用pytest测试框架

pytest.ini文件创建

①pytest项目中的配置文件,可以对pytest执行过程中操作做全局控制。
②在项目根目录新建 pytest.ini 文件。文件内容如下:

[pytest]
addopts = --html=report.html --self-contained-html

③addopts 指定执行时的其他参数说明:

  • –html=report/report.html --self-contained-html 生成pytest-html带样式的报告
  • -s 输出我们用例中的调式信息
  • -q 安静的进行测试
  • -v 可以输出用例更加详细的执行信息,比如用例所在的文件及用例名称等

10、编写测试用例

新建TestCase目录并创建test_search.py文件

①在 TestCase 目录中创建 test_search.py 文件。文件内容如下:
② pytest.fixture装饰器实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器。

③第一个测试用例:实现了在百度搜索selenium关键字,并点击搜索按钮,并在搜索结果中,用正则查找结果页源代码,返回数量大于10我们就认为通过。

④第二个测试用例:实现了百度搜索selenium关键字,然后断言搜索候选中的所有结果有没有selenium关键字。

import re
import pytest
from utils.logger import log
from common.readconfig import ini
from page_object.searchpage import SearchPageclass TestSearch:@pytest.fixture(scope='function', autouse=True)def open_baidu(self, drivers):"""打开百度"""search = SearchPage(drivers)search.get_url(ini.url)def test_001(self, drivers):"""搜索"""search = SearchPage(drivers)search.input_search("selenium")search.click_search()result = re.search(r'selenium', search.get_source)log.info(result)assert resultdef test_002(self, drivers):"""测试搜索候选"""search = SearchPage(drivers)search.input_search("selenium")log.info(list(search.imagine))assert all(["selenium" in i for i in search.imagine])if __name__ == '__main__':pytest.main(['TestCase/test_search.py'])

conftest.py

①在项目根目录下新建一个 conftest.py 文件。

②conftest.py是测试框架pytest的胶水文件,里面用到了fixture函数,封装并传递出了driver。

import pytest
from py.xml import html
from selenium import webdriverdriver = None@pytest.fixture(scope='session', autouse=True)
def drivers(request):""":param request: python内置的fixture函数,本函数中用来注册终结函数:return: 返回driver实例"""global driverif driver is None:driver = webdriver.Chrome()driver.maximize_window()def fn():driver.quit()request.addfinalizer(fn)return driver@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item):"""当测试失败的时候,自动截图,展示到html报告中:param item:"""pytest_html = item.config.pluginmanager.getplugin('html')outcome = yieldreport = outcome.get_result()report.description = str(item.function.__doc__)extra = getattr(report, 'extra', [])if report.when == 'call' or report.when == "setup":xfail = hasattr(report, 'wasxfail')if (report.skipped and xfail) or (report.failed and not xfail):file_name = report.nodeid.replace("::", "_") + ".png"screen_img = _capture_screenshot()if file_name:html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:1024px;height:768px;" ' \'οnclick="window.open(this.src)" align="right"/></div>' % screen_imgextra.append(pytest_html.extras.html(html))report.extra = extradef pytest_html_results_table_header(cells):cells.insert(1, html.th('用例名称'))cells.insert(2, html.th('Test_nodeid'))cells.pop(2)def pytest_html_results_table_row(report, cells):cells.insert(1, html.td(report.description))cells.insert(2, html.td(report.nodeid))cells.pop(2)def pytest_html_results_table_html(report, data):if report.passed:del data[:]data.append(html.div('通过的用例未捕获日志输出.', class_='empty log'))def _capture_screenshot():'''截图保存为base64:return:'''return driver.get_screenshot_as_base64()

11、发送邮件

①当项目执行完成之后,需要发送到自己或者其他人邮箱里查看结果。
②编写发送邮件的模块。
③在 utils 目录中新建 send_mail.py 文件,文件内容如下:

import zmail
from config.conf import cmdef send_report():"""发送报告"""with open(cm.REPORT_FILE, encoding='utf-8') as f:content_html = f.read()try:mail = {'from': 'xxxxxx@qq.com','subject': '最新的测试报告邮件','content_html': content_html,'attachments': [cm.REPORT_FILE, ]}server = zmail.server(*cm.EMAIL_INFO.values())server.send_mail(cm.ADDRESSEE, mail)print("测试邮件发送成功!")except Exception as e:print("Error: 无法发送邮件,{}!", format(e))if __name__ == "__main__":'''请先在config/conf.py文件设置QQ邮箱的账号和密码'''send_report()

④在 config/conf.py 文件中设置我们自己的QQ邮箱账号以及QQ邮箱授权码。运行 send_report() 函数。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。

相关文章:

Python+Selenium+Pytest+POM自动化测试框架封装详解

1、测试框架简介 1&#xff09;测试框架的优点 代码复用率高&#xff0c;如果不使用框架的话&#xff0c;代码会显得很冗余。可以组装日志、报告、邮件等一些高级功能。提高元素等数据的可维护性&#xff0c;元素发生变化时&#xff0c;只需要更新一下配置文件。使用更灵活的…...

Hidden Marlov Model(HMM)

一、Model 1、将声学特征设为X&#xff0c;经过语音识别得到的tokens设为Y&#xff0c;目标是找到通过X得到Y的最大概率&#xff0c;可以通过概率公式改变为 分为两个概率 2、将tokens序列Y转化为states序列S&#xff0c;声学特征分得更细 3、从states到声学特征的过程 二、HM…...

mamba的安装及下载速度慢问题解决

同事反馈mamba的安装时网络慢 mamba是conda的加速工具&#xff0c;相比于conda 对包和环境的管理&#xff0c;mamba可以实现并行运算。相比于 conda&#xff0c;mamba 是用C重写了 conda 的部分功能&#xff0c;运行效率显著提高&#xff0c;可以进行并行的下载&#xff0c;使…...

【Linux入门】Linux环境搭建

目录 前言 一、发行版本 二、搭建Linux环境 1.Linux环境搭建方式 2.虚拟机安装Ubuntu 22.02.4 1&#xff09;安装VMWare 2&#xff09;下载镜像源 3&#xff09;添加虚拟机 4&#xff09;换源 5&#xff09;安装VM Tools 6)添加快照 总结 前言 Linux是一款自由和开放…...

CPU缓存一致性机制详解

CPU缓存一致性机制详解 在多核处理器中&#xff0c;缓存一致性是保证系统正常运行的重要环节。本文详细介绍了缓存一致性协议、写入策略、总线嗅探、目录协议等相关概念&#xff0c;并通过示例代码解释了这些机制是如何在实际应用中工作的。通过学习本文&#xff0c;读者可以深…...

Android 12系统源码_屏幕设备(一)DisplayManagerService的启动

前言 DisplayManagerService是Android Framework中管理显示屏幕相关的模块&#xff0c;各种Display的连接、配置等&#xff0c;都是通过DMS和来管理控制。 在DMS模块中&#xff0c;对显示屏幕的描述分为物理显示屏(physical display)和逻辑显示屏(logical display)&#xff0c…...

《AI视频类工具之十——​D-ID》

一.简介 官网:D-ID | The #1 Choice for AI Generated Video Creation Platform D-ID是一个人工智能生成的视频创建平台,可以轻松快速地从文本输入中创建高质量、高性价比和引人入胜的视频,背后的Al技术是由Stable Difusion和GPT.3提供支持,可以在没有任何技术知识的情况…...

【网络】局域网LAN、广域网WAN、TCP/IP协议、封装和分用

文章目录 局域网 LAN广域网 WAN网络中的重要概念IP 地址端口号 认识协议协议分层是什么OSI 七层网络模型TCP/IP 五层网络模型&#xff08;或四层&#xff09;物理层传输层网络层数据链表层应用层网络设备所在分层 封装和分用[站在发送方视角]&#xff08;封装&#xff09;[站在…...

我司搜索中台的三次演变

本人从入职就开始负责我司的搜索中台了&#xff0c;总共是经历了三个大版本的迭代。 分别是&#xff1a; 基于阿里云智能开放搜索OpenSearch实现的第一代自研&#xff0c;开源canal&#xff08;数据同步&#xff09; 底层阿里云elasticsearch 对索引封装 实现的第二代自研&a…...

html+css+js网页设计 电商模版4个页面

htmlcssjs网页设计 电商模版4个页面 带js 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&…...

区块链技术在Facebook中的潜力:未来趋势与挑战

数据安全的新高度 区块链技术以其去中心化和不可篡改的特性&#xff0c;正在成为提升数据安全和隐私保护的重要工具。Facebook作为全球最大的社交媒体平台之一&#xff0c;正积极探索如何将区块链技术应用于其平台&#xff0c;以增强用户数据的安全性和隐私保护。Facebook在应…...

dockerfile自定义镜像

目录 概念 基于dockerfile创建 dockerfile的命令 构建容器 FROM ENTRYPOINT和CMD RUN COPY和ADD 工作目录和环境变量以及容器卷&#xff08;挂载卷&#xff09; EXPOSE 实战 概念 dockerfile就是自定义镜像&#xff0c;通过dockerfile创建的都是镜像&#xff0c;而…...

【工作状态】如何保持专注?

好的睡眠计划主题化 1、保持足够的睡眠&#xff0c;才能头脑清晰和有精力&#xff0c;工作不是纯拼体力&#xff0c;要用脑力的。 2、脑力主要工作放在午餐前&#xff0c;在脑力充足的时候使用脑力&#xff0c;下午五点后可以安排脑力活动较低的工作&#xff0c;比如听课读书。…...

欧科云链研究院对话:风浪越大鱼越贵—链上数据洞悉加密市场规律

作者 Hedy 出品 OKG Research “我们从来就不是理性人。但可以用最简单的工具——链上数据做‘最猛’的分析。” 在经历了超级宏观周之后&#xff0c;金融市场产生了巨大的震荡&#xff0c;加密市场的表现也越来越受到宏观经济因素的影响。欧科云链研究院OKG Research 集结多…...

SQLite库笔记:日期和时间函数

1. 函数概述 SQLite支持7个日期和时间函数&#xff0c;如下&#xff1a; 1 date(time-value, modifier, modifier, ...) 返回YYYY-MM-DD格式的日期 2 time(time-value, modifier, modifier, ...) 返回HH:MM:SS格式的时间 3 datetime(time-value, modifier, modifier, ...…...

Linux开发板运行报错/system/bin/sh: can‘t create /dev/leds: Permission denied

Linux开发板运行报错/system/bin/sh: cant create /dev/leds: Permission denied 1.问题解决 1.问题解决 /system/bin/sh: can’t create /dev/leds: Permission denied 在linux开发板下运行驱动报错没有权限&#xff0c;需要运行 su,同时也会停止打印 在运行&#xff1a; ch…...

月薪5W的项目经理是如何面试的?这份面试攻略请收好!

面试是项目经理求职必须经历的一关&#xff0c;但很多经验不够丰富的项目经理不知道面试会问些什么问题&#xff0c;也不知道要怎么回答&#xff0c;无疑会直接影响面试企业的判断&#xff0c;使项目经理求职受阳.所以&#xff0c;项目经理想要顺利求职&#xff0c;还是有必要掌…...

接口隔离原则

接口隔离原则 接口隔离原则就是客户端不应该依赖它不需要的接口&#xff0c;或者说类间的依赖关系应该建立在最小的接口上。 我们以搜索美女为例&#xff0c;设计了如下的类图&#xff1a; 源代码如下。美女及其实现类&#xff1a; 搜索程序及其子类源代码如下&#xff1a; 最…...

【C++ 面试 - 基础题】每日 3 题(十六)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…...

端到端测试自动化:使用JavaScript打造可靠的Web应用

端到端测试&#xff08;End-to-End Testing&#xff0c;简称E2E测试&#xff09;是软件测试的一种形式&#xff0c;用于验证整个应用从端到端的流程是否按预期工作。在JavaScript生态系统中&#xff0c;E2E测试通常使用专门的框架来模拟用户交互&#xff0c;验证应用的业务逻辑…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...