`

Selenium2 WebDriver入门

 
阅读更多

1 简介

资源

jar包:http://code.google.com/p/selenium/downloads/list

官方 UserGuide:http://seleniumhq.org/docs/

2 基本配置

2.1 Firefox

对于不同的浏览器,需要创建不同类型的WebDriver进行测试,默认情况下我们通常可以直接 new XXXDriver() 来创建对应类型的 WebDriver。

如果使用Firefox测试,而Firefox又没有安装在默认目录下,那么直接 new FirefoxDriver()将会出现异常提示找不到浏览器。这时,我们需要在程序开始调用以下代码,用以指定Firefox的位置:

System.setProperty(“webdriver.firefox.bin”, “***\\firefox.exe”)

或者我们使用 FirefoxBinary 实例来指定浏览器的位置:

File firefox = new File(“…\\firefox.exe”);

FirefoxBinary firefoxbin = new FirefoxBinary(firefox);

WebDriver driver = new FirefoxDriver(firefoxbin, null);

值得注意的是,使用以上两种配置启动的Firefox浏览器是“全新”的,也就是说浏览器的设置都是初始的,包括插件集。这会使依赖 Firebug 等插件的开发调试工作无法进行,于是我们需要保留浏览器的配置信息。

这需要使用FirefoxProfile 实例来指定配置文件的位置:

String path = System.getProperty( "user.home" )

+ "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\";

File prodir = new File( path );

File[] files = prodir.listFiles( new FilenameFilter()

{

@Override

public boolean accept( File dir, String name )

{

return name.endsWith( ".default" );

}

} );

FirefoxProfile profile = new FirefoxProfile( files[0] );

综上而言,我们通常会使用 FirefoxDriver(FirefoxBinarybinary, FirefoxProfile profile) 形式的构造器。

 

2.2 Chrome

与Firefox类似,如果测试程序找不到Chrome的安装位置(非默认位置),那么可以这样指定:

System.setProperty(“webdriver.chrome.driver”, “***\\chrome.exe”)

但是,使用Chrome测试,比较特别的是,需要驱动程序:

http://chromedriver.storage.googleapis.com/index.html

通常,我们使用 ChromeDriver(ChromeDriverServiceservice, ChromeOptions options) 形式的构造器,前一参数可指定驱动程序的位置,后一参数可指定浏览器的位置。

ChromeDriverService 实例的创建如下:

String chromeDriver = "…\\chromedriver.exe";

ChromeDriverService service = new ChromeDriverService.Builder().

usingDriverExecutable( new File(chromeDriver) ).build();

ChromeOptions 实例的创建如下:

String chrome = "…\\chrome.exe";

ChromeOptions options = new ChromeOptions();

options.setBinary( chrome );

 

3 基本使用

3.1 打开浏览器

开始测试前,总是应该创建一个WebDriver接口实现类实例,以打开某种浏览器。

// 创建Firefox driver实例,打开Firefox

WebDriver driver = new FirefoxDriver();

// 创建IE driver实例,打开IE

WebDriver driver = new InternetExplorerDriver();

3.2 打开测试页面

打开浏览器后,应该导航到测试页面进行测试。

driver.get( "http://www.baidu.com" )

另一种可选方式是:

driver.navigate().to( "http://www.baidu.com" );

3.3 查找元素

导航到测试页面后,就应该要查找页面元素进行操作了。

由于Selenium2推崇面向接口编程,所以所有元素都使用WebElement接口代表。

定位元素位置可以在WebDriver实例上进行,也可以在某个WebElement上进行。它们都暴露了findElement()和findElements()方法,前者查找返回一个WebElement对象否则抛出异常;后者查找返回一个WebElement列表,如果没有匹配项列表可能为空。

两种find方法都使用By类实例进行定位。By是一个抽象类,所以实际使用的应是它的派生子类,每种派生子类都代表一种查找策略。通常我们不直接调用其派生子类的构造器创建对象,而是使用By类的静态工厂方法来创建。

下面逐一说明各种定位方式。

3.3.1By ID

通过ID查找。这是最高效也最常用的定位方式。但是,可能存在的陷阱是:网页中ID并非唯一或者ID是自动生成的。使用中应该避免这些情况。

WebElement element = driver.findElement(By.id("coolestWidgetEvah"));

3.3.2By Name

通过name查找。

WebElement cheese = driver.findElement(By.name("cheese"));

3.3.3By XPath

通过XPath查找。WebDriver试图在任何地方使用浏览器原生XPath能力,但是对于原生不支持XPath的浏览器,将提供实现。这可能导致一些非预期的行为,除非你清楚不同XPath引擎间的差异。

Driver

Tag and Attribute Name

Attribute Values

Native XPath Support

HtmlUnit Driver

Lower-cased

As they appear in the HTML

Yes

Internet Explorer Driver

Lower-cased

As they appear in the HTML

No

Firefox Driver

Case insensitive

As they appear in the HTML

Yes

比如如下页面:

<input type="text" name="example" />

<INPUT type="text" name="other" />

查找语句为:

List<WebElement> inputs = driver.findElements(By.xpath("//input"));

匹配结果为:

XPath expression

HtmlUnit Driver

Firefox Driver

Internet Explorer Driver

//input

1 (“example”)

2

2

//INPUT

0

2

0

有时元素不必声明某些有默认值的属性,比如input元素的type属性可以缺省,缺省值为text。但是在WebDriver中使用XPath时,你不能期望能够匹配未声明的默认属性。

3.3.4By Class Name

通过class属性查找。实际使用中相同的class属性一般对应多个元素,所以一般会查找到多个元素,然后取用第一个元素。

List<WebElement> cheeses = driver.findElements(By.className("cheese"));

3.3.5By Link Text

通过超链接文本查找超链接。

WebElement cheese = driver.findElement(By.linkText("cheese"));

3.3.6By Partial Link Text

通过部分超链接文本查找超链接。

WebElement cheese = driver.findElement(By.partialLinkText("cheese"));

3.3.7By Css Selector

通过Css Selector查找。如果浏览器默认原生支持css查询,可参阅w3c css selectors;否则 Sizzle被使用。IE6,7和FF3.0都使用Sizzle作为css查询引擎。

注意并非所有的浏览器都是等效的,有的css在一个中起作用也许在另一个中不会。

WebElement cheese = driver.findElement(By.cssSelector("#food span.dairy.aged"));

3.3.8By TagName

通过元素标签名查找。

WebElement frame = driver.findElement(By.tagName("iframe"));

3.4 界面操作

找到页面元素后,需要操作元素,通常WebElement接口方法就足以操作大多数元素了。

3.4.1通用操作

 

// 点击

element.click();

// 文本框输入

element.sendKeys(“*****”);

// 文本框清空

element.clear();

// 是否选中,单/多选等

element.isSelected();

// 是否可用

element.isEnabled();

3.4.2文件域

file.sendKeys(filePath);

3.4.3下拉列表

对于下拉列表这种较复杂的元素,使用通用的方法来操作将不是那么高效的。我们可以将其封装为Select对象,这将提供更多有用的方法便于操作。

Select select = new Select(driver.findElement(By.tagName("select")));

select.selectByVisibleText(“***”);

select.deselectByVisibleText(“***”);

select.selectByValue(“***”);

select.deselectByValue(“***”);

select.deselectAll();

select.getAllSelectedOptions();

select.getFirstSelectedOption();

3.4.4表单

一旦填写完表单,我们就期望提交它。一个提交的方法是找到“提交”按钮并点击它。

driver.findElement(By.id("submit")).click();

另外,WebDriver为每个元素都提供了一个方便的submit()方法。如果你调用一个处于表单中的元素的submit()方法,WebDriver将沿DOM向上查找直到找到表单然后提交。如果元素不在表单中,则会抛出NoSuchElementException异常。

// 表单提交

element.submit();

3.4.5Actions

// 拖拽元素到目标元素中

new Actions( driver ).dragAndDrop( element, target ).perform();

// hover

new Actions(driver).moveToElement( text ).perform();

3.4.6对话框

我们可以获取到各种弹出对话框的对象,并可以执行accept、dismiss、读取内容或者向prompt中输入内容等操作。

Alert alert = driver.switchTo().alert();

alert.accept();

alert.dismiss();

alert.getText();

alert. sendKeys();

3.4.7Windows和Frames切换

有的Web应用是多框架或多窗口的。

WebDriver支持在命名窗口间切换:

driver.switchTo().window("windowName");

怎样知道窗口的名字呢?查看一下打开它的JS或超链接:

<a href="somewhere.html" target="windowName">Click here to open a new window</a>

另外,也可以使用窗口句柄,这可能需要迭代所有窗口句柄来获取某个窗口的句柄了:

for (String handle : driver.getWindowHandles()) {

driver.switchTo().window(handle);

}

在框架间切换也是类似的:

driver.switchTo().frame("frameName");

3.4.8导航

driver.navigate().forward();

driver.navigate().back();

 

4 非界面操作

4.1 Cookie

driver.manage().addCookie(cookie);

driver.manage().getCookies();

driver.manage().getCookieNamed(“cookieName”);

driver.manage().deleteCookieNamed(“cookieName”);

driver.manage().deleteCookie(cookie);

driver.manage().deleteAllCookies();

4.2 执行JS

可以执行任意JS脚本来查找一个元素,并且只要返回一个DOM元素,它将被自动转换为WebElement对象。

WebElement element = (WebElement) ((JavascriptExecutor)driver).executeScript("return $('.cheese')[0]");

 

4.3 截图

测试过程中,可以把页面截图,保存成为图片。

需要注意,截取的图片存在临时目录,所以需要将其拷贝到指定的目录,否则测试完成可就找不到截图了。

File screenshotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);

FileUtils.copyFile( screenshotFile, new File("E:\\1.png") );

或远程截图

WebDriver augmentedDriver = new Augmenter().augment(getDriver());

File screenshotFile = ((TakesScreenshot)augmentedDriver).getScreenshotAs(OutputType.FILE);

 

4.4 等待

当页面需要一段时间才能加载完成,那么就需要等待完成后才进行查找和操作。

等待有2种:显性等待和隐性等待。

显性等待使用WebDriverWait类和ExpectedCondition接口完成,编码实现ExpectedCondition接口用以判断某种条件,然后等待这种条件达成或超时。

WebElement myDynamicElement = (new WebDriverWait(driver, 10))

.until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));

ExpectedConditions类提供了许多静态工厂方法,返回常用的ExpectedCondition对象。

隐性等待更为简洁:

driver.manage().timeouts().implicitlyWait( 10, TimeUnit.SECONDS );

但是隐性等待的设置将影响后续全局的查找操作。

4.5 改变User Agent

FirefoxProfile profile = new FirefoxProfile();

profile.addAdditionalPreference("general.useragent.override", "some UA string");

WebDriver driver = new FirefoxDriver(profile);

 

5 附录

5.1 注意

5.1.1关于click()

当调用WebElement.click()时,如果被操作元素是不可用的(disabled),click()方法调用仍会是正常的,不会有异常。

所以,如果会出现被点击的元素是不可用的情况,而点击不可用元素又被认为是非法的,那么应该在click()调用前使用isEnable()方法检查元素可用性。

5.1.2driver.close() vs.driver.quit()

在测试结束后通常需要关闭浏览器,这个操作通常使用close()或quit()方法完成。但是两者是有区别的,其方法说明也体现了这一点。

close()

Close the current window, quitting the browser if it's the last window currently open.

quit()

Quits this driver, closing every associated window.

对于close()而言,如果当前窗口是最后一个打开窗口,那么关闭当前窗口退出浏览器;quit()则关闭每个关联的窗口退出浏览器。

但是,实际使用中close()方法的行为同说明有一些出入。以firefox为例,当当前窗口为最后一个打开窗口时,close()方法不会将最后一个窗口关闭,当然也不会使firefox退出。

5.2 常用API

5.2.1Sleeper

原生休眠类

org.openqa.selenium.browserlaunchers.Sleeper

public static void sleepTightInSeconds(longtimeoutInSeconds)

public static void sleepTight(long timeout)

 

分享到:
评论

相关推荐

    实时监控体系:基于Prometheus的API性能指标可视化方案.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    5个提升DeepSeekAPI生成质量的调参技巧,开发者必看!.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    ACM动态规划模板-区间修改线段树问题模板

    ACM动态规划模板-区间修改线段树问题模板

    深度解析C语言调试技巧:VSCode+GDB实战排错指南.pdf

    # 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!

    10个高效调用DeepSeekAPI的技巧:从请求优化到缓存策略.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    基于Python语言的PersonRelationKnowledgeGraph设计源码

    本项目为Python语言开发的PersonRelationKnowledgeGraph设计源码,总计包含49个文件,涵盖19个.pyc字节码文件、12个.py源代码文件、8个.txt文本文件、3个.xml配置文件、3个.png图片文件、2个.md标记文件、1个.iml项目配置文件、1个.cfg配置文件。该源码库旨在构建一个用于表示和查询人物关系的知识图谱系统。

    成本优化指南:通过Token计算模型将API费用降低57%的秘诀.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    大华智能物联平台,的对接其他接口的API,可以获得视频拉流的flv/hls/rstp 的拉流地址,demo项目为springBoot项目,可以通过摄像头的视频通道,获取到实时拉流的uRl

    rtsp实时预览接口URL:/evo-apigw/admin/API/MTS/Video/StartVideo HLS、FLV、RTMP实时预览接口方式 :接口URL/evo-apigw/admin/API/video/stream/realtime 参数名 必选 类型 说明 data true string Json串 +channelId true string 视频通道编码 +streamType true string 码流类型:1=主码流, 2=辅码流,3=辅码流2 +type true string 协议类型:hls,hlss,flv,flvs,ws_flv,wss_flv,rtmp hls:http协议,m3u8格式,端口7086; hlss:https协议,m3u8格式,端口是7096; flv:http协议,flv格式,端口7886; flvs:https协议,flv格式,端口是7896; ws_flv:ws协议,flv格式,端口是7886; wss_flv:wss协议,flv格式,端口是7896; rtmp:rtmp协议,端口是1975;

    Simulink永磁风机飞轮储能系统二次调频技术研究:频率特性分析与参数优化,Simulink永磁风机飞轮储能二次调频技术:系统频率特性详解及参数优化研究参考详实文献及两区域系统应用,simulink

    Simulink永磁风机飞轮储能系统二次调频技术研究:频率特性分析与参数优化,Simulink永磁风机飞轮储能二次调频技术:系统频率特性详解及参数优化研究参考详实文献及两区域系统应用,simulink永磁风机飞轮储能二次调频,系统频率特性如下,可改变调频参数改善频率。 参考文献详细,两区域系统二次调频。 ,核心关键词: 1. Simulink 2. 永磁风机 3. 飞轮储能 4. 二次调频 5. 系统频率特性 6. 调频参数 7. 改善频率 8. 参考文献 9. 两区域系统 以上关键词用分号(;)分隔,结果为:Simulink;永磁风机;飞轮储能;二次调频;系统频率特性;调频参数;改善频率;参考文献;两区域系统。,基于Simulink的永磁风机与飞轮储能系统二次调频研究:频率特性及调频参数优化

    MATLAB驱动的ASR防滑转模型:PID与对照控制算法对比,冰雪路面条件下滑移率与车速轮速对照展示,MATLAB驱动的ASR防滑转模型:PID与对照控制算法对比,冰雪路面条件下滑移率与车速轮速对照图

    MATLAB驱动的ASR防滑转模型:PID与对照控制算法对比,冰雪路面条件下滑移率与车速轮速对照展示,MATLAB驱动的ASR防滑转模型:PID与对照控制算法对比,冰雪路面条件下滑移率与车速轮速对照图展示,MATLAB驱动防滑转模型ASR模型 ASR模型驱动防滑转模型 ?牵引力控制系统模型 选择PID控制算法以及对照控制算法,共两种控制算法,可进行选择。 选择冰路面以及雪路面,共两种路面条件,可进行选择。 控制目标为滑移率0.2,出图显示车速以及轮速对照,出图显示车辆轮胎滑移率。 模型简单,仅供参考。 ,MATLAB; ASR模型; 防滑转模型; 牵引力控制系统模型; PID控制算法; 对照控制算法; 冰路面; 雪路面; 控制目标; 滑移率; 车速; 轮速。,MATLAB驱动的ASR模型:PID与对照算法在冰雪路面的滑移率控制研究

    芯片失效分析方法介绍 -深入解析芯片故障原因及预防措施.pptx

    芯片失效分析方法介绍 -深入解析芯片故障原因及预防措施.pptx

    4131_127989170.html

    4131_127989170.html

    PostgreSQL自动化部署与优化脚本:智能化安装、安全加固与监控集成

    内容概要:本文提供了一个全面的PostgreSQL自动化部署解决方案,涵盖智能环境适应、多平台支持、内存与性能优化以及安全性加强等重要方面。首先介绍了脚本的功能及其调用方法,随后详细阐述了操作系统和依赖软件包的准备过程、配置项的自动生成机制,还包括对实例的安全性和监控功能的强化措施。部署指南给出了具体的命令操作指导,便于新手理解和执行。最后强调了该工具对于不同硬件条件和服务需求的有效应对能力,特别是针对云计算环境下应用的支持特点。 适合人群:对PostgreSQL集群运维有一定基础并渴望提高效率和安全性的数据库管理员及工程师。 使用场景及目标:本脚本能够帮助企业在大规模部署时减少人工介入时间,确保系统的稳定性与高性能,适用于各类需要稳定可靠的数据库解决方案的企业或机构,特别是在大数据量和高并发事务处理场合。 其他说明:文中还提及了一些高级功能如自动备份、流复制等设置步骤,使得该方案不仅可以快速上线而且能满足后续维护和发展阶段的要求。同时提到的技术性能数据也为用户评估其能否满足业务需求提供了直观参考。

    房地产开发合同[示范文本].doc

    房地产开发合同[示范文本].doc

    成本优化实战:DeepSeekAPI的Tokens计算与计费策略拆解.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    安全必读:DeepSeek接口调用中的数据加密与合规实践.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    工程技术承包合同[示范文本].doc

    工程技术承包合同[示范文本].doc

    蓝桥杯开发赛作品源码【基于C语言】

    蓝桥杯开发赛【作品源码】

    深度解析DeepSeek语义分析API:实现情感分析与意图识别的进阶技巧.pdf

    在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!

    CVPR2023复现技术:多数据集验证下的YOLOX、YOLOv5及YOLOV7检测涨点助力器,CVPR2023复现实验助力检测涨点,验证了YOLOX、YOLOv5及YOLOV7在多个数据集上的有效性

    CVPR2023复现技术:多数据集验证下的YOLOX、YOLOv5及YOLOV7检测涨点助力器,CVPR2023复现实验助力检测涨点,验证了YOLOX、YOLOv5及YOLOV7在多个数据集上的有效性,cvpr2023复现,助力检测涨点,YOLOX YOLOv5 YOLOV7均有效,再多个数据集验证有效 ,cvpr2023复现; 助力检测涨点; YOLOX有效; YOLOv5有效; YOLOV7有效; 多数据集验证有效,CVPR2023复现成功:多模型检测涨点验证有效

Global site tag (gtag.js) - Google Analytics