This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/stormcrawler.git
The following commit(s) were added to refs/heads/main by this push:
new 735160ef Remove Selenium module, fixes #1994 (#2059)
735160ef is described below
commit 735160efe864ddf9b47bf21991c53f585a04adb1
Author: Julien Nioche <[email protected]>
AuthorDate: Mon Aug 17 19:20:06 2026 +0100
Remove Selenium module, fixes #1994 (#2059)
Signed-off-by: Julien Nioche <[email protected]>
---
docs/src/main/asciidoc/configuration.adoc | 9 --
docs/src/main/asciidoc/internals.adoc | 42 +++---
external/selenium/README.md | 45 ------
external/selenium/pom.xml | 106 --------------
external/selenium/selenium-conf.yaml | 41 ------
.../protocol/selenium/NavigationFilter.java | 36 -----
.../protocol/selenium/NavigationFilters.java | 116 ---------------
.../protocol/selenium/RemoteDriverProtocol.java | 137 ------------------
.../protocol/selenium/SeleniumProtocol.java | 116 ---------------
.../protocol/selenium/ProtocolTest.java | 156 ---------------------
pom.xml | 1 -
11 files changed, 22 insertions(+), 783 deletions(-)
diff --git a/docs/src/main/asciidoc/configuration.adoc
b/docs/src/main/asciidoc/configuration.adoc
index 3fc80f26..40dec13b 100644
--- a/docs/src/main/asciidoc/configuration.adoc
+++ b/docs/src/main/asciidoc/configuration.adoc
@@ -263,15 +263,6 @@ header.
| http.filter.ipaddress.include | - | (OkHttp only) Comma-separated list (or
YAML list) of allowed IP ranges. If empty, all addresses are allowed unless
excluded. See <<IP Address Filtering>>.
| http.filter.ipaddress.exclude | - | (OkHttp only) Comma-separated list (or
YAML list) of blocked IP ranges. See <<IP Address Filtering>>.
| http.trust.everything | true | If true, trust all SSL/TLS connections.
-| navigationfilters.config.file | - | JSON config for NavigationFilter (used
by the Selenium protocol module).
-| selenium.addresses | - | WebDriver server addresses.
-| selenium.capabilities | - | Desired WebDriver capabilities
-.
-| selenium.delegated.protocol | - | Delegated protocol for selective Selenium
usage.
-| selenium.implicitlyWait | 0 | WebDriver element search timeout.
-| selenium.instances.num | 1 | Number of instances per WebDriver connection.
-| selenium.pageLoadTimeout | 0 | WebDriver page load timeout.
-| selenium.setScriptTimeout | 0 | WebDriver script execution timeout.
| topology.message.timeout.secs | -1 | OKHTTP message timeout.
|===
diff --git a/docs/src/main/asciidoc/internals.adoc
b/docs/src/main/asciidoc/internals.adoc
index ab5cddeb..262e7c07 100644
--- a/docs/src/main/asciidoc/internals.adoc
+++ b/docs/src/main/asciidoc/internals.adoc
@@ -385,7 +385,7 @@ When handling HTTP redirects, StormCrawler offers three
modes:
2. **Redirects disabled** (`redirections.allowed: false`): Redirect target
URLs are not sent to the status stream. Redirects are effectively ignored.
-3. **Immediate follow** (`http.allow.redirects: true`): Redirects are followed
immediately in the HTTP client and the target URLs are not emitted to the
status stream. This is the default behavior for browser-based protocols
(Selenium and Playwright), but it is also supported by the OkHttp protocol.
Note that with immediate follows, redirect targets bypass URL filtering,
deduplication, and `robots.txt` checks.
+3. **Immediate follow** (`http.allow.redirects: true`): Redirects are followed
immediately in the HTTP client and the target URLs are not emitted to the
status stream. This is the default behavior for the browser-based Playwright
protocol, but it is also supported by the OkHttp protocol. Note that with
immediate follows, redirect targets bypass URL filtering, deduplication, and
`robots.txt` checks.
==== Network Protocols
@@ -422,36 +422,38 @@ https.protocol.implementation:
"org.apache.stormcrawler.protocol.okhttp.HttpProt
----
*
link:https://github.com/apache/stormcrawler/blob/main/core/src/main/java/org/apache/stormcrawler/protocol/httpclient/HttpProtocol.java[HttpClient]
(*deprecated* — will be removed in the next major release; use OKHttp instead)
-*
link:https://github.com/apache/stormcrawler/blob/main/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/SeleniumProtocol.java[Selenium]
*
link:https://github.com/apache/stormcrawler/blob/main/core/src/main/java/org/apache/stormcrawler/protocol/okhttp/HttpProtocol.java[OKHttp]
+*
link:https://github.com/apache/stormcrawler/blob/main/external/playwright/src/main/java/org/apache/stormcrawler/protocol/playwright/HttpProtocol.java[Playwright]
(browser-based, in the `playwright` external module)
==== Feature grid
-[cols="2,1,1,1", options="header"]
+[cols="2,1,1", options="header"]
|===
-| Features | HTTPClient | OKHttp | Selenium
-
-| Basic authentication |
link:https://github.com/apache/stormcrawler/pull/589[Y] |
link:https://github.com/apache/stormcrawler/issues/792[Y] | N
-| Proxy (w. credentials?) | Y / Y | Y /
link:https://github.com/apache/stormcrawler/issues/751[Y] | ?
-| Interruptible / trimmable
link:https://github.com/apache/stormcrawler/issues/463[#463] | N / Y | Y / Y |
Y / N
-| Cookies | Y | link:https://github.com/apache/stormcrawler/issues/632[Y] | N
-| Response headers | Y | Y | N
-| Trust all certificates | N |
link:https://github.com/apache/stormcrawler/issues/615[Y] | N
-| HEAD method | link:https://github.com/apache/stormcrawler/issues/485[Y] |
link:https://github.com/apache/stormcrawler/pull/923[Y] | N
-| POST method | N | link:https://github.com/apache/stormcrawler/issues/641[Y]
| N
-| Verbatim response header |
link:https://github.com/apache/stormcrawler/issues/317[Y] |
link:https://github.com/apache/stormcrawler/issues/506[Y] | N
-| Verbatim request header | N |
link:https://github.com/apache/stormcrawler/issues/506[Y] | N
-| IP address capture | N |
link:https://github.com/apache/stormcrawler/pull/691[Y] | N
-| Navigation and javascript | N | N | Y
-| HTTP/2 | N | Y | (Y)
-| Configurable connection pool | N |
link:https://github.com/apache/stormcrawler/issues/918[Y] | N
+| Features | HTTPClient | OKHttp
+
+| Basic authentication |
link:https://github.com/apache/stormcrawler/pull/589[Y] |
link:https://github.com/apache/stormcrawler/issues/792[Y]
+| Proxy (w. credentials?) | Y / Y | Y /
link:https://github.com/apache/stormcrawler/issues/751[Y]
+| Interruptible / trimmable
link:https://github.com/apache/stormcrawler/issues/463[#463] | N / Y | Y / Y
+| Cookies | Y | link:https://github.com/apache/stormcrawler/issues/632[Y]
+| Response headers | Y | Y
+| Trust all certificates | N |
link:https://github.com/apache/stormcrawler/issues/615[Y]
+| HEAD method | link:https://github.com/apache/stormcrawler/issues/485[Y] |
link:https://github.com/apache/stormcrawler/pull/923[Y]
+| POST method | N | link:https://github.com/apache/stormcrawler/issues/641[Y]
+| Verbatim response header |
link:https://github.com/apache/stormcrawler/issues/317[Y] |
link:https://github.com/apache/stormcrawler/issues/506[Y]
+| Verbatim request header | N |
link:https://github.com/apache/stormcrawler/issues/506[Y]
+| IP address capture | N |
link:https://github.com/apache/stormcrawler/pull/691[Y]
+| Navigation and javascript | N | N
+| HTTP/2 | N | Y
+| Configurable connection pool | N |
link:https://github.com/apache/stormcrawler/issues/918[Y]
|===
+Neither of the HTTP clients executes JavaScript: use the browser-based
link:https://github.com/apache/stormcrawler/tree/main/external/playwright[Playwright]
protocol for pages that require rendering or navigation.
+
==== HTTP/2
* The
link:https://github.com/apache/stormcrawler/blob/main/core/src/main/java/org/apache/stormcrawler/protocol/okhttp/HttpProtocol.java[OKHttp]
protocol supports link:https://en.wikipedia.org/wiki/HTTP/2[HTTP/2] if the JDK
includes
link:https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation[ALPN]
(Java 9 and upwards or Java 8 builds starting early/mid 2020).
*
link:https://github.com/apache/stormcrawler/blob/main/core/src/main/java/org/apache/stormcrawler/protocol/httpclient/HttpProtocol.java[HttpClient]
does not yet support HTTP/2.
-*
link:https://github.com/apache/stormcrawler/blob/main/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/SeleniumProtocol.java[Selenium]:
whether HTTP/2 is used or not depends on the used driver.
+*
link:https://github.com/apache/stormcrawler/blob/main/external/playwright/src/main/java/org/apache/stormcrawler/protocol/playwright/HttpProtocol.java[Playwright]:
whether HTTP/2 is used or not depends on the browser.
Since link:https://github.com/apache/stormcrawler/pull/829[#829], the HTTP
protocol version used is configurable via `http.protocol.versions` (see also
comments in
link:https://github.com/apache/stormcrawler/blob/main/core/src/main/resources/crawler-default.yaml[crawler-default.yaml]).
diff --git a/external/selenium/README.md b/external/selenium/README.md
deleted file mode 100644
index d2cbd60a..00000000
--- a/external/selenium/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Selenium Protocol for Apache StormCrawler
-
-> **⚠️ Deprecated:** The Selenium module is deprecated and will be removed in
the next major release of StormCrawler.
-
-This project provides a **[Selenium](https://www.selenium.dev/)-based protocol
implementation** for Apache StormCrawler.
-
----
-
-## Overview
-
-The [Selenium](https://www.selenium.dev) protocol allows StormCrawler to
interact with dynamic web pages using Selenium WebDriver. It is particularly
useful for crawling JavaScript-heavy sites that require a real browser
environment.
-
----
-
-## Configuration
-
-Add `selenium-conf.yaml` to your topology configuration. Below is a sample
configuration:
-
-```yaml
-# navigationfilters.config.file: "navigationfilters.json"
-# selenium.addresses: "http://localhost:9515"
-
-# Enable or disable Selenium tracing (default: false)
-selenium.tracing: false
-
-# Selenium timeouts (rely on Selenium defaults if set to -1)
-selenium.timeouts:
- script: -1 # Maximum time for scripts to run
- pageLoad: -1 # Maximum time to wait for page load
- implicit: -1 # Implicit wait time for finding elements
-
-# Selenium capabilities
-# selenium.capabilities:
-# browserName: "chrome" # Required: choose your browser
-# phantomjs.page.settings.userAgent: "$userAgent" # Example: set custom
user agent
-#
-# # ChromeDriver specific options
-# goog:chromeOptions:
-# args:
-# - "--headless" # Run Chrome in headless mode
-# - "--disable-gpu" # Disable GPU acceleration
-# - "--mute-audio" # Mute audio output
-
-
-
diff --git a/external/selenium/pom.xml b/external/selenium/pom.xml
deleted file mode 100644
index d2e5d02e..00000000
--- a/external/selenium/pom.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied. See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.stormcrawler</groupId>
- <artifactId>stormcrawler-external</artifactId>
- <version>4.0.0-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <artifactId>stormcrawler-selenium</artifactId>
- <packaging>jar</packaging>
-
- <name>stormcrawler-selenium</name>
-
<url>https://github.com/apache/stormcrawler/tree/master/external/selenium</url>
- <description>Selenium-based Protocol for StormCrawler (deprecated - will
be removed in the next major release)</description>
-
- <properties>
- <selenium.version>4.46.0</selenium.version>
- <wiremock.version>3.13.2</wiremock.version>
- <jacoco.haltOnFailure>true</jacoco.haltOnFailure>
- <jacoco.classRatio>1.00</jacoco.classRatio>
- <jacoco.instructionRatio>0.69</jacoco.instructionRatio>
- <jacoco.methodRatio>0.80</jacoco.methodRatio>
- <jacoco.branchRatio>0.62</jacoco.branchRatio>
- <jacoco.lineRatio>0.65</jacoco.lineRatio>
- <jacoco.complexityRatio>0.55</jacoco.complexityRatio>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.seleniumhq.selenium</groupId>
- <artifactId>selenium-remote-driver</artifactId>
- <version>${selenium.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.seleniumhq.selenium</groupId>
- <artifactId>selenium-support</artifactId>
- <version>${selenium.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.stormcrawler</groupId>
- <artifactId>stormcrawler-core</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.wiremock</groupId>
- <artifactId>wiremock</artifactId>
- <version>${wiremock.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.awaitility</groupId>
- <artifactId>awaitility</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.testcontainers</groupId>
- <artifactId>selenium</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.seleniumhq.selenium</groupId>
- <artifactId>selenium-chrome-driver</artifactId>
- <version>${selenium.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.testcontainers</groupId>
- <artifactId>junit-jupiter</artifactId>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
-</project>
diff --git a/external/selenium/selenium-conf.yaml
b/external/selenium/selenium-conf.yaml
deleted file mode 100644
index 83250ed7..00000000
--- a/external/selenium/selenium-conf.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-config:
- # navigationfilters.config.file: "navigationfilters.json"
- # selenium.addresses: "http://localhost:9515"
-
- selenium.tracing: false
-
- # rely on selenium's default values
- # set to a value >= 0 to override
- selenium.timeouts:
- script: -1
- pageLoad: -1
- implicit: -1
-
- # selenium.capabilities:
- # a browser name is required
- # browserName:"chrome"
- # illustrates the use of the variable for user agent
- # phantomjs.page.settings.userAgent: "$userAgent"
- # ChromeDriver config
- # goog:chromeOptions:
- # args:
- # - "--headless"
- # - "--disable-gpu"
- # - "--mute-audio"
-
-
diff --git
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/NavigationFilter.java
b/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/NavigationFilter.java
deleted file mode 100644
index 284f9ed4..00000000
---
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/NavigationFilter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.stormcrawler.protocol.selenium;
-
-import org.apache.stormcrawler.Metadata;
-import org.apache.stormcrawler.protocol.ProtocolResponse;
-import org.apache.stormcrawler.util.AbstractConfigurable;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.openqa.selenium.remote.RemoteWebDriver;
-
-/**
- * @deprecated the Selenium module is deprecated and will be removed in the
next major release of
- * StormCrawler.
- */
-@Deprecated
-public abstract class NavigationFilter extends AbstractConfigurable {
- /** The end result comes from the first filter to return non-null * */
- public abstract @Nullable ProtocolResponse filter(
- @NotNull RemoteWebDriver driver, @NotNull Metadata metadata);
-}
diff --git
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/NavigationFilters.java
b/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/NavigationFilters.java
deleted file mode 100644
index 02f1c40a..00000000
---
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/NavigationFilters.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.stormcrawler.protocol.selenium;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.stormcrawler.Metadata;
-import org.apache.stormcrawler.protocol.ProtocolResponse;
-import org.apache.stormcrawler.util.ConfUtils;
-import org.apache.stormcrawler.util.Configurable;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.openqa.selenium.remote.RemoteWebDriver;
-import org.slf4j.LoggerFactory;
-
-/**
- * Wrapper for the NavigationFilter defined in a JSON configuration.
- *
- * @see
org.apache.stormcrawler.util.Configurable#createConfiguredInstance(Class,
Class, Map,
- * JsonNode) for more information.
- * @deprecated the Selenium module is deprecated and will be removed in the
next major release of
- * StormCrawler.
- */
-@Deprecated
-public class NavigationFilters extends NavigationFilter {
-
- public static final NavigationFilters emptyNavigationFilters = new
NavigationFilters();
-
- private static final org.slf4j.Logger LOG =
LoggerFactory.getLogger(NavigationFilters.class);
-
- private NavigationFilter[] filters;
-
- private NavigationFilters() {
- filters = new NavigationFilter[0];
- }
-
- /**
- * loads the filters from a JSON configuration file
- *
- * @throws IOException
- */
- public NavigationFilters(@NotNull Map<String, Object> stormConf, @NotNull
String configFile)
- throws IOException {
- // load the JSON configFile
- // build a JSON object out of it
- JsonNode confNode;
- try (InputStream confStream =
getClass().getClassLoader().getResourceAsStream(configFile)) {
- ObjectMapper mapper = new ObjectMapper();
- confNode = mapper.readValue(confStream, JsonNode.class);
- } catch (Exception e) {
- throw new IOException("Unable to build JSON object from file", e);
- }
-
- configure(stormConf, confNode);
- }
-
- public @Nullable ProtocolResponse filter(
- @NotNull RemoteWebDriver driver, @NotNull Metadata metadata) {
- for (NavigationFilter filter : filters) {
- ProtocolResponse response = filter.filter(driver, metadata);
- if (response != null) {
- return response;
- }
- }
- return null;
- }
-
- /**
- * Loads and configure the NavigationFilters based on the storm config if
there is one otherwise
- * returns an emptyNavigationFilters.
- */
- public static NavigationFilters fromConf(@NotNull Map<String, Object>
stormConf) {
- String configfile = ConfUtils.getString(stormConf,
"navigationfilters.config.file");
- if (StringUtils.isNotBlank(configfile)) {
- try {
- return new NavigationFilters(stormConf, configfile);
- } catch (IOException e) {
- String message =
- "Exception caught while loading the NavigationFilters
from " + configfile;
- LOG.error(message);
- throw new RuntimeException(message, e);
- }
- }
-
- return NavigationFilters.emptyNavigationFilters;
- }
-
- @Override
- public void configure(@NotNull Map<String, Object> stormConf, @NotNull
JsonNode filtersConf) {
- List<NavigationFilter> filterLists =
- Configurable.createConfiguredInstance(
- this.getClass(), NavigationFilter.class, stormConf,
filtersConf);
-
- filters = filterLists.toArray(new NavigationFilter[0]);
- }
-}
diff --git
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/RemoteDriverProtocol.java
b/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/RemoteDriverProtocol.java
deleted file mode 100644
index 5ef162a1..00000000
---
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/RemoteDriverProtocol.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.stormcrawler.protocol.selenium;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.apache.storm.Config;
-import org.apache.stormcrawler.protocol.Protocol;
-import org.apache.stormcrawler.util.ConfUtils;
-import org.apache.stormcrawler.util.URLUtil;
-import org.openqa.selenium.WebDriver.Timeouts;
-import org.openqa.selenium.remote.DesiredCapabilities;
-import org.openqa.selenium.remote.RemoteWebDriver;
-
-/**
- * Delegates the requests to one or more remote selenium servers. The
processes must be started /
- * stopped separately. The URLs to connect to are specified with the config
'selenium.addresses'.
- *
- * @deprecated the Selenium module is deprecated and will be removed in the
next major release of
- * StormCrawler.
- */
-@Deprecated
-public class RemoteDriverProtocol extends SeleniumProtocol {
-
- private void substituteUserAgent(Map<String, Object> keyvals, final String
userAgentString) {
- if (keyvals == null) {
- return;
- }
-
- for (Entry<String, Object> entry : keyvals.entrySet()) {
- Object val = entry.getValue();
- // substitute variable $useragent for the real value
- if (val instanceof String &&
val.toString().contains("$useragent")) {
- String newval = ((String) val).replaceAll("\\$useragent",
userAgentString);
- entry.setValue(newval);
- } else if (val instanceof Map<?, ?>) {
- substituteUserAgent((Map<String, Object>) val,
userAgentString);
- } else if (val instanceof List<?>) {
- List<String> newList = new ArrayList<>();
- ((List<String>) val)
- .forEach(
- s -> {
- String newval =
s.replaceAll("\\$useragent", userAgentString);
- newList.add(newval);
- });
- entry.setValue(newList);
- }
- }
- }
-
- @Override
- public void configure(Config conf) {
- super.configure(conf);
-
- final String userAgentString = getAgentString(conf);
-
- // custom capabilities
- final Map<String, Object> confCapabilities =
- (Map<String, Object>) conf.get("selenium.capabilities");
-
- substituteUserAgent(confCapabilities, userAgentString);
-
- // see https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities
- final DesiredCapabilities capabilities = new DesiredCapabilities();
-
- confCapabilities.forEach((k, v) -> capabilities.setCapability(k, v));
-
- LOG.info("Configuring Selenium with {}", capabilities);
-
- // load addresses from config
- List<String> addresses =
ConfUtils.loadListFromConf("selenium.addresses", conf);
- if (addresses.size() == 0) {
- throw new RuntimeException("No value found for
selenium.addresses");
- }
-
- final boolean tracing = ConfUtils.getBoolean(conf, "selenium.tracing",
false);
-
- // TEMPORARY: draw attention to config change
- for (String p : new String[] {"implicitlyWait", "pageLoadTimeout",
"scriptTimeout"}) {
- if (conf.containsKey("selenium." + p)) {
- String message = "selenium." + p + " is deprecated. Please use
selenium.timeouts!";
- LOG.error(message);
- throw new RuntimeException(message);
- }
- }
-
- for (String cdaddress : addresses) {
- try {
- RemoteWebDriver driver =
- new RemoteWebDriver(URLUtil.toURL(cdaddress),
capabilities, tracing);
- // setting timouts
- // see
https://www.browserstack.com/guide/understanding-selenium-timeouts
- Timeouts touts = driver.manage().timeouts();
- Map<String, Number> timeouts = (Map<String, Number>)
conf.get("selenium.timeouts");
- if (timeouts != null) {
- long implicitTimeout = timeouts.getOrDefault("implicit",
-1).longValue();
- long pageLoadTimeout = timeouts.getOrDefault("pageLoad",
-1).longValue();
- long scriptTimeout = timeouts.getOrDefault("script",
-1).longValue();
- if (implicitTimeout != -1) {
-
touts.implicitlyWait(Duration.ofMillis(implicitTimeout));
- }
- if (pageLoadTimeout != -1) {
-
touts.pageLoadTimeout(Duration.ofMillis(pageLoadTimeout));
- }
- if (scriptTimeout != -1) {
- touts.scriptTimeout(Duration.ofMillis(scriptTimeout));
- }
- }
- drivers.add(driver);
- } catch (Exception e) {
- LOG.error(e.getLocalizedMessage(), e);
- }
- }
- }
-
- public static void main(String[] args) throws Exception {
- Protocol.main(new RemoteDriverProtocol(), args);
- }
-}
diff --git
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/SeleniumProtocol.java
b/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/SeleniumProtocol.java
deleted file mode 100644
index c0ce3e3e..00000000
---
a/external/selenium/src/main/java/org/apache/stormcrawler/protocol/selenium/SeleniumProtocol.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.stormcrawler.protocol.selenium;
-
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.concurrent.LinkedBlockingQueue;
-import org.apache.http.HttpHeaders;
-import org.apache.storm.Config;
-import org.apache.stormcrawler.Metadata;
-import org.apache.stormcrawler.protocol.AbstractHttpProtocol;
-import org.apache.stormcrawler.protocol.ProtocolResponse;
-import org.openqa.selenium.remote.RemoteWebDriver;
-import org.slf4j.LoggerFactory;
-
-/**
- * @deprecated the Selenium module is deprecated and will be removed in the
next major release of
- * StormCrawler.
- */
-@Deprecated
-public abstract class SeleniumProtocol extends AbstractHttpProtocol {
-
- protected static final org.slf4j.Logger LOG =
LoggerFactory.getLogger(SeleniumProtocol.class);
-
- protected LinkedBlockingQueue<RemoteWebDriver> drivers;
-
- private NavigationFilters filters;
-
- public static final String MD_KEY_START = "selenium.protocol.start";
- public static final String MD_KEY_END = "selenium.protocol.end";
-
- @Override
- public void configure(Config conf) {
- super.configure(conf);
- drivers = new LinkedBlockingQueue<>();
- filters = NavigationFilters.fromConf(conf);
- }
-
- public ProtocolResponse getProtocolOutput(String url, Metadata metadata)
throws Exception {
- RemoteWebDriver driver;
- while ((driver = getDriver()) == null) {
- // get there if there has been an interrupted exception
- // just try again
- }
- try {
- final Metadata outputMeta = new Metadata();
- outputMeta.addValue(MD_KEY_START, Instant.now().toString());
-
- // This will block for the page load and any
- // associated AJAX requests
- driver.get(url);
-
- String u = driver.getCurrentUrl();
-
- // call the filters
- ProtocolResponse response = filters.filter(driver, metadata);
- if (response != null) {
- return response;
- }
-
- // if the URL is different then we must have hit a redirection
- if (!u.equalsIgnoreCase(url)) {
- byte[] content = new byte[] {};
- Metadata m = new Metadata();
- m.addValue(HttpHeaders.LOCATION, u);
- return new ProtocolResponse(content, 307, m);
- }
-
- outputMeta.addValue(MD_KEY_END, Instant.now().toString());
-
- // if no filters got triggered
- byte[] content =
driver.getPageSource().getBytes(StandardCharsets.UTF_8);
- return new ProtocolResponse(content, 200, outputMeta);
-
- } finally {
- // finished with this driver - return it to the queue
- drivers.put(driver);
- }
- }
-
- /** Returns the first available driver * */
- private final RemoteWebDriver getDriver() {
- try {
- return drivers.take();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- return null;
- }
-
- @Override
- public void cleanup() {
- LOG.info("Cleanup called on Selenium protocol drivers");
- synchronized (drivers) {
- drivers.forEach(
- (d) -> {
- d.close();
- });
- }
- }
-}
diff --git
a/external/selenium/src/test/java/org/apache/stormcrawler/protocol/selenium/ProtocolTest.java
b/external/selenium/src/test/java/org/apache/stormcrawler/protocol/selenium/ProtocolTest.java
deleted file mode 100644
index 5e03e658..00000000
---
a/external/selenium/src/test/java/org/apache/stormcrawler/protocol/selenium/ProtocolTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.stormcrawler.protocol.selenium;
-
-import static org.awaitility.Awaitility.await;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang3.mutable.MutableBoolean;
-import org.apache.storm.Config;
-import org.apache.storm.utils.MutableObject;
-import org.apache.stormcrawler.Metadata;
-import org.apache.stormcrawler.protocol.AbstractProtocolTest;
-import org.apache.stormcrawler.protocol.ProtocolResponse;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Timeout;
-import org.openqa.selenium.chrome.ChromeOptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testcontainers.containers.BrowserWebDriverContainer;
-import
org.testcontainers.containers.BrowserWebDriverContainer.VncRecordingMode;
-import org.testcontainers.junit.jupiter.Testcontainers;
-import org.testcontainers.utility.DockerImageName;
-
-/**
- * Tests the Selenium protocol implementation on a standalone Chrome instance
and not through
- * Selenium Grid.
https://java.testcontainers.org/modules/webdriver_containers/#example
- */
-@Testcontainers(disabledWithoutDocker = true)
-class ProtocolTest extends AbstractProtocolTest {
-
- private static final Logger LOG =
LoggerFactory.getLogger(ProtocolTest.class);
-
- private static final DockerImageName SELENIUM_IMAGE =
- DockerImageName.parse("seleniarm/standalone-chromium:124.0")
- .asCompatibleSubstituteFor("selenium/standalone-chrome");
-
- private BrowserWebDriverContainer<?> chrome =
- new BrowserWebDriverContainer<>(SELENIUM_IMAGE)
- .withCapabilities(new ChromeOptions())
- .withRecordingMode(VncRecordingMode.SKIP, null)
- .withAccessToHost(true)
- .withExtraHost("website.test", "host-gateway");
-
- public RemoteDriverProtocol getProtocol() {
- LOG.info(
- "Configuring protocol instance to connect to {}",
- chrome.getSeleniumAddress().toExternalForm());
- List<String> l = new ArrayList<>();
- // l.add("--no-sandbox");
- // l.add("--disable-dev-shm-usage");
- // l.add("--headless");
- // l.add("--disable-gpu");
- // l.add("--remote-allow-origins=*");
- Map<String, Object> m = new HashMap<>();
- m.put("args", l);
- // m.put("extensions", Collections.EMPTY_LIST);
- Map<String, Object> capabilities = new HashMap<>();
- capabilities.put("browserName", "chrome");
- capabilities.put("goog:chromeOptions", m);
- Config conf = new Config();
- conf.put("http.agent.name", "this_is_only_a_test");
- conf.put("selenium.addresses",
chrome.getSeleniumAddress().toExternalForm());
- Map<String, Object> timeouts = new HashMap<>();
- timeouts.put("implicit", 10000);
- timeouts.put("pageLoad", 10000);
- timeouts.put("script", 10000);
- conf.put("selenium.timeouts", timeouts);
- conf.put("selenium.capabilities", capabilities);
- RemoteDriverProtocol protocol = new RemoteDriverProtocol();
- protocol.configure(conf);
- return protocol;
- }
-
- @BeforeEach
- void init() {
- chrome.start();
- }
-
- /**
- * you can configure one instance of Selenium to talk to multiple drivers
but can't have a
- * multiple instances of the protocol. If there is only one instance and
one target, you must
- * wait...
- */
- @Test
- @Timeout(value = 2, unit = TimeUnit.MINUTES)
- void testBlocking() {
- RemoteDriverProtocol protocol = getProtocol();
- MutableBoolean noException = new MutableBoolean(true);
- MutableObject endTimeFirst = new MutableObject();
- MutableObject startTimeSecond = new MutableObject();
- await().until(() -> httpServer.isRunning());
- final String url = "http://website.test" + ":" + HTTP_PORT + "/";
- new Thread(
- () -> {
- try {
- ProtocolResponse response =
- protocol.getProtocolOutput(url, new
Metadata());
- endTimeFirst.setObject(
- Instant.parse(
- response.getMetadata()
- .getFirstValue(
-
SeleniumProtocol.MD_KEY_END)));
- } catch (Exception e) {
- noException.setValue(false);
- }
- })
- .start();
- new Thread(
- () -> {
- try {
- ProtocolResponse response =
- protocol.getProtocolOutput(url, new
Metadata());
- startTimeSecond.setObject(
- Instant.parse(
- response.getMetadata()
- .getFirstValue(
-
SeleniumProtocol.MD_KEY_START)));
- } catch (Exception e) {
- noException.setValue(false);
- }
- })
- .start();
- await().until(
- () ->
- endTimeFirst.getObject() != null
- && startTimeSecond.getObject() !=
null);
- Instant etf = (Instant) endTimeFirst.getObject();
- Instant sts = (Instant) startTimeSecond.getObject();
- // check that the second call started AFTER the first one finished
- Assertions.assertTrue(etf.isBefore(sts));
- Assertions.assertTrue(noException.booleanValue());
- protocol.cleanup();
- }
-}
diff --git a/pom.xml b/pom.xml
index 65f2a1e2..2277cd27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -724,7 +724,6 @@ under the License.
<module>external/opensearch</module>
<module>external/opensearch-java</module>
<module>external/playwright</module>
- <module>external/selenium</module>
<module>external/solr</module>
<module>external/sql</module>
<module>external/tika</module>