Selenium Grid 中的 CLI 选项
所有 Grid 组件配置的 CLI 选项的详细信息。
有不同的部分可用于配置 Grid。每个部分都有可以通过命令行参数配置的选项。
组件到部分映射的完整描述如下所示。
请注意,如果某个选项被修改或添加但尚未记录,则此文档可能已过时。如果您遇到这种情况,请查看“配置帮助”部分,并随时向我们发送拉取请求以更新此页面。
章节
独立 | 中心 | 节点 | 分发器 | 路由器 | 会话 | 会话队列 | |
---|---|---|---|---|---|---|---|
分发器 | |||||||
Docker | |||||||
事件 | |||||||
日志记录 | |||||||
网络 | |||||||
节点 | |||||||
路由器 | |||||||
中继器 | |||||||
服务器 | |||||||
会话队列 | |||||||
会话 |
分发器
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--healthcheck-interval | int | 120 | 健康检查将为所有节点运行的频率(以秒为单位)。这确保服务器可以成功 ping 所有节点。 |
--distributor | uri | http://localhost:5553 | 分发器的 URL。 |
--distributor-host | string | localhost | 分发器正在监听的主机。 |
--distributor-implementation | string | org.openqa.selenium.grid.distributor.local.LocalDistributor | 非默认分发器实现的完整类名 |
--distributor-port | int | 5553 | 分发器正在监听的端口。 |
--reject-unsupported-caps | boolean | false | 如果 Grid 不支持请求的功能,则允许分发器立即拒绝请求。立即拒绝请求适用于不按需启动节点的 Grid 设置。 |
--slot-matcher | string | org.openqa.selenium.grid.data.DefaultSlotMatcher | 要使用的非默认插槽匹配器的完整类名。这用于确定节点是否可以支持特定会话。 |
--slot-selector | string | org.openqa.selenium.grid.distributor.selector.DefaultSlotSelector | 非默认插槽选择器的完整类名。这用于在匹配节点后选择节点中的插槽。 |
--newsession-threadpool-size | int | 24 | 分发器使用固定大小的线程池来创建新会话,因为它从队列中消耗新的会话请求。这允许配置线程池的大小。默认值为可用处理器数量 * 3。注意:如果线程数远大于可用处理器,则并不总是会提高性能。大量的线程会导致更多的上下文切换,这是一种昂贵的操作。 |
Docker
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--docker-assets-path | string | /opt/selenium/assets | 将存储资产的绝对路径 |
--docker- | string[] | selenium/standalone-firefox:latest '{"browserName": "firefox"}' | Docker 配置,将镜像名称映射到刻板印象功能(示例 `-D selenium/standalone-firefox:latest ‘{“browserName”: “firefox”}’) |
--docker-devices | string[] | /dev/kvm:/dev/kvm | 向容器公开设备。每个设备映射声明都必须至少包含主机和容器中设备的路径,并用冒号分隔,如本示例所示:/device/path/in/host:/device/path/in/container |
--docker-host | string | localhost | Docker 守护程序正在运行的主机名 |
--docker-port | int | 2375 | Docker 守护程序正在运行的端口 |
--docker-url | string | http://localhost:2375 | 用于连接 Docker 守护程序的 URL |
--docker-video-image | string | selenium/video:latest | 启用视频录制时要使用的 Docker 镜像 |
--docker-host-config-keys | string[] | Dns DnsOptions DnsSearch ExtraHosts Binds | 指定应将哪些 docker 主机配置键传递给浏览器容器。可以在 Docker API 文档中找到密钥名称,或者通过运行 `docker inspect` 节点-docker 容器找到。 |
事件
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--bind-bus | boolean | false | 连接字符串应绑定还是连接。 如果为 true,则组件将绑定到事件总线(就像事件总线也将由组件启动一样,通常由分发器和中心启动)。 如果为 false,则组件将连接到事件总线。 |
--events-implementation | string | org.openqa.selenium.events.zeromq.ZeroMqEventBus | 非默认事件总线实现的完整类名 |
--publish-events | string | tcp://*:4442 | 用于将事件发布到事件总线的连接字符串 |
--subscribe-events | string | tcp://*:4443 | 用于订阅来自事件总线的事件的连接字符串 |
日志记录
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--http-logs | boolean | false | 启用 http 日志记录。应启用跟踪以记录 http 日志。 |
--log-encoding | string | UTF-8 | 日志编码 |
--log | string | Windows 路径示例'\path\to\file\gridlog.log' 或 'C:\path\path\to\file\gridlog.log' Linux/Unix/MacOS 路径示例 '/path/to/file/gridlog.log' | 用于写出日志的文件。确保文件路径与操作系统的文件路径兼容。 |
--log-level | string | “INFO” | 日志级别。默认日志级别为 INFO。日志级别在此处描述 https://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html |
--plain-logs | boolean | true | 使用纯日志行 |
--structured-logs | boolean | false | 使用结构化日志 |
--tracing | boolean | true | 启用跟踪收集 |
--log-timestamp-format | string | HH:mm:ss.SSS | 允许配置日志时间戳格式 |
网络
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--relax-checks | boolean | false | 放松对传入请求的来源标头和内容类型的检查,这违反了严格的 W3C 规范符合性。 |
节点
选项 | 类型 | 值/示例 | 描述 | |
---|---|---|---|---|
--detect-drivers | boolean | true | 自动检测当前系统上可用的驱动程序,并将它们添加到节点。 | |
--driver-configuration | string[] | display-name="Firefox Nightly" max-sessions=2 webdriver-path="/usr/local/bin/geckodriver" stereotype="{\"browserName\": \"firefox\", \"browserVersion\": \"86\", \"moz:firefoxOptions\": {\"binary\":\"/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin\"}}" | 节点支持的已配置驱动程序的列表。建议通过 toml 配置文件提供这种类型的配置,以提高可读性 | |
--driver-factory | string[] | org.openqa.selenium.example.LynxDriverFactory '{"browserName": "lynx"}' | 完全限定类名到此匹配的浏览器配置的映射。 | |
--driver-implementation | string[] | "firefox" | 应检查的驱动程序。如果指定,将跳过自动配置。 | |
--node-implementation | string | "org.openqa.selenium.grid.node.local.LocalNodeFactory" | 非默认节点实现的完整类名。这用于管理会话的生命周期。 | |
--grid-url | string | https://grid.example.com | 整个 Grid 的公共 URL(通常是中心或路由器的地址) | |
--heartbeat-period | int | 60 | 节点将向分发器发送心跳事件以告知其节点已启动的频率(以秒为单位)。 | |
--max-sessions | int | 8 | 最大并发会话数。默认值为可用处理器数。 | |
--override-max-sessions | boolean | false | 可用处理器数是建议的最大会话值(每个处理器 1 个浏览器会话)。将此标志设置为 true 允许覆盖建议的最大值。由于主机可能会耗尽资源,因此会话的稳定性和可靠性可能会受到影响。 | |
--register-cycle | int | 10 | 节点将尝试首次向分发器注册自身的频率(以秒为单位)。 | |
--register-period | int | 120 | 节点将尝试首次向分发器注册的持续时间(以秒为单位)。在此期间完成后,节点将不再尝试注册。 | |
--session-timeout | int | 300 | 设 X 为会话超时时间,单位为秒。节点将自动终止在过去 X 秒内没有任何活动的会话。这将释放插槽以供其他测试使用。 | |
--vnc-env-var | string[] | SE_START_XVFB SE_START_VNC SE_START_NO_VNC | 用于检查以确定 VNC 流是否可用的环境变量。 | |
--no-vnc-port | int | 7900 | 如果 VNC 可用,则设置本地 noVNC 流可获取的端口 | |
--drain-after-session-count | int | 1 | 在执行 X 个会话后,排空并关闭节点。这对于像 Kubernetes 这样的环境很有用。大于零的值启用此功能。 | |
--hub | string | http://localhost:4444 | 在 Hub 和 Node 配置中,Hub 的地址。可以是主机名或 IP 地址(hostname ),在这种情况下,Hub 将被假定为 http://hostname:4444 ,--grid-url 将相同,--publish-events 将为 tcp://hostname:4442 ,并且 --subscribe-events 将为 tcp://hostname:4443 。如果 hostname 包含端口号,则将用于 --grid-url ,但事件总线的 URI 将保持不变。可以通过设置正确的标志来覆盖任何这些默认值。如果主机名具有协议(例如 https ),也将使用该协议。 | |
--enable-cdp | boolean | true | 在 Grid 中启用 CDP 代理。如果网络不允许 WebSocket,则 Grid 管理员可以禁用 CDP。默认为 True。 | |
--enable-managed-downloads | boolean | false | 这将导致节点自动管理节点上给定会话下载的文件。 | |
--selenium-manager | boolean | false | 当当前系统上没有可用的驱动程序时,使用 Selenium Manager。默认为 False。 | |
--connection-limit-per-session | int | 10 | 设 X 为每个会话的最大 WebSocket 连接数。这将确保一个会话不会耗尽主机的连接限制。 |
中继器
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--service-url | string | http://localhost:4723 | 用于连接支持 WebDriver 命令的服务(如 Appium 服务器或云服务)的 URL。 |
--service-host | string | localhost | 支持 WebDriver 命令的服务正在运行的主机名 |
--service-port | int | 4723 | 支持 WebDriver 命令的服务正在运行的端口 |
--service-status-endpoint | string | /status | 可选,用于查询 WebDriver 服务状态的端点,应返回 HTTP 200 响应 |
--service-protocol-version | string | HTTP/1.1 | 可选,在与端点服务状态通信时,在 HttpClient 中强制使用特定的协议版本 |
--service-configuration | string[] | max-sessions=2 stereotype='{"browserName": "safari", "platformName": "iOS", "appium:platformVersion": "14.5"}}' | 将调用转发到的服务的配置。建议通过 toml 配置文件提供这种类型的配置,以提高可读性。 |
路由器
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--password | string | myStrongPassword | 客户端必须用来连接到服务器的密码。必须同时设置此密码和用户名才能使用。 |
--username | string | admin | 客户端必须用来连接到服务器的用户名。必须同时设置此用户名和密码才能使用。 |
--sub-path | string | my_company/selenium_grid | Hub/路由器/独立服务器上所有面向用户的路由都应考虑的子路径。 |
--disable-ui | boolean | true | 禁用 Grid UI。 |
服务器
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--external-url | string | http://10.0.1.1:33333 | 组件通常可用的外部 URL。当组件位于不同的网络并且涉及代理服务器时,在复杂的网络拓扑中非常有用。 |
--allow-cors | boolean | true | Selenium 服务器是否应允许来自任何主机的 Web 浏览器连接 |
--host | string | localhost | 服务器 IP 或主机名:通常会自动确定。 |
--bind-host | boolean | true | 服务器是否应绑定到主机地址/名称,或者仅使用它来“报告其可访问的 URL”。在复杂的网络拓扑中,当服务器无法使用当前 IP/主机名而是外部 IP 或主机名(例如在 Docker 容器内部)报告自身时,这很有帮助。 |
--https-certificate | path | /path/to/cert.pem | 用于 https 的服务器证书。运行“java -jar selenium-server.jar info security”以获取更详细的信息 |
--https-private-key | path | /path/to/key.pkcs8 | 用于 https 的私钥。运行“java -jar selenium-server.jar info security”以获取更详细的信息 |
--max-threads | int | 24 | 最大侦听器线程数。默认值为:(可用处理器)* 3。 |
--port | int | 4444 | 要监听的端口。没有默认值,因为此参数由不同的组件使用,例如,路由器/Hub/独立服务器将使用 4444,而节点将使用 5555。 |
会话队列
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--sessionqueue | uri | http://localhost:1237 | 会话队列服务器的地址。 |
-sessionqueue-host | string | localhost | 会话队列服务器正在监听的主机。 |
--sessionqueue-port | int | 1234 | 会话队列服务器正在监听的端口。 |
--session-request-timeout | int | 300 | 超时时间(秒)。新的传入会话请求将添加到队列中。在队列中等待时间超过配置时间的请求将超时。 |
--session-retry-interval | int | 5 | 重试间隔(秒)。如果所有插槽都忙,则在给定的间隔后重试新的会话请求。 |
会话
选项 | 类型 | 值/示例 | 描述 |
---|---|---|---|
--sessions | uri | http://localhost:1234 | 会话映射服务器的地址。 |
--sessions-host | string | localhost | 会话映射服务器正在监听的主机。 |
--sessions-port | int | 1234 | 会话映射服务器正在监听的端口。 |
配置示例
启动 Grid 组件时可以使用上述所有选项。它们是探索 Grid 选项并尝试各种值以找到合适配置的好方法。
我们建议使用 Toml 文件 来配置 Grid。配置文件提高了可读性,您还可以将它们检入源代码控制中。
在需要时,您可以将 Toml 文件配置与 CLI 参数结合使用。
命令行标志
要将配置选项作为命令行标志传递,请确定组件的有效选项,并遵循以下模板。
java -jar selenium-server-<version>.jar <component> --<option> value
独立服务器,设置最大会话数和主端口
java -jar selenium-server-<version>.jar standalone --max-sessions 4 --port 4444
Hub,设置新的会话请求超时、主端口并禁用跟踪
java -jar selenium-server-<version>.jar hub --session-request-timeout 500 --port 3333 --tracing false
节点,最多 4 个会话,带有调试(详细)日志,端口为 7777,并且仅使用 Firefox 和 Edge
java -jar selenium-server-<version>.jar node --max-sessions 4 --log-level "fine" --port 7777 --driver-implementation "firefox" --driver-implementation "edge"
分发器,设置会话映射服务器 URL、会话队列服务器 URL 并禁用总线
java -jar selenium-server-<version>.jar distributor --sessions http://localhost:5556 --sessionqueue http://localhost:5559 --bind-bus false
设置自定义功能以匹配特定的节点
重要提示:自定义功能需要在所有节点的配置中设置。它们还需要始终包含在每个会话请求中。
启动 Hub
java -jar selenium-server-<version>.jar hub
启动自定义 cap 设置为 true
的节点 A
java -jar selenium-server-<version>.jar node --detect-drivers false --driver-configuration display-name="Chrome (custom capability true)" max-sessions=1 stereotype='{"browserName":"chrome","gsg:customcap":true}' --port 6161
启动自定义 cap 设置为 false
的节点 B
java -jar selenium-server-<version>.jar node --detect-drivers false --driver-configuration display-name="Chrome (custom capability true)" max-sessions=1 stereotype='{"browserName":"chrome","gsg:customcap":false}' --port 6262
匹配节点 A
ChromeOptions options = new ChromeOptions();
options.setCapability("gsg:customcap", true);
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444"), options);
driver.get("https://seleniumcn.cn");
driver.quit();
将自定义功能设置为 false
以匹配节点 B。
启用节点管理的下载
有时,测试可能需要访问它在节点上下载的文件。要检索这些文件,可以执行以下操作。
启动 Hub
java -jar selenium-server-<version>.jar hub
启动启用管理下载的节点
java -jar selenium-server-<version>.jar node --enable-managed-downloads true
在测试级别设置功能
想要使用此功能的测试应将功能 "se:downloadsEnabled"
设置为 true
options.setCapability("se:downloadsEnabled", true);
这是如何工作的
- Grid 基础架构将尝试将带有
"se:downloadsEnabled"
的会话请求与仅使用--enable-managed-downloads true
启动的节点进行匹配 - 如果匹配了会话,则节点会自动设置所需的功能,以使浏览器知道应将文件下载到何处。
- 节点现在允许用户
- 列出为特定会话下载的所有文件,以及
- 从文件列表中检索特定文件。
- 当会话结束(或)由于不活动而超时时,为特定会话下载文件的目录会自动清理。
注意:目前,此功能仅在以下浏览器上受支持
Edge
Firefox
和Chrome
浏览器
列出当前会话可下载的文件
- 要从中
GET
的端点是/session/<sessionId>/se/files
。 - 会话需要处于活动状态才能使命令正常工作。
- 原始响应如下所示
{
"value": {
"names": [
"Red-blue-green-channel.jpg"
]
}
}
在响应中,文件名列表出现在键 names
下。
下载文件
- 要从中
POST
的端点是/session/<sessionId>/se/files
,有效负载的形式为{"name": "fileNameGoesHere}
- 会话需要处于活动状态才能使命令正常工作。
- 原始响应如下所示
{
"value": {
"filename": "Red-blue-green-channel.jpg",
"contents": "Base64EncodedStringContentsOfDownloadedFileAsZipGoesHere"
}
}
- 响应 blob 包含两个键,
filename
- 下载的文件名。contents
- 文件的 Base64 编码的压缩内容。
- 文件内容经过 Base64 编码,需要解压缩。
列出可以下载的文件
下面提到的 curl
示例可用于列出当前会话在节点中下载的所有文件,这些文件可以在本地检索。
curl -X GET "http://localhost:4444/session/90c0149a-2e75-424d-857a-e78734943d4c/se/files"
示例响应如下所示
{
"value": {
"names": [
"Red-blue-green-channel.jpg"
]
}
}
检索下载的文件
假设下载的文件名为 Red-blue-green-channel.jpg
,并且使用 curl
,可以使用以下命令下载该文件
curl -H "Accept: application/json" \
-H "Content-Type: application/json; charset=utf-8" \
-X POST -d '{"name":"Red-blue-green-channel.jpg"}' \
"http://localhost:4444/session/18033434-fa4f-4d11-a7df-9e6d75920e19/se/files"
示例响应如下所示
{
"value": {
"filename": "Red-blue-green-channel.jpg",
"contents": "UEsDBBQACAgIAJpagVYAAAAAAAAAAAAAAAAaAAAAUmVkLWJsAAAAAAAAAAAAUmVkLWJsdWUtZ3JlZW4tY2hhbm5lbC5qcGdQSwUGAAAAAAEAAQBIAAAAcNkAAAAA"
}
}
Java 中的完整示例代码
以下是 Java 中的一个示例,它执行以下操作
- 设置功能以指示测试需要自动管理下载的文件。
- 通过浏览器触发文件下载。
- 列出可从远程节点检索的文件(这些本质上是在当前会话中下载的文件)
- 选择一个文件并将该文件从远程节点下载到本地计算机。
import com.google.common.collect.ImmutableMap;
import org.openqa.selenium.By;
import org.openqa.selenium.io.Zip;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import java.io.File;
import java.net.URL;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import static org.openqa.selenium.remote.http.Contents.asJson;
import static org.openqa.selenium.remote.http.Contents.string;
import static org.openqa.selenium.remote.http.HttpMethod.GET;
import static org.openqa.selenium.remote.http.HttpMethod.POST;
public class DownloadsSample {
public static void main(String[] args) throws Exception {
// Assuming the Grid is running locally.
URL gridUrl = new URL("http://localhost:4444");
ChromeOptions options = new ChromeOptions();
options.setCapability("se:downloadsEnabled", true);
RemoteWebDriver driver = new RemoteWebDriver(gridUrl, options);
try {
demoFileDownloads(driver, gridUrl);
} finally {
driver.quit();
}
}
private static void demoFileDownloads(RemoteWebDriver driver, URL gridUrl) throws Exception {
driver.get("https://seleniumcn.cn/selenium/web/downloads/download.html");
// Download the two available files on the page
driver.findElement(By.id("file-1")).click();
driver.findElement(By.id("file-2")).click();
// The download happens in a remote Node, which makes it difficult to know when the file
// has been completely downloaded. For demonstration purposes, this example uses a
// 10-second sleep which should be enough time for a file to be downloaded.
// We strongly recommend to avoid hardcoded sleeps, and ideally, to modify your
// application under test, so it offers a way to know when the file has been completely
// downloaded.
TimeUnit.SECONDS.sleep(10);
//This is the endpoint which will provide us with list of files to download and also to
//let us download a specific file.
String downloadsEndpoint = String.format("/session/%s/se/files", driver.getSessionId());
String fileToDownload;
try (HttpClient client = HttpClient.Factory.createDefault().createClient(gridUrl)) {
// To list all files that are were downloaded on the remote node for the current session
// we trigger GET request.
HttpRequest request = new HttpRequest(GET, downloadsEndpoint);
HttpResponse response = client.execute(request);
Map<String, Object> jsonResponse = new Json().toType(string(response), Json.MAP_TYPE);
@SuppressWarnings("unchecked")
Map<String, Object> value = (Map<String, Object>) jsonResponse.get("value");
@SuppressWarnings("unchecked")
List<String> names = (List<String>) value.get("names");
// Let's say there were "n" files downloaded for the current session, we would like
// to retrieve ONLY the first file.
fileToDownload = names.get(0);
}
// Now, let's download the file
try (HttpClient client = HttpClient.Factory.createDefault().createClient(gridUrl)) {
// To retrieve a specific file from one or more files that were downloaded by the current session
// on a remote node, we use a POST request.
HttpRequest request = new HttpRequest(POST, downloadsEndpoint);
request.setContent(asJson(ImmutableMap.of("name", fileToDownload)));
HttpResponse response = client.execute(request);
Map<String, Object> jsonResponse = new Json().toType(string(response), Json.MAP_TYPE);
@SuppressWarnings("unchecked")
Map<String, Object> value = (Map<String, Object>) jsonResponse.get("value");
// The returned map would contain 2 keys,
// filename - This represents the name of the file (same as what was provided by the test)
// contents - Base64 encoded String which contains the zipped file.
String zippedContents = value.get("contents").toString();
// The file contents would always be a zip file and has to be unzipped.
File downloadDir = Zip.unzipToTempDir(zippedContents, "download", "");
// Read the file contents
File downloadedFile = Optional.ofNullable(downloadDir.listFiles()).orElse(new File[]{})[0];
String fileContent = String.join("", Files.readAllLines(downloadedFile.toPath()));
System.out.println("The file which was "
+ "downloaded in the node is now available in the directory: "
+ downloadDir.getAbsolutePath() + " and has the contents: " + fileContent);
}
}
}