Java/Kotlin 使用 Chrome 无头浏览器
1. 概念
无头浏览器在类似于流行网络浏览器的环境中提供对网页的自动控制,但是通过命令行界面或使用网络通信来执行。 它们对于测试网页特别有用,因为它们能够像浏览器一样呈现和理解超文本标记语言,包括页面布局、颜色、字体选择以及JavaScript和AJAX的执行等样式元素,这些元素在使用其他测试方法时通常是不可用的。[1][2]
无头浏览器通常用来:
- Web应用程序中的测试自动化。
- 拍摄网页截图
- 对JavaScript库运行自动化测试
- 收集网站数据
- 自动化网页交互
1.2 与传统的Http 库做爬虫对比
无头浏览器与HTTP库都可以用于爬虫,但它们有一些区别和优劣势。无头浏览器指的是使用脚本来模拟真实浏览器的使用场景,它能够更好地处理JavaScript渲染、异步请求等问题,而HTTP库则更适合处理静态页面、API等。
无头浏览器:
- JavaScript渲染和动态页面处理: 如果你需要爬取动态页面或者需要执行JavaScript代码,无头浏览器是更好的选择。
- JavaScript解密:无头浏览器不能解密js脚本以此让你查阅,但是他能执行该脚本以此来得到结果。而HTTP库对于加密的JS需要进行JS逆向等操作之后在模拟加密过程才能与API进行访问,而无头浏览器直接帮你进行模拟。无头模拟器通常用于有加密的js的网站
- 隐私和安全:无头浏览器可以模拟真实的用户行为,更能够避免被网站检测到并阻止。此外,无头浏览器可以自主的使用代理、设置cookies等方式来保护隐私和安全。因此可以做到处理反爬虫的效果
HTTP库:
- 性能和速度:HTTP库通常比无头浏览器更快。HTTP只需要考虑API和静态页面的获取,不需要解析页面,获取CSS,渲染页面
- 代码复杂度和维护成本:获取某个数据可以通过少量代码直接调用API。使用无头浏览器可能需要更复杂的代码,因为需要编写JavaScript代码来模拟用户行为和操作DOM
1.3 无头浏览器一览
-
Headless Chrome: Google推出的无头浏览器,可以模拟Chrome浏览器的所有功能,包括JavaScript解析、HTML解析、CSS解析等。
-
Selenium : 并不是一个无头浏览器,而是一个浏览器自动化测试工具,这个通常会被搞混,他可以通过驱动程序来自动化操作对应的浏览器。Selenium可以支持多款主流浏览器,包括Chrome、Firefox、Safari等。同时 Selenium还支持浏览器的无头模式,比如Firefox、PhantomJS、Chrome的无头模式(Headless)等
-
Puppeteer: Google开发的一个Node.js库,用于控制Headless Chrome,可以模拟用户操作、截屏、生成PDF等。
-
Playwright: Microsoft开发的一个Node.js库,可以控制多个浏览器,包括Chrome、Firefox和Safari等,可以模拟用户操作、截屏、生成PDF等。
-
Splash:一个基于Python的无头浏览器,可以解析JavaScript、渲染网页、截屏等,可以通过HTTP API进行控制。
-
HtmlUnit: 一款基于Java的开源无头浏览器,它可以模拟浏览器行为并执行JavaScript代码。它可以与JUnit和TestNG等测试框架集成,用于自动化测试和Web爬虫等任务。
-
JBrowserDriver: 一款基于Selenium WebDriver的无头浏览器,它使用Java Swing库模拟浏览器界面。它可以模拟用户行为,进行自动化测试和Web爬虫等任务。然而,由于它使用了Java Swing库,因此可能需要更多的资源。
-
Cobra: 一款Java HTML解析器和渲染引擎,可以模拟浏览器行为并执行JavaScript代码。它可以用于自动化测试、Web爬虫和Web应用程序等任务。然而,由于它不是专门为自动化测试而设计的,因此可能需要更多的配置和代码。
1.4. 自动化配置环境
2.1 引入依赖:
ChromiumDownloader
是用于下载 Chromium
和对应的 ChromiumDriver
。
同时ChromiumDownloader依赖了 selenium
所以仅需要引入这个一个依赖即可,如果需要更换 selenium
另外自行引入即可
<dependency><groupId>io.github.zimoyin</groupId><artifactId>ChromiumDownloader</artifactId><version>1.2.0</version>
</dependency>
2.2 下载 Chromium/ChromiumDriver
使用 ChromiumLoader.downloadAndLoad
即可自动下载 Chromium/ChromiumDriver
如果在本地./chrome
查找到了 Chromium/ChromiumDriver 则不会去下载了
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("127.0.0.1", 8070))
val options = ChromiumLoader.downloadAndLoad(proxy)
因为需要到谷歌服务器去下载文件,所以对于需要一些特殊的Proxy才能访问和下载。
如果需要手动下载到该构建网站下载最新的构建版本即可: 点击跳转
2.3 访问百度
至此一个最简单的功能已将实现了,通过 ChromiumDownloader 不再需要手动去下载Chrome 和它的驱动了
val options = ChromiumLoader.downloadAndLoad(proxy)
// 注意 Root 运行需要关闭沙盒
options.addArguments("--no-sandbox")
options.addArguments("--disable-dev-shm-usage")
options.addArguments("--ignore-ssl-errors=yes")
options.addArguments("--ignore-certificate-errors")
options.addArguments("--headless")
ChromeDriver(options).use {get("https://www.baidu.com")
}
小工具
获取浏览器和驱动的版本号
println(ChromiumLoader.getChromeDriverVersion(path))
println(ChromiumLoader.getChromeVersion(path))
2.Headless Chrome
2.1 环境搭建
2.1.1 安装Chrome
Windows : 直接在 Chrome/Chromium 官网下载。推荐使用 Chromium 开箱即用。
历史版本:
- Chromium历史版本第三方版本统计: 基本包括驱动版本
- 官方历史快照版: 基本包括驱动版本
- 选择您的平台:Mac、Win、Linux、ChromiumOS
- 选择您想要使用的 Chromium 内部版本号
LAST_CHANGE
文件中提到了最新的
- 下载包含 Chromium 的 zip 文件
- 里面有一个二进制可执行文件可以运行
如何指定打开的浏览器,而不是默认的浏览器 :
- 通过将驱动放在你浏览器所在的文件夹内,并设置
System.setProperty("webdriver.chrome.driver","驱动地址");
即可 - 通过代码进行设置
System.setProperty("webdriver.chrome.driver","bin path:驱动地址")
ChromeOptions options = new ChromeOptions();
options.setBinary("bin path: 浏览器的执行文件");
ebDriver driver = new ChromeDriver(options);
linux: 请百度,我使用的是Ubuntu 所以我直接百度的 Ubuntu Ser ver 安装 Chrome
Linux : 安装chrome headless CHATGPT
Chrome Headless实际上是Chrome浏览器的无界面版本,可以通过命令行进行操作。以下是在Linux系统中安装Chrome Headless的步骤:
-
确认系统已安装Google Chrome浏览器,如果没有,可以使用以下命令安装:
sqlCopy codesudo apt update sudo apt install google-chrome-stable
-
安装Chromium浏览器所需的依赖项:
sqlCopy codesudo apt update sudo apt install -y unzip libgconf-2-4 libnss3-dev libfontconfig1
-
下载ChromeDriver:
bashCopy codewget https://chromedriver.storage.googleapis.com/91.0.4472.101/chromedriver_linux64.zip unzip chromedriver_linux64.zip sudo mv chromedriver /usr/local/bin/ sudo chown root:root /usr/local/bin/chromedriver sudo chmod +x /usr/local/bin/chromedriver
-
启动Chrome浏览器,并设置Headless模式:
cssCopy code google-chrome-stable --headless --disable-gpu --no-sandbox --remote-debugging-port=9222
-
现在您可以使用Chrome浏览器和Headless模式进行操作。例如,您可以使用Selenium WebDriver进行自动化测试或网络爬虫。
注意:请注意安全问题。在生产环境中使用Chrome Headless时,请确保采取适当的安全措施,如限制访问Chrome浏览器的端口或禁用某些Chrome浏览器的功能。
2.1.2 启动浏览器
打开 Chromestatus 网站
# chrome 是二进制文件不是命令,你可以打开Chrome的安装目录找到
# 或者新建一个 Chrome 快捷方式,在快捷方式的属性里找到 快捷方式-目标 添加以下参数
# --user-data-dir=D:\Chrome\user1 这是设置缓存目录的参数
chrome --headless --disable-gpu --remote-debugging-port=9222 https://www.chromestatus.com
2.1.3 下载chromedriver
找到对应浏览器版本的驱动
官方网站:http://chromedriver.storage.googleapis.com/index.html
2.1.4 配置 chromedriver 的环境变量
在环境变量里面的 Path 添加 chromedriver 所在文件夹的路径。注意可以不设置
2.1.5 添加依赖
注意第一个的版本必须是最新的否则可能与驱动不匹配。第二个依赖可以不引入,如果发生了异常再引入也可以
<dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><!--<version>3.4.0</version>--><version>4.7.2</version>
</dependency><!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>24.1-jre</version>
</dependency>
2.1.6 代码启动浏览器
https://blog.csdn.net/qq_22003641/article/details/79137327
https://blog.csdn.net/dengjie811227/article/details/102292146
https://www.cnblogs.com/eastonliu/p/9102239.html
https://blog.csdn.net/erhuobuer/article/details/108680617
//驱动地址: 如果不设置环境变量则需要设置驱动地址
//如果想要打开特点的浏览器,就把驱动放在那个浏览器的所在文件夹内,比如要打开Chromium 就放在 Chromium 的文件夹内
System.setProperty("webdriver.chrome.driver","/chromedriver");
// 设置驱动
ChromeOptions options=new ChromeOptions();
//设置 chrome 的无头模式
options.addArguments("--headless");
options.addArguments("--disable-gpu");
options.addArguments("--no-sandbox");
options.addArguments("--disable-dev-shm-usage");
options.addArguments("--start-maximized");
//因为报表页面必须滚动才能全部展示,这里直接给个很大的高度
options.addArguments("--window-size=1280,4300");
//设置用户目录
options.addArguments(" --user-data-dir=D:\\Chrome\\user1");
// 创建webdriver驱动
WebDriver driver = new ChromeDriver(options);//注意 UA为 User-Agent: selenium/4.8.3 (java windows)
// 访问网页
webDriver.get(url);
// Selenium提供了8种定位方式。请通过 By这个类查看
//clear() 清除文本。sendKeys(*value) 模拟按键输入。click() 单击元素。submit()方法用于提交表单
// 获取输入框,输入selenium
driver.findElement(By.id("kw")).sendKeys("selenium");
// 获取“百度一下”按钮,进行搜索
driver.findElement(By.id("su")).click();//模拟键盘
//WebElement 对象.sendKeys(Keys.SPACE)//注意可以用组合键//执行javascript 可以直接设置localstroage,cookie等方式。不过拼字符串实在太麻烦
String token = "localStorage.setItem('cloud.token','{\"val\":\"5d31f455-8ed5-4ebe-80d1-760665df452c\",\"expires\":1584531900299}')";
((JavascriptExecutor)webDriver).executeScript(token);//定位section元素
WebElement element = webDriver.findElement(By.tagName("section"));
Point p = element.getLocation();
int width = element.getSize().getWidth();
int height = element.getSize().getHeight();
Rectangle rec = new Rectangle(p.getX(),p.getY(),height,width);//截取全屏
File scrFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
//在全屏图片下裁剪
BufferedImage img = ImageIO.read(scrFile);
BufferedImage dest = img.getSubimage(p.getX(), p.getY(),rec.getWidth(),rec.getHeight());
ImageIO.write(dest, "png", scrFile);
//拷贝文件
FileUtils.copyFile(scrFile , new File("a.png"));
log.info("截图完成");
//退出
webDriver.quit();
WebDriver driver = new ChromeDriver(); //Chrome浏览器
WebDriver driver = new FirefoxDriver(); //Firefox浏览器
WebDriver driver = new EdgeDriver(); //Edge浏览器
WebDriver driver = new InternetExplorerDriver(); // Internet Explorer浏览器
WebDriver driver = new OperaDriver(); //Opera浏览器
WebDriver driver = new PhantomJSDriver(); //PhantomJS
2.2 报错
如果报错请首要排查三个原因
-
chrome 版本是否与驱动大版本一致,建议都升级为最新版
-
java 引入的jar库是否是最新版
-
Exception in thread "main" org.openqa.selenium.SessionNotCreatedException: Could not start a new session. Response code 500. Message: unknown error: failed to write first run file
这个异常通常是由于Selenium驱动程序无法启动浏览器会话导致的,可能是由于驱动程序版本与浏览器版本不兼容,或者是由于缺少浏览器二进制文件或用户权限不足等原因。 如果你设置了用户缓存目录请给予java程序权限
org.openqa.selenium.UnhandledAlertException: unexpected alert open: {Alert text : Hello World!}
这个异常通常是由于在执行测试期间,页面上出现了未预期的弹窗,例如警告框、确认框或提示框等。
要解决这个问题,您可以尝试以下几个步骤:
- 使用
switchTo().alert()
方法切换到警告弹窗并处理它。例如,您可以使用accept()
方法点击弹窗上的“确定”按钮,或使用dismiss()
方法点击弹窗上的“取消”按钮。- 在执行任何可能引发警告弹窗的操作之前,可以使用
driver.switchTo().alert()
方法来检查页面是否有警告弹窗。如果存在,可以通过上述方法来处理它。
NoSuchElementException
:当尝试访问不存在的元素时,会引发此异常。TimeoutException
:当 Selenium 超时并无法在指定时间内找到所需的元素或页面元素时,会引发此异常。StaleElementReferenceException
:当尝试访问一个已经被删除或不再可用的元素时,会引发此异常。ElementNotVisibleException
:当尝试访问一个隐藏的元素时,会引发此异常。ElementNotInteractableException
:当尝试与无法与之交互的元素进行交互时,会引发此异常。InvalidSelectorException
:当选择器无效或不符合语法规则时,会引发此异常NoSuchWindowException
:当尝试访问不存在的窗口时,会引发此异常。UnhandledAlertException
:当出现未处理的警告弹窗时,会引发此异常。SessionNotCreatedException
:当浏览器会话无法启动时,会引发此异常。WebDriverException
:这是一个通用异常,可能由各种原因引起,例如网络连接问题、代理设置错误等。SessionNotCreatedException
:当浏览器会话无法创建或启动时,会引发此异常。可能是因为缺少驱动程序或浏览器版本不兼容等原因。TimeoutException
:当 Selenium 无法在指定的时间内执行操作时,会引发此异常。例如,当页面加载过慢或元素不可见时。NoSuchWindowException
:当尝试访问不存在的浏览器窗口时,会引发此异常。NoSuchSessionException
:当尝试访问已经关闭的浏览器会话时,会引发此异常。ElementNotVisibleException
:当尝试访问不可见的元素时,会引发此异常。ElementNotSelectableException
:当尝试选择不支持选择操作的元素时,会引发此异常。InvalidSelectorException
:当选择器无效或不符合语法规则时,会引发此异常。JavascriptException
:当在 JavaScript 代码中发生错误时,会引发此异常。UnhandledAlertException
:当出现未处理的警告弹窗时,会引发此异常。
2.3 项目实例
2.3.0 设置WebDriver
DesiredCapabilities
和 ChromeOptions
都是用于设置 WebDriver 的选项和配置的类。它们之间的区别在于:
DesiredCapabilities
是 Selenium WebDriver 中的一个通用选项类,可以用于设置所有支持的浏览器的选项。而ChromeOptions
是针对 Chrome 浏览器的选项类,只能用于设置 Chrome 浏览器的选项。DesiredCapabilities
可以设置的选项包括浏览器类型、版本、操作系统、页面加载策略、代理等。而ChromeOptions
可以设置的选项包括二进制文件路径、启动参数、扩展、调试端口等。- 在使用 Chrome 浏览器时,您通常需要使用
ChromeOptions
来设置选项,例如指定浏览器的二进制文件路径或设置启动参数。而在使用其他浏览器时,您可能需要使用DesiredCapabilities
来设置选项。
// 创建一个 ChromeOptions 对象
ChromeOptions options = new ChromeOptions();
// 设置 Chrome 浏览器的二进制文件路径
options.setBinary("/usr/bin/google-chrome");
// 设置启动参数
options.addArguments("--disable-extensions");// 创建一个 DesiredCapabilities 对象
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
// 设置 ChromeOptions 选项
capabilities.setCapability(ChromeOptions.CAPABILITY, options);// 使用 DesiredCapabilities 对象创建 ChromeDriver
// 也可以使用 options 直接设置
WebDriver driver = new ChromeDriver(capabilities);// 访问网站
driver.get("https://www.example.com");// 关闭浏览器
driver.quit();
2.3.1 控制浏览器
//控制浏览器
// 设置全屏
driver.manage().window().fullscreen();
//获取当前窗口相对于屏幕左上角的位置。
System.out.println(driver.manage().window().getPosition());
//获取浏览器大小
System.out.println(driver.manage().window().getSize());
//最小化
driver.manage().window().minimize();
//最大化
driver.manage().window().maximize();
//设置窗口大小
driver.manage().window().setSize(...);
2.3.2 模拟鼠标
-
ActionChains
模拟鼠标 -
Actions action = new Actions(driver);
-
contextClick()
右击 -
clickAndHold()
鼠标点击并控制 -
doubleClick()
双击 -
dragAndDrop()
拖动 -
release()
释放鼠标 -
dragAndDrop(source, target):
模拟鼠标拖拽 拖拽到某个元素然后松开 -
dragAndDropBy(source, xoffset, yoffset):
模拟鼠标拖拽 拖拽到某个坐标然后松开 -
moveToElement()
模拟鼠标悬停 -
clickAndHold()
方法用于模拟鼠标悬停操作, 在调用时需要指定元素定位 -
perform()
执行所有Actions中存储的行为 -
build()
构建所有操作 -
模拟鼠标移动 它是模拟鼠标移动而不是真实的鼠标移动
moveByOffset()
moveToElement
- 示例
action.clickAndHold(WebElement对象).build().perform();
2.3.3 历史记录
//允许驱动程序访问浏览器的历史记录并导航到给定的URL。
WebDriver.Navigation navigate = driver.navigate();
navigate.refresh();//刷新
navigate.back();//回退
navigate.forward();//向前
navigate.to(..);//跳转URL
2.3.4 窗口切换
//获取当前打开窗口的所有句柄
Set<String> handles = driver.getWindowHandles();
//获取当前窗口的句柄(String类型)
String handle = driver.getWindowHandle();
//跳转页面,通过窗口句柄,这里使用第一个句柄
driver.switchTo().window(handles.stream().findFirst().orElse(""));
//新开一个窗口
driver.switchTo().newWindow(WindowType.TAB);
driver.get("https://bilibili.com");
2.3.5 Cookie
//Cookie 操作
Set<Cookie> cookies = driver.manage().getCookies();
driver.manage().addCookie(null);
driver.manage().deleteAllCookies();
driver.manage().deleteCookieNamed("");
driver.manage().getCookieNamed("");
2.3.6 等待页面加载
我们经常会碰到用selenium操作页面上某个元素的时候, 需要等待页面加载完成后, 才能操作。 否则页面上的元素不存在,会抛出异常。或者碰到AJAX异步加载,我们需要等待元素加载完成后, 才能操作。
2.3.6.1 页面加载策略
默认Chrome 浏览器下 所有的元素定位是在页面被完全加载后(页面tab不再转圈)才开始。执行 get 后的代码
在 Selenium 中,可以通过 WebDriver
接口的 manage()
方法来设置页面加载策略。页面加载策略是指当页面处于加载状态时,WebDriver 应该等待多长时间才应该抛出 TimeoutException
异常。以下是几种页面加载策略:
normal
:这是默认的页面加载策略。它会等待页面加载完毕,并在超时时间内等待。eager
:这个策略会尝试尽快地完成页面加载,并在超时时间内等待。如果页面在超时时间内没有加载完毕,它会抛出TimeoutException
异常。none
:这个策略不会等待页面加载完毕,并立即返回。如果您想在页面加载完毕之前执行某些操作,则可以使用这个策略。请注意,如果您在等待操作之前尝试访问页面元素,则可能会抛出StaleElementReferenceException
异常。
1. 元素出现但页面未加载完毕
首选需要明白的一点是,如果什么都不设置,通常,以chrome浏览器为例,所有的元素定位是在页面被完全加载后(页面tab不再转圈)才开始。
有时候其实想要的元素已经加载出来了,只是页面还在加载其他东西,例如图片,此时若不想继续等待直接执行元素定位操作,则需要在创建driver的时候设置页面加载策略:
当调用driver.get(“https://xxxx.xxx.xxx”)来访问某页面时,get方法通常会阻塞浏览器直到页面完全加载后才执行后面的动作,若一个页面加载过慢,则会导致get方法一直阻塞。有时候希望页面在加载过程中就开始检测元素是否存在,而不是等到页面加载完了才开始检测,想要实现这个效果,可以用DesiredCapabilities类下的setPageLoadStrategy方法(Python,Chrome浏览器) 设置页面加载策略为 none
,以便在页面加载期间执行其他操作。接下来,我们使用 WebDriverWait
类等待元素的可见性。在这里,我们等待了最多 10 秒钟,直到元素可见。如果元素在这个时间内没有可见,它会抛出 TimeoutException
异常。
ChromeOptions options = new ChromeOptions();
options.setPageLoadStrategy(PageLoadStrategy.NONE);
WebDriver driver = new ChromeDriver(options);driver.get("https://example.com");//等待页面30s
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
//指定要等待的元素。
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("example-id")));
System.out.println("Page element is visible: " + element.isDisplayed());driver.quit();
2.3.6.2 隐示等待
隐式等待是一种全局等待,它在 WebDriver 对象实例化后设置一次即可,对于整个 WebDriver 实例的生命周期都起作用。
隐式等待的作用是让 WebDriver 在查找页面元素时等待一段时间,如果在等待时间内找到了指定的元素,则立即执行后面的操作。如果等待时间结束仍未找到指定的元素,则抛出 NoSuchElementException
异常。这种等待方式适用于那些需要加载一些资源(例如 JavaScript、图片等)的页面,因为这些资源可能会影响页面元素的加载速度。driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
// 设置 Chrome 浏览器驱动路径
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
// 创建 ChromeDriver 实例
WebDriver driver = new ChromeDriver();// 设置隐式等待时间为 10 秒
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);// 访问网站
driver.get("https://www.example.com");// 查找并操作页面元素
WebElement element = driver.findElement(By.id("example-id"));
element.click();// 关闭浏览器
driver.quit();
2.3.6.3 显示等待
显示等待是一种精确控制等待时间的等待方式,它可以让我们在指定时间内等待某个条件的成立。与隐式等待不同,显式等待是在代码中手动编写的,需要指定等待的最长时间,以及判断条件的类型和条件值。当等待时间内判断条件成立,则立即执行后续的操作,否则在等待时间到达后抛出异常。
Selenium WebDriver 提供了一个名为 WebDriverWait
的类来实现显式等待。使用 WebDriverWait
可以指定等待的最长时间和等待条件,常用的等待条件包括 elementToBeClickable
、presenceOfElementLocated
、visibilityOfElementLocated
等等。
// 设置 Chrome 浏览器驱动路径
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
// 创建 ChromeDriver 实例
WebDriver driver = new ChromeDriver();// 访问网站
driver.get("https://www.example.com");// 显式等待页面元素加载完成
WebDriverWait wait = new WebDriverWait(driver, 10);
//ExpectedConditions.visibilityOfElementLocated 方法来指定等待条件为指定元素的可见性。如果等待时间内指定元素的可见性成立,则 wait.until 方法立即返回找到的页面元素,并执行后续的操作;如果等待时间到达后仍未找到指定元素,则抛出 TimeoutException 异常。
//ExpectedConditions 提供的各种判断条件。WebElement element = wait.until(ExpectedConditions.condition());
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("example-id")));// 对页面元素进行操作
element.click();// 关闭浏览器
driver.quit();
2.3.6.4 流畅等待
FluentWait
是WebDriver提供的另一种等待方式,用于在指定时间内以一定的时间间隔不断地进行条件判断,直到超时或者条件成立为止。与WebDriverWait
相比,FluentWait
更加灵活,可以根据具体需求自定义等待时间和等待条件,适用于一些比较特殊的场景。
使用FluentWait
需要先定义等待条件(ExpectedCondition
对象)和等待时间间隔,然后将它们传入FluentWait
的构造方法中,最后调用until
方法即可。与显示等待的 WebDriverWait类似,区别是WebDriverWait已经设置好几个等待条件,而流畅等待 FluentWait可以自己设置等待条件。
FluentWait<WebDriver> wait = new FluentWait<>(driver).withTimeout(Duration.ofSeconds(10)) // 设置超时时间为10秒.pollingEvery(Duration.ofSeconds(1)) // 每隔1秒检测一次.ignoring(NoSuchElementException.class); // 忽略NoSuchElementException异常WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("example-id")));
2.3.7 定位方式
- 根据元素ID进行定位
driver.findElement(By.id("element-id"));
- 根据元素名称进行定位
driver.findElement(By.name("element-name"));
- 根据链接文本进行定位
driver.findElement(By.linkText("link-text"));
- 根据部分链接文本进行定位
driver.findElement(By.partialLinkText("partial-link-text"));
- 根据元素标签名称进行定位
driver.findElement(By.tagName("tag-name"));
- 根据CSS选择器进行定位
driver.findElement(By.cssSelector("selector"));
- 根据XPath表达式进行定位
driver.findElement(By.xpath("xpath-expression"));
- 根据元素类名进行定位
driver.findElement(By.className("class-name"));
需要注意的是,不同的定位方式的效率和适用场景也不同,需要根据实际情况选择合适的定位方式。另外,还可以使用复合定位方式,将多种定位方式组合使用来定位元素。
2.3.7.1 css定位
根据CSS选择器进行定位是Selenium中常用的一种方式,可以通过使用 By.cssSelector()
方法实现。
在使用CSS选择器进行定位时,可以通过元素的id、class、属性和标签名称等信息来定位元素。下面是一些常用的CSS选择器示例:
- 通过id定位元素
driver.findElement(By.cssSelector("#element-id"));
- 通过class定位元素
driver.findElement(By.cssSelector(".element-class"));
- 通过属性定位元素
driver.findElement(By.cssSelector("[attribute-name='attribute-value']"));
- 通过标签名称定位元素
driver.findElement(By.cssSelector("tag-name"));
- 通过组合选择器定位元素
driver.findElement(By.cssSelector("tag-name#element-id.attribute-name[attribute-value]"));
- 子选择器
使用>
符号来选择作为某元素子元素的元素,例如:
driver.findElement(By.cssSelector("parent-element > child-element"));
- 后代选择器
使用空格符号来选择某元素后代元素,例如:
driver.findElement(By.cssSelector("parent-element child-element"));
- 相邻兄弟选择器
使用+
符号来选择某元素之后相邻的兄弟元素,例如:
driver.findElement(By.cssSelector("preceding-element + sibling-element"));
- 通用兄弟选择器
使用~
符号来选择某元素之后的兄弟元素,例如:
driver.findElement(By.cssSelector("preceding-element ~ sibling-element"));
需要注意的是,在使用CSS选择器进行定位时,需要确保选择器的唯一性,否则可能会定位到不符合预期的元素。同时,还需要注意选择器的复杂度和性能问题。在定位复杂的元素时,建议优先考虑使用XPath表达式进行定位。
2.3.8 获取页面源代码
- Java
driver.getPageSource()
- JS
// 注入JavaScript脚本
String script = "return document.documentElement.outerHTML;";
String pageSource = (String) ((JavascriptExecutor) driver).executeScript(script);
2.3.9 打开相同的浏览器(来自于网络)
在使用 Selenium 进行自动化测试时,如果希望在每次运行脚本时打开相同的浏览器,可以使用 WebDriver 的 SessionId
属性来实现。
首先,打开浏览器并执行测试代码,可以通过 driver.getSessionId()
方法获取当前浏览器会话的 SessionId
值。然后,在下一次运行测试脚本时,可以使用 WebDriver
的 attach
方法,传入上一次运行时获取的 SessionId
值,即可重新打开相同的浏览器并继续测试。
以下是使用 Java 实现上述方法的示例代码:
// 第一次打开浏览器并执行测试代码
WebDriver driver = new ChromeDriver();
driver.get("https://www.example.com");
String sessionId = driver.getSessionId().toString();
driver.quit();// 下一次打开相同的浏览器并继续测试
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("debuggerAddress", "localhost:9222");
WebDriver driver = new ChromeDriver(options);
driver = new ChromeDriver(options);
driver.get("https://www.example.com");
RemoteWebDriver remoteWebDriver = (RemoteWebDriver) driver;
remoteWebDriver.executeScript("window.open('about:blank', '_blank');");
remoteWebDriver.switchTo().window(remoteWebDriver.getWindowHandles().stream().skip(1).findFirst().get());
remoteWebDriver.get("http://localhost:9222/json/new?"+sessionId);
remoteWebDriver.switchTo().window(remoteWebDriver.getWindowHandles().stream().findFirst().get());
需要注意的是,在上述代码中,需要事先在命令行启动一个 Chrome 浏览器实例,并启用远程调试模式。在启动浏览器实例时,需要使用 --remote-debugging-port
参数指定一个空闲的端口号,如 9222
。在运行测试脚本时,需要将 ChromeOptions
实例的 debuggerAddress
属性设置为 localhost:9222
,表示连接到远程调试端口。在连接上一个已有的浏览器实例后,需要调用 window.open()
方法打开一个新的空白窗口,并切换到该窗口,最后通过 http://localhost:9222/json/new?sessionId
URL 加载之前会话的 SessionId
值,以恢复之前浏览器会话的状态。
2.3.10 启动参数设置
// Chrome
options = new ChromeOptions();
// 启动就最大化
// options.addArguments("start-fullscreen");
// options.addArguments("--start-maximized");
// 禁用浏览器弹出窗口拦截器。
options.addArguments("--disable-popup-blocking");
// 取消沙盘模式
options.addArguments("no-sandbox");
//禁用 Chrome 的 /dev/shm 空间,在一些低配服务器上可能会导致 Chrome 崩溃。
options.addArguments("--disable-dev-shm-usage");
// 禁止扩展
options.addArguments("disable-extensions");
// 禁止默认浏览器检查
options.addArguments("no-default-browser-check");
options.addArguments("about:histograms");
options.addArguments("about:cache");
// 设置浏览器固定大小
// 注意:设定了浏览器固定大小后,浏览器打开后浏览器的位置可能会变到其他位置,因此可以使用设置刘浏览器的位置方法和设置浏览器的大小方法一起使用;driver.manage().window().maximize();
options.addArguments("--window-size=1600,900");
// chrome正受到自动测试软件的控制
options.addArguments("disable-infobars");//谷歌插件 注意对于路径都要使用 new File(...).getCanonicalPath();或者使用相对路径
options.addExtensions(new File("/path/to/extension.crx"))
options.setBinary(new File("/path/to/chrome"));
// 禁用 GPU 硬件加速,可以避免一些图形渲染问题和内存泄漏问题。
options.addArguments("--disable-gpu");
//用户工作目录(缓存地址)
options.addArguments("--user-data-dir="+new File("./cache/user/user1").getCanonicalPath());//每当我们使用selenium启动chrome浏览器时,将为每个新会话创建一个新实例/临时配置文件。如果我们要加载默认的Chrome浏览器或自定义Chrome配置文件,
//我们可以将'user-data-dir'参数传递给ChromeOptions,这是Chrome命令行切换,告诉Chrome使用哪个配置文件。如果路径不存在,chrome将在指定的路径中创建新的配置文件。
options.addArgument("user-data-dir=/path/to/your/custom/profile");//无头浏览器
options.addArguments("--headless");
//禁用浏览器的同源策略,允许在同一网站内加载来自多个域的资源。
options.addArguments("--disable-web-security");
//设置浏览器的 User-Agent 字符串,可以用来伪装浏览器类型和版本。
options.addArguments("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3");//性能优化
options.addArguments("--disable-extensions");//禁用 Chrome 扩展程序。
options.addArguments("--no-sandbox");//高危
options.addArguments("--blink-settings=imagesEnabled=false");//禁用浏览器中的图片加载,可以加快浏览器的渲染速度。
options.addArguments("--disable-features=IsolateOrigins,site-per-process");//高危
options.addArguments("--disable-features=VizDisplayCompositor");//高危
options.addArguments("--disable-features=RendererCodeIntegrity");//高危
options.addArguments("--disable-blink-features=AutomationControlled");// 高危
options.addArguments("--mute-audio");// 禁用浏览器声音。
options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation")); //禁用自动化标识
options.setExperimentalOption("useAutomationExtension", false);// 禁用拓展程序
//不禁用 CSS 的情况下,将网页加载为无样式的版本,从而提高性能。注意这设置了UA
options.addArguments("--user-agent=Googlebot");
options.addArguments("--disable-javascript");//禁用JavaScript
options.addArguments("--disable-blink-features=CSSAnimations");//禁用CSS动画
options.addArguments("--disable-blink-features=CSSTransitions");//禁用CSS过渡
其他
--disable-notifications
: 禁用浏览器通知。
--disable-popup-blocking
: 禁用浏览器弹出窗口拦截器。
--disable-default-apps
: 禁用默认应用程序。
--hide-scrollbars
: 隐藏浏览器滚动条。
--mute-audio
: 禁用浏览器声音。
--log-level=3
: 设置浏览器的日志级别为WARNING
。
--disable-logging
: 禁用浏览器日志输出。
setExperimentalOption("useAutomationExtension", false)
: 禁用 Chrome 扩展程序,用于避免一些自动化测试过程中出现的问题。
setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"))
: 禁用 Chrome 的自动化开关,也是用于避免自动化测试过程中出现的问题。这行代码会禁用 Chrome 的自动化开关。当启用自动化测试时,Chrome 会自动开启一个特殊的标志“enable-automation”,这个标志可能会导致一些网站行为异常或者被检测到并阻止自动化测试。因此,在执行自动化测试时,禁用此开关可以避免这些问题的发生。
setExperimentalOption("prefs", prefs)
: 设置 Chrome 的偏好选项。方法可以设置 Chrome 浏览器的偏好选项。在这个方法中,prefs
参数是一个Map<String, Object>
对象,其中包含一些键值对,用于设置浏览器的偏好选项。偏好选项可以用来控制浏览器的一些行为,例如下载文件的默认路径、启用 Flash 插件、禁用自动填充表单等。通过设置偏好选项,可以使自动化测试脚本更加灵活和可控。
--disable-browser-side-navigation
: 禁用浏览器侧边导航。
--disable-features=VizDisplayCompositor
: 禁用 Chrome 的某个功能,可以提高 Chrome 的性能。这个功能用于渲染页面的图形界面,禁用它可以提高 Chrome 的性能,但可能会影响页面的显示效果。
--disable-features=RendererCodeIntegrity
: 禁用 Chrome 的某个功能,可以提高 Chrome 的性能。这个功能用于保护渲染器进程不被攻击者利用,但它会消耗一些额外的性能,禁用它可以提高 Chrome 的性能。
--blink-settings=imagesEnabled=false
: 禁用浏览器中的图片加载,可以加快浏览器的渲染速度。
--disable-blink-features=AutomationControlled
: 禁用 Blink 引擎自动化控制的功能。可以禁用 Chrome 浏览器中 Blink 引擎的自动化控制功能,使得一些原本受到限制的操作变得可行。但需要注意的是,禁用这个功能可能会导致一些不安全的操作被执行,因此需要谨慎使用。
--disable-features=IsolateOrigins,site-per-process
: 禁用 Chrome 的网站隔离和进程隔离功能,可以提高性能和减少内存占用。
--remote-debugging-port=9222
: 开启 Chrome 的远程调试端口。
--disable-extensions
: 禁用 Chrome 扩展程序。
--disable-web-security
: 禁用 Chrome 的同源策略,允许在同一网站内加载来自多个域的资源。
。--disable-features=CSSGridLayout
。启用该参数后,Chrome 浏览器将不会使用 CSS 网格布局来排版页面,可能会提高页面加载速度和浏览器性能,但也会导致网页排版样式异常
2.3.11 执行 JS
在Java中使用Selenium执行JavaScript可以使用JavascriptExecutor
接口。这个接口可以在Selenium WebDriver对象上使用
System.setProperty("webdriver.chrome.driver", "path/to/chromedriver");
WebDriver driver = new ChromeDriver();driver.get("http://www.example.com");JavascriptExecutor js = (JavascriptExecutor) driver;// 在页面上执行JavaScript
js.executeScript("alert('Hello World!');");driver.quit();
如何处理js的返回值: 接收返回值,根据 Class 进行强制转换
Object o = js.executeScript("return 1+1");
//class java.lang.Long
System.out.println(o.getClass());
if (o instanceof Long){Long l = (Long)o;// ........
}
2.3.12 关闭日志
您使用的是其他日志框架,例如 log4j
或 logback
,则需要查找该框架提供的特定方法或配置来关闭日志记录。通常,这些框架都提供了一些级别配置,您可以将其设置为“OFF”或“ERROR”来关闭日志记录。
2.3.13 截图
//截取全屏
File scrFile = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
//在全屏图片下裁剪
BufferedImage img = ImageIO.read(scrFile);
BufferedImage dest = img.getSubimage(p.getX(), p.getY(),rec.getWidth(),rec.getHeight());
ImageIO.write(dest, "png", scrFile);
//拷贝文件
FileUtils.copyFile(scrFile , new File("a.png"));
log.info("截图完成");
File screenshotFile = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
这行代码使用了 TakesScreenshot
接口中的 getScreenshotAs
方法来获取元素的屏幕截图。 getScreenshotAs
方法接受一个参数,即 OutputType
,用于指定截图的类型。在这里,我们使用了 OutputType.FILE
来指定截图以文件形式返回。
TakesScreenshot
接口是一个由 WebDriver 实现的接口,它允许您获取 WebDriver 实例的屏幕截图。通过将 WebDriver 实例转换为 TakesScreenshot
接口类型,您可以调用 getScreenshotAs
方法来获取屏幕截图。但是,请注意,如果您传递的是一个 WebElement 对象而不是 WebDriver 实例,那么将会截取该元素的屏幕截图,而不是整个页面的截图。
另外,由于 getScreenshotAs
方法返回的是一个 File
类型的对象,您需要使用 Java 的 FileUtils
类或其他类库来将截图保存到本地文件中。在上面的代码中,我们使用了 Apache Commons IO 库中的 FileUtils
类来复制文件
2.3.14 插件(来自网络)
控制浏览器插件的方式取决于您使用的浏览器和插件类型。下面是一些常见浏览器插件的控制方式:
- AdBlock Plus:使用 AdBlock Plus 的
org.openqa.selenium.chrome.ChromeOptions
类和addExtensions
方法来加载插件。示例代码如下:
javaCopy codeChromeOptions options = new ChromeOptions();
options.addExtensions(new File("/path/to/adblockplus.crx"));
WebDriver driver = new ChromeDriver(options);
- uBlock Origin:使用 uBlock Origin 的
org.openqa.selenium.chrome.ChromeOptions
类和addExtensions
方法来加载插件。示例代码如下:
javaCopy codeChromeOptions options = new ChromeOptions();
options.addExtensions(new File("/path/to/ublockorigin.crx"));
WebDriver driver = new ChromeDriver(options);
- Firebug:使用 Firefox 的
org.openqa.selenium.firefox.FirefoxProfile
类和addExtension
方法来加载插件。示例代码如下:
javaCopy codeFirefoxProfile profile = new FirefoxProfile();
File firebug = new File("/path/to/firebug.xpi");
File netExport = new File("/path/to/netExport.xpi");
profile.addExtension(firebug);
profile.addExtension(netExport);
WebDriver driver = new FirefoxDriver(profile);
在上面的代码中,我们使用了 Firefox 的 addExtension
方法来加载 Firebug 插件和 NetExport 插件。
请注意,加载浏览器插件可能会对浏览器性能产生一定影响,因此请谨慎使用。此外,不同版本的浏览器和插件可能需要不同的加载方式,请根据您的具体情况进行调整。
相关文章:
Java/Kotlin 使用 Chrome 无头浏览器
1. 概念 无头浏览器在类似于流行网络浏览器的环境中提供对网页的自动控制,但是通过命令行界面或使用网络通信来执行。 它们对于测试网页特别有用,因为它们能够像浏览器一样呈现和理解超文本标记语言,包括页面布局、颜色、字体选择以及JavaSc…...
AI前端开发:赋能开发者,提升解决实际问题的能力
近年来,人工智能技术飞速发展,深刻地改变着各行各业。在软件开发领域,AI写代码工具的出现更是引发了一场革命,尤其是前端开发领域,AI的应用正在显著提升开发者的解决实际问题的能力。本文将探讨AI前端开发如何提升效率…...
【Elasticsearch】Elasticsearch检索方式全解析:从基础到实战(二)
接着上一篇文章;我们继续来研究es的复杂检索 文章目录 (1) bool用来做复合查询(2)Filter【结果过滤】(3)term(4)Aggregation(执行聚合) (1) bool用来做复合查询 复合语…...
ASP.NET Core SignalR的分布式部署
假设聊天室程序被部署在两台服务器上,客户端1、2连接到了服务器A上的ChatRoomHub,客户端3、4连接到服务器B上的ChatRoomHub,那么客户端1发送群聊消息时,只有客户端1、2能够收到,客户端3、4收不到;在客户端3…...
kafka的架构和工作原理
目录 Kafka 架构 Kafka 工作原理 Kafka 数据流 Kafka 核心特性 总结 Kafka 架构 1. 生产者(Producer) 2. 消费者(Consumer) 3. 主题(Topic) 4. 分区(Partition) 5. 副本(Replica) 6. 代理(Broker) 7. ZooKeeper(旧版本)/KRaft(新版本) Kafka 工作…...
当没有OpenGL时,Skia如何绘制?
Skia 是可以在没有 OpenGL 的情况下进行图形绘制的,但是具体能否成功绘制图形,取决于 Skia 是如何配置的,以及平台上是否提供了其他的底层图形 API。 Skia 的底层依赖 Skia 的目标是提供一种跨平台的 2D 图形绘制接口。为了加速图形渲染&…...
Java小白入门基础知识(一)
1.初识Java java源程序通过javac 编译生成字节码文件,通过java命令运行java程序 总结: 1)在一个Java文件中,只能有一个public class 2)public class一定要和文件名一致 3)类里面包含方法 4)…...
游戏内常见加密
加密只是增大破解难度,没法说绝对安全,避免过度加密导致性能消耗过大。 通用算法库 lua的加密算法库:https://github.com/somesocks/lua-lockbox/tree/master 比如通信协议就用到里面一些算法cry.encrypt 算法优劣:AES加解密-CBC…...
【Java八股文】02-Java集合面试篇
【Java八股文】02-Java集合面试篇 概念数组与集合区别常用集合Java中的线程安全的集合是什么?Collections和Collection的区别 Listjava中list的几种实现把ArrayList变成线程安全的有哪些方法?CopyOnWriteArrayList是如何保证线程安全的? Mapj…...
springCloud-2021.0.9 之 GateWay 示例
文章目录 前言springCloud-2021.0.9 之 GateWay 示例1. GateWay 官网2. GateWay 三个关键名称3. GateWay 工作原理的高级概述4. 示例4.1. POM4.2. 启动类4.3. 过滤器4.4. 配置 5. 启动/测试 前言 如果您觉得有用的话,记得给博主点个赞,评论,收…...
公然上线传销项目,Web3 的底线已经被无限突破
作者:Techub 热点速递 撰文:Yangz,Techub News 今天早些时候,OKX 将上线 PI 的消息在圈内引起轩然大波,对于上线被板上钉钉为传销盘子的「项目」 ,Techub News 联系了 OKX 公关,但对方拒绝置评…...
SQL数据清理:去除字段值中的多余符号(Demo例子)
目录 前言1. 基础2. 进阶 前言 Excel中有大量不合法的符号,导入到系统之后,数据库有很多脏数据,对此下述展开sql的清洗教程 在数据库的文本字段中,可能会存在多余的逗号或符号,如,销售,, 或 二手车,销售,,这种情况 希…...
MongoDB 的使用场景
一、内容管理系统 1. 博客平台 文章内容、作者信息、标签、评论等数据结构多样,MongoDB 的无模式特性可轻松应对。比如 WordPress 等博客系统,使用 MongoDB 能灵活存储不同格式和长度的文章内容,以及与文章相关的各种元数据。 2. 新闻网站…...
STM32 RTC 实时时钟说明
目录 背景 RTC(实时时钟)和后备寄存器 32.768HZ 如何产生1S定时 RTC配置程序 第一次上电RTC配置 第1步、启用备用寄存器外设时钟和PWR外设时钟 第2步、使能RTC和备份寄存器访问 第3步、备份寄存器初始化 第4步、开启LSE 第5步、等待LSE启动后稳定状态 第6步、配置LSE为…...
微服务SpringCloud Alibaba组件nacos教程【详解naocs基础使用、服务中心配置、集群配置,附有案例+示例代码】
一.Nacos教程 文章目录 一.Nacos教程1.1 Nacos简介1.2 nacos基本使用直接下载打包服务源码方式启动 1.3 创建nacos客服端1.4 nacos集群配置1.5 nacos配置中心 1.1 Nacos简介 nacos是spring cloud alibaba生态中非常重要的一个组件,它有两个作用: 1:注册…...
深度整理总结MySQL——Expalin指南(二)
Expalin指南(二 前言Extrano tables usedImpossible whereNo matching min/max rowUsing indexUsing index conditionUsing whereUsing join buffer (Block Nested Loop)Not existsUsing intersect(...)、Using union(...)和Using sort_union(...)Zero limitUsing filesortUsin…...
【机器学习】常见采样方法详解
在机器学习领域,数据采样(Sampling)是一项至关重要的技术。它不仅影响模型的训练效率,还直接关系到模型的性能与泛化能力。本文将从基础概念出发,逐步深入介绍机器学习中常见的采样方法,帮助读者全面理解并…...
Kubernetes 最佳实践:Top 10 常见 DevOps/SRE 面试问题及答案
1. 如何在 Kubernetes 中设置资源请求和限制? 资源请求确保容器有最小资源量(CPU/内存),而限制则强制容器消耗的最大资源量。这有助于高效资源分配并防止资源争用。 示例: resources:requests:memory: "256Mi&…...
Python自动化办公之Excel拆分
在日常办公中,我们经常需要将包含多个Sheet页的Excel文件拆分成多个独立的Excel文件。例如,当我们要把一份Excel表格发给各部门确认时,出于控制信息知悉范围、确保数据保密性等方面的考虑,每个部门仅需查看和确认与自己部门对应的…...
Mac上搭建宝塔环境并部署PHP项目
安装Docker Desktop》搭建Centos版本的宝塔环境》部署PHP项目 1. 下载Docker for mac 软件:https://www.docker.com/ 或使用终端命令:brew install --cask --appdir/Applications docker 2. 使用命令安装宝塔环境的centos7系统: docker pul…...
qt 控件的焦点事件
在 Qt 中,设置焦点策略是通过 QWidget 的 setFocusPolicy() 方法来实现的。焦点策略控制了一个控件何时和如何获取焦点。Qt 提供了几种常见的焦点策略,以帮助管理控件的焦点行为。 常见的焦点策略 Qt::NoFocus:控件不接受焦点。Qt::TabFocus&…...
深度学习_学习笔记
pandas Pandas 是一个强大的数据分析库,它封装和集成了多个其他库的功能,以便为用户提供更加便捷的数据处理能力。 pandas与csv 都可用于处理csv文件(注意csv文件不是excel文件) csv 是 Python 标准库的一部分,适合…...
如何在 Elasticsearch 中设置向量搜索 - 第二部分
作者:来自 Elastic Valentin Crettaz 了解如何在 Elasticsearch 中设置向量搜索并执行 k-NN 搜索。 本文是三篇系列文章中的第二篇,深入探讨了向量搜索(也称为语义搜索)的复杂性以及它在 Elasticsearch 中的实现方式。 第一部分重…...
leetcode 面试经典 150 题:跳跃游戏 II
链接跳跃游戏 II题序号45题型数组题解贪心算法难度中等熟练度✅✅✅ 题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums…...
C++20 新特性解析
1. 概念(Concepts) 概念是 C++20 引入的一项重要特性,它允许程序员定义类型约束,从而在编译时检查模板参数是否符合某些要求。概念提供了模板参数的限制,使得模板代码更加可读和易于维护。 示例代码: #include <iostream> #include <concepts>// 定义一个…...
vue不是内部或外部命令?
问题:当我们在使用脚手架创建项目之前,执行了npm i vue/cli -g或yarn global add vue/cli之后,再执行vue --version无法执行,vue不是内部或外部命令。 前几天在学vue时也是遇到了这个问题,现在来分享一下解决方法。 …...
C#中的Frm_Welcome.Instance.Show(),是什么意思
Frm_Welcome.Instance.Show() 是一种常见的单例模式(Singleton Pattern)实现方式,通常用于在应用程序中确保某个窗体(Form)只有一个实例,并通过该实例显示窗体。以下是对这段代码的详细解释: 代…...
k8s优雅操作pod容器组
k8s优雅操作pod容器组 回退备份 kubectl get deploy deployName -o yaml>>deployName-bak-date "%Y-%m-%d".yaml获取副本数 replicasecho | kubectl get -o template deploy/deployName --template{{.spec.replicas}}停止容器组 kubectl scale deployment …...
【LeetCode: 1760. 袋子里最少数目的球 + 二分】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...
动态规划LeetCode-416.分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 示例 1: 输入:nums [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。 示例 2&…...
kotlin-kapt
kotlin-kapt kotlin-kapt 是 Kotlin 的一个插件,专门用于处理注解处理器(Annotation Processor)。以下是对该插件的详细解释和指南: kotlin-kapt 是什么? kotlin-kapt 是 Kotlin 官方提供的一个插件,用于在…...
网络安全技术复习总结
1|0第一章 概论 1.网络安全发展阶段包括四个阶段:通信安全、计算机安全、网络安全、网络空间安全。 2.2017年6月1日,我国第一部全面规范网络空间安全的基础性法律《中华人民共和国网络安全法》正式实施。 3.2021年 6月10日,《中华人民共和…...
java 集合
Java集合框架(Java Collections Framework)是一个强大的工具库,旨在简化数据存储和操作的任务。它提供了一组接口、类和算法,帮助开发者高效地管理数据,如列表、集合和映射。下面是Java集合框架的详细介绍:…...
Java常见排序算法及代码实现
1、选择排序算法 选择排序(Selection Sort)是一种简单直观的排序算法,它的工作原理是每次从未排序部分选择最小(或最大)的元素,将其放到已排序部分的末尾。 2、冒泡排序算法 冒泡排序(Bubble…...
130,[1] 攻防世界 very_easy_sql
进入靶场 典型SQL注入页面 先查看源码 访问 试试http://127.0.0.1/ 还尝试了其他都是nonono 回归第一个登录页面 提交的内容不在url处显示,反而第二个url页面会在url处显示 明白第一个页面是通过post方式提交,反正没得到什么信息,去抓…...
Spring Boot从入门到精通:核心知识点+实战指南
目录 一、Spring Boot 是什么?为什么它如此流行? 二、快速创建你的第一个Spring Boot应用 2.1 使用Spring Initializr生成项目 2.2 核心代码示例 三、深度解析Spring Boot核心机制 3.1 自动配置原理揭秘 3.2 自定义Starter实战 四、生产环境必备…...
深入探索现代CSS:从基础到未来趋势
引言:CSS的进化之路 CSS(层叠样式表)自1996年诞生以来,已从简单的样式描述语言发展为构建现代Web体验的核心技术。截至2023年,超过98%的网站使用CSS3技术,其发展历程见证了Web从静态文档到富交互应用的蜕变…...
python-leetcode 23.反转链表
题目: 给单链表的头节点,反转链表,并返回反转后的链表。 方法一:迭代 在遍历链表时,将当前节点的next指针改为指向前一个节点。由于节点没有引用其前一个节点,因此要先存储前一个节点,在更改引…...
Foundation CSS 可见性
Foundation CSS 可见性 引言 在网页设计中,CSS可见性是一个至关重要的概念。它决定了元素在网页上是否可见,以及如何显示。Foundation CSS 是一个流行的前端框架,它提供了丰富的工具和组件来帮助开发者构建响应式和可访问的网页。本文将深入探讨 Foundation CSS 中的可见性…...
DeepSeek模拟阿里面试——java基本语法
为了全面准备阿里Java高级程序员的面试,以下是针对数据类型和变量、运算符、流程控制的系统性复习和准备策略: 数据类型和变量 基本数据类型 整数类型:byte(1字节)、short(2字节)、int…...
大模型基本原理(二)——ChatGPT的工作原理
如何得到一个ChatGPT? 1、无监督预训练:通过大量的文本数据集进行无监督训练,得到一个基座模型(只会续写文本) 2、监督微调:通过一些人类撰写的高质量对话数据对基座模型进行监督微调,得到一个…...
TensorRT 8.6.1教程1-TensorRT简介
区分计算节点和数据节点 视频 TensorRT 教程 | 基于 8.6.1 版本 | 第一部分_哔哩哔哩_bilibili cookbook...
Seaweedfs(master volume filer) docker run参数帮助文档
文章目录 进入容器后执行获取weed -h英文中文 weed server -h英文中文 weed volume -h英文中文 关键点测试了一下,这个-volume.minFreeSpace string有点狠,比如设置值为10(10%),它直接给系统只留下10%的空间࿰…...
深度求索(DeepSeek)的AI革命:NLP、CV与智能应用的技术跃迁
Deepseek官网:DeepSeek 引言:AI技术浪潮中的深度求索 近年来,人工智能技术以指数级速度重塑全球产业格局。在这场技术革命中,深度求索(DeepSeek)凭借其前沿的算法研究、高效的工程化能力以及对垂直场景的…...
探索RDMA技术:从基础到实践
1. 引言 在当今的高性能计算(HPC)和数据中心领域,数据传输的效率和速度至关重要。RDMA(Remote Direct Memory Access,远程直接内存访问)技术作为一种高效的网络通信机制,能够显著减少数据传输的延迟和CPU负载。本文将从基础到实践,详细介绍RDMA技术及其编程模型,帮助…...
Excel 笔记
实际问题记录 VBA脚本实现特殊的行转列 已知:位于同一Excel工作簿文件中的两个工作表:Sheet1、Sheet2。 问题:现要将Sheet2中的每一行,按Sheet1中的样子进行转置: Sheet2中每一行的黄色单元格,为列头。…...
Flutter编译运行android问题之JVM版本问题
错误1: FAILURE: Build failed with an exception. * What went wrong: Execution failed for task :audioplayers_android:compileDebugKotlin. > Inconsistent JVM-target compatibility detected for tasks compileDebugJavaWithJavac (1.8) and compileDebug…...
自动化遇到的问题记录(遇到问题就更)
总结回归下自己这边遇到的一些问题 “EOF错误”,获取不到csv里面的内容 跑多csv文件里的场景,部分场景的请求值为 1、检查csv文件里不能直接是[]开头的参数,把[]改到ms平台的请求参数里 2、有时可能是某个参数值缺了双引号的其中一边 met…...
解决 Flutter Device Daemon 启动失败问题的实践记录
解决 Flutter Device Daemon 启动失败问题的实践记录 最近在使用 Flutter 开发时踩了一个坑。看似是个小问题,但折腾了好久,最终通过日志分析和查阅资料才找到了解决办法。这里记录一下整个问题的排查过程,希望能帮助到遇到类似问题的小伙伴…...
中国通信企业协会 通信网络安全服务能力评定 证书使用说明
中国通信企业协会颁发的通信网络安全服务能力资格证书,是证明证书持有单位符合通信网络安全服务相应能力准则要求。证书持有单位在使用中国通信企业协会颁发的证书时,应遵守以下规定: 评定证书 证书持有单位必须遵守《中国通信企业协会通信网…...