ashbythorpe / selenium-r

Low-Level Browser Automation Interface
https://ashbythorpe.github.io/selenium-r/
Other
17 stars 1 forks source link

Failed to connect to localhost port 4444 #5

Closed ozanozbeker closed 5 months ago

ozanozbeker commented 6 months ago

Hi, I'm not sure what might have changed since I last used the package (really {selenider}) but I can't seem to create a new Selenium session using Google Chrome anymore. I have this issue across multiple devices. I encountered this problem first using {selenider}:

library(selenider)

session = selenider_session(
  session = 'selenium',
  browser = 'chrome',
  options = selenium_options(
    client_options = selenium_client_options(
      capabilities = list(
        'goog:chromeOptions' = list(
          extensions = list(
            base64enc::base64encode("Resources/helium10_xray_extension_8.0.7_0.crx")
          )
        )
      )
    )
  )
)

and have been able to reproduce it with {selenium} directly:

library(selenium)

server = selenium_server()
session = SeleniumSession$new(browser = 'chrome')

I don't get this error when I use chromote so I believe it has to do with Selenium. I'm using the latest version of Java 8.

Here is the full error message when using {selenium}:

R> rlang::last_trace()
<error/httr2_failure>
Error in `httr2::req_perform()`:
! Failed to perform HTTP request.
Caused by error in `curl::curl_fetch_memory()`:
! Failed to connect to localhost port 4444 after 2244 ms: Couldn't connect to server
---
Backtrace:
    ▆
 1. └─SeleniumSession$new(browser = "chrome")
 2.   └─selenium (local) initialize(...)
 3.     └─selenium:::req_perform_selenium(...)
 4.       └─httr2::req_perform(req)
 5.         └─base::tryCatch(...)
 6.           └─base (local) tryCatchList(expr, classes, parentenv, handlers)
 7.             └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
 8.               └─value[[3L]](cond)

I wasn't sure if it was a port issue, so I tried again using netstat::free_port() but I still get the same error:

session_port = free_port()

session = selenider_session(
  session = 'selenium',
  browser = 'chrome',
  options = selenium_options(
    client_options = selenium_client_options(
      port = session_port,
      capabilities = list(
        'goog:chromeOptions' = list(
          extensions = list(
            base64enc::base64encode("Resources/helium10_xray_extension_8.0.7_0.crx")
          )
        )
      )
    ),
    server_options = selenium_server_options(
      port = session_port
    )
  )
)

Error message:

R> rlang::last_trace(drop = FALSE)
<error/selenider_error_selenium_server>
Error in `create_selenium_client_internal()`:
! We could not connect to a Selenium Server instance after 20 seconds.
Caused by error in `selenium::wait_for_selenium_available()`:
! Timed out waiting for selenium server to start
---
Backtrace:
     ▆
  1. ├─selenider::selenider_session(...)
  2. │ └─selenider:::get_driver(...)
  3. │   ├─selenider:::skip_error_if_testing(...)
  4. │   └─selenider:::create_selenium_client_internal(browser, options$client_options)
  5. │     ├─rlang::try_fetch(...)
  6. │     │ ├─base::tryCatch(...)
  7. │     │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
  8. │     │ │   └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
  9. │     │ │     └─base (local) doTryCatch(return(expr), name, parentenv, handler)
 10. │     │ └─base::withCallingHandlers(...)
 11. │     └─selenium::wait_for_selenium_available(...)
 12. │       └─rlang::abort(...)
 13. │         └─rlang:::signal_abort(cnd, .file)
 14. │           └─base::signalCondition(cnd)
 15. └─rlang (local) `<fn>`(`<rlng_rrr>`)
 16.   └─handlers[[1L]](cnd)
 17.     └─selenider:::stop_connect_selenium_server(timeout = 20, error = e)
 18.       └─cli::cli_abort(...)
 19.         └─rlang::abort(...)
---
Caused by error in `httr2::req_perform()`:
! Failed to perform HTTP request.
Caused by error in `curl::curl_fetch_memory()`:
! Failed to connect to localhost port 14415 after 2223 ms: Couldn't connect to server
---
Backtrace:
     ▆
  1. └─selenider::selenider_session(...)
  2.   └─selenider:::get_driver(...)
  3.     ├─selenider:::skip_error_if_testing(...)
  4.     └─selenider:::create_selenium_client_internal(browser, options$client_options)
  5.       ├─rlang::try_fetch(...)
  6.       │ ├─base::tryCatch(...)
  7.       │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
  8.       │ │   └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
  9.       │ │     └─base (local) doTryCatch(return(expr), name, parentenv, handler)
 10.       │ └─base::withCallingHandlers(...)
 11.       └─selenium::wait_for_selenium_available(timeout = 20, port = options$port, host = options$host, error = TRUE)
 12.         ├─rlang::try_fetch(...)
 13.         │ ├─base::tryCatch(...)
 14.         │ │ └─base (local) tryCatchList(expr, classes, parentenv, handlers)
 15.         │ │   └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
 16.         │ │     └─base (local) doTryCatch(return(expr), name, parentenv, handler)
 17.         │ └─base::withCallingHandlers(...)
 18.         └─selenium::get_server_status(...)
 19.           └─selenium:::get_status(req, verbose = verbose, timeout = timeout)
 20.             └─selenium:::req_perform_selenium(req, verbose = verbose, timeout = timeout)
 21.               └─httr2::req_perform(req)
 22.                 └─base::tryCatch(...)
 23.                   └─base (local) tryCatchList(expr, classes, parentenv, handlers)
 24.                     └─base (local) tryCatchOne(expr, names, parentenv, handlers[[1L]])
 25.                       └─value[[3L]](cond)

Let me know if I can provide anything else to help with this.

ozanozbeker commented 6 months ago

So I tried to use {RSelenium} and at first I think I actually got the same issue:

R> # Start Server
R> rsD = rsDriver(
+>   port = free_port(),
+>   browser = 'chrome',
+>   version = 'latest',
+>   chromever = 'latest',
+>   verbose = TRUE,
+>   check = TRUE,
+>   extraCapabilities = list(
+>     chromeOptions = list(
+>       extensions = list(
+>         base64enc::base64encode("Resources/helium10_xray_extension_8.0.7_0.crx")
+>       )
+>     )
+>   )
+> )
Warning in rsDriver(port = free_port(), browser = "chrome", version = "latest",  :
  Could not determine server status.
[1] "Connecting to remote server"
Could not open chrome browser.
Client error message:
Undefined error in httr call. httr output: Failed to connect to localhost port 14415 after 2243 ms: Couldn't connect to server
Check server log for further details.

I realized after a bit that I hadn't deleted the LICENSE.chromedriver file, and then that the chromedriver binman downloaded did not match my Chrome version. Once those got fixed, {RSelenium} was able to run. I tried to use {selenider} after but still ran into the original issue, so I don't think it's directly Java or Selenium related.

ashbythorpe commented 6 months ago

If you are using selenium, you need to wait for the selenium server to start before running SeleniumSession$new(), e.g.:

library(selenium)

server <- selenium_server()

wait_for_selenium_available(error = TRUE)

session <- SeleniumSession$new()

I might just add this functionality to the selenium_server() function by default.

The "could not connect to server" message just means that there isn't a server instance running.

However, selenider should do this waiting automatically, so I don't know why that isn't working. My best guess is it's just a timeout issue: the server takes more than 20 seconds to start. If that's the case, then the above code snippet should not work, since wait_for_selenium_available() waits 20 seconds by default. If you get the same error from the above code, can you try running it with different values of timeout passed into wait_for_selenium_available() (e.g. 60)? If that's the issue, I'll probably change the default timeout in selenider to 60, and allow this value to be configured in selenium_client_options().

If that still doesn't work, can you share the output of server$read_output() and server$read_error()?

ozanozbeker commented 6 months ago

Here is my output:

R> wait_for_selenium_available(error = TRUE)
Error in `wait_for_selenium_available()`:
! Timed out waiting for selenium server to start
Caused by error in `httr2::req_perform()`:
! Failed to perform HTTP request.
Caused by error in `curl::curl_fetch_memory()`:
! Failed to connect to localhost port 4444 after 2243 ms: Couldn't connect to server
Run `rlang::last_trace()` to see where the error occurred.
R> ?wait_for_selenium_available
R> wait_for_selenium_available(error = TRUE, timeout = 60)
Error in `wait_for_selenium_available()`:
! Timed out waiting for selenium server to start
Caused by error in `httr2::req_perform()`:
! Failed to perform HTTP request.
Caused by error in `curl::curl_fetch_memory()`:
! Failed to connect to localhost port 4444 after 2248 ms: Couldn't connect to server
Run `rlang::last_trace()` to see where the error occurred.
R> server$read_output()
[1] ""
R> server$read_error()
[1] "Exception in thread \"main\" java.lang.UnsupportedClassVersionError: org/openqa/selenium/grid/Bootstrap has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0\r\n\tat java.lang.ClassLoader.defineClass1(Native Method)\r\n\tat java.lang.ClassLoader.defineClass(Unknown Source)\r\n\tat java.security.SecureClassLoader.defineClass(Unknown Source)\r\n\tat java.net.URLClassLoader.defineClass(Unknown Source)\r\n\tat java.net.URLClassLoader.access$100(Unknown Source)\r\n\tat java.net.URLClassLoader$1.run(Unknown Source)\r\n\tat java.net.URLClassLoader$1.run(Unknown Source)\r\n\tat java.security.AccessController.doPrivileged(Native Method)\r\n\tat java.net.URLClassLoader.findClass(Unknown Source)\r\n\tat java.lang.ClassLoader.loadClass(Unknown Source)\r\n\tat sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)\r\n\tat java.lang.ClassLoader.loadClass(Unknown Source)\r\n\tat sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)\r\n"

I'm using the current version of Java Version 8 Update 401 (Jan 16, 2024) from the java.com, would it help to use JDK instead?

ashbythorpe commented 5 months ago

Yeah, the error seems to suggest that your version of Java is outdated. RSelenium uses a much older version of Selenium server, so it makes sense that you wouldn't see this issue with that package.

This article suggests that Java 8 is not supported: https://www.selenium.dev/blog/2023/java-8-support/

ozanozbeker commented 5 months ago

So the Java website defers to Java 8 for consumer usage. Using JDK 17, I had no issues. The installation section of the {selenider} docs links to Java 8 for use with Selenium so that might need updated. Also, it took about 8 seconds for the session to initialize, so the default 20 seconds is probably still okay for future use. Thanks for the assistance!