RSelenium icon indicating copy to clipboard operation
RSelenium copied to clipboard

RSelenium::rsDriver() should auto-detect proper ChromeDriver if `browser = "chrome"`

Open salim-b opened this issue 4 years ago • 20 comments

This is a suggestion to auto-detect the proper ChromeDriver version because it happens regularly that the default setting chromever = "latest" selects a ChromeDriver version that's ahead of the current stable Chrome browser version.

I'd suggest something like the following to select the latest ChromeDriver version matching the major-minor-patch version number of the system's stable Google Chrome browser:

# Get installed stable Google Chrome version ...
if (xfun::is_unix()) {

  chrome_driver_version <-
    system2(command = ifelse(xfun::is_macos(),
                             "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
                             "google-chrome-stable"),
            args = "--version",
            stdout = TRUE,
            stderr = TRUE) %>%
    stringr::str_extract(pattern = "(?<=Chrome )(\\d+\\.){3}")
  
  ## on Windows a plattform-specific bug prevents us from calling the Google Chrome binary directly to get its version number
  ## cf. https://bugs.chromium.org/p/chromium/issues/detail?id=158372
} else if (xfun::is_windows()) {

  chrome_driver_version <-
    system2(command = "wmic",
            args = 'datafile where name="C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe" get Version /value',
            stdout = TRUE,
            stderr = TRUE) %>%
    stringr::str_extract(pattern = "(?<=Version=)(\\d+\\.){3}")
  
} else rlang::abort(message = "Your OS couldn't be determined (Linux, macOS, Windows) or is not supported.")

# ... and determine most recent ChromeDriver version matching it
chrome_driver_version %<>%
  magrittr::extract(!is.na(.)) %>%
  stringr::str_replace_all(pattern = "\\.",
                           replacement = "\\\\.") %>%
  paste0("^",  .) %>%
  stringr::str_subset(string =
                        binman::list_versions(appname = "chromedriver") %>%
                        dplyr::last()) %>%
  as.numeric_version() %>%
  max() %>%
  as.character()

This procedure should adhere to the official ChromeDriver versioning scheme. Quote:

  • ChromeDriver uses the same version number scheme as Chrome (...)
  • Each version of ChromeDriver supports Chrome with matching major, minor, and build version numbers. For example, ChromeDriver 73.0.3683.20 supports all Chrome versions that start with 73.0.3683.

Ideally, we'd check if Chrome is available on the system at all before running system2() and also take the open-source Chromium into consideration (make it conditional on param browser).

salim-b avatar Dec 14 '19 01:12 salim-b

@juyeongkim Any comment on this?

I'd be willing to prepare a PR if you would provide some implementaion guidance (i.a. what pkgs I can use)...

salim-b avatar Jan 16 '20 11:01 salim-b

Thanks for putting this together. It doesn't quite work on my MacOS system: because system2() calls shQuote on the command argument, you shouldn't escape the spaces. Once that is fixed, it does appear to work.

dmurdoch avatar Jun 30 '20 23:06 dmurdoch

It doesn't quite work on my MacOS system: because system2() calls shQuote on the command argument, you shouldn't escape the spaces. Once that is fixed, it does appear to work.

Thanks for the reminder! I've updated the first post accordingly.

salim-b avatar Jul 05 '20 19:07 salim-b

Any developments on this issue? Having just run into this problem, then finding this issue, this looks like it would be an extremely valuable addition to RSelenium.

josswright avatar Oct 16 '20 08:10 josswright

I've been using Salim's solution, and it's been working fine on MacOS.

dmurdoch avatar Oct 16 '20 14:10 dmurdoch

Ah, I had the impression that the suggestion was to roll this solution into the rsDriver() code itself.

josswright avatar Oct 17 '20 13:10 josswright

Ah, I had the impression that the suggestion was to roll this solution into the rsDriver() code itself.

That was the idea when I filed this issue. But I've never heard back from @juyeongkim (or another project member)...

The code outlined above is not perfect. For example, we shouldn't rely on binman::list_versions() since it just returns an error in case of a fresh install where no ChromeDriver versions had been downloaded before. Instead, https://chromedriver.storage.googleapis.com/index.html should be parsed directly.

salim-b avatar Oct 17 '20 17:10 salim-b

I'd just go ahead and prepare the PR, using your own judgment about what to use. At a minimum, that would make it easier for others to incorporate your suggestion (by forking) if the maintainer doesn't act on it.

dmurdoch avatar Oct 17 '20 19:10 dmurdoch

I'd just go ahead and prepare the PR (...)

I've submitted #237. Until it gets merged (if at all), you can install it with

remotes::install_github("ropensci/RSelenium#237")

Then you can call rsDriver() with the new chromever = "latest_compatible" option like this:

RSelenium::rsDriver(browser = "chrome",
                    chromever = "latest_compatible")

Feedback welcome! I've only tested it on Linux so far but it should work on macOS and Windows since the code is based on earlier feedback from users of these systems (i.a. @dmurdoch 😄).

salim-b avatar Oct 18 '20 22:10 salim-b

Hi, @salim-b . Your solution, unfortunately throws an error for me. The error is as follows:

Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  : 
  arguments imply differing number of rows: 1, 0

The details of my system are:

    _                           
platform       x86_64-w64-mingw32          
arch           x86_64                      
os             mingw32                     
system         x86_64, mingw32             
status                                     
major          4                           
minor          0.2                         
year           2020                        
month          06                          
day            22                          
svn rev        78730                       
language       R                           
version.string R version 4.0.2 (2020-06-22)
nickname       Taking Off Again            

I'm running Windows Server 2019, Version 1809, OS Build, 17763.1518. Chrome seems to launch however, but the error message is thrown nonetheless.

Any ideas how to fix this?

mlamias avatar Nov 03 '20 08:11 mlamias

@mlamias Are you sure the error you've posted originates from launching rsDriver()?

What happens if you just enter the following into an R prompt:

rd <- RSelenium::rsDriver(browser = "chrome",
                          chromever = "latest_compatible")

rd$client$close()
rd$server$stop()

salim-b avatar Nov 03 '20 13:11 salim-b

@salim-b, thanks for your help. Indeed I have my code working now. I'm not sure what happened, but it seemed once I bounced our server the error resolved itself. I absolutely love this solution and saves me lots of headaches. Consider my issues resolved.

Thanks again! Great piece of code!

mlamias avatar Nov 09 '20 22:11 mlamias

remotes::install_github("ropensci/RSelenium#237") doesn't work for me to get the intermediate fix.

traceback() results in the following: 6: stop("Cannot find GitHub pull request ", params$username, "/", params$repo, "#", x, "\n", response$message) 5: github_resolve_ref.github_pull(meta$ref %||% ref, meta, host = host, auth_token = auth_token) 4: github_resolve_ref(meta$ref %||% ref, meta, host = host, auth_token = auth_token) 3: FUN(X[[i]], ...) 2: lapply(repo, github_remote, ref = ref, subdir = subdir, auth_token = auth_token, host = host) 1: remotes::install_github("ropensci/RSelenium#237")

If I run your entire code, the code itself doesn't throw any errors. However, calling rD <- rsDriver(browser=c("chrome"), chromever="latest_compatible", port = 4444L) results in checking Selenium Server versions: BEGIN: PREDOWNLOAD BEGIN: DOWNLOAD BEGIN: POSTDOWNLOAD checking chromedriver versions: BEGIN: PREDOWNLOAD BEGIN: DOWNLOAD BEGIN: POSTDOWNLOAD Error in chrome_ver(chromecheck[["platform"]], chromever) : version requested doesnt match versions available = 2.28,2.29,2.30,80.0.3987.106,81.0.4044.138,81.0.4044.20,81.0.4044.69,83.0.4103.14,83.0.4103.39,84.0.4147.30,85.0.4183.38,85.0.4183.83,85.0.4183.87,86.0.4240.22,87.0.4280.20,87.0.4280.88,88.0.4324.27

I'm having the issue this pull request is meant to fix: My installed Chrome version is 87.0.4280.88 but RSelenium appears to be using version 8, which is unstable.

Any advice?

adrearlystate avatar Jan 06 '21 19:01 adrearlystate

If I follow those instructions it doesn't work for me either, but I've been using the code below based on the PR, and it works fine with the CRAN version of RSelenium:

rsStuff <- local({
  rD <- NULL
  driver <- function(port = 4567L, force = FALSE, verbose = FALSE) {
    if (force)
      rD <<- NULL
    if (!is.null(rD))
      return(rD)
    versions <- binman::list_versions("chromedriver")
    versions <- c(versions$mac64, getChromeDriverVersion(versions))
    v <- length(versions) + 1
    while (v && (is.null(rD) || inherits(rD, "condition"))) {
      v <- v - 1  # Try each value
      rD <<- tryCatch(rsDriver(verbose = verbose, 
                               port = port + sample(0:1000, 1), 
                               chromever=versions[v],
                               geckover = NULL, 
                               phantomver = NULL), error = function(e) e,
                               message = function(m) m)
    }
    rD
  }
  kill <- function() {
    try(rD$server$stop())
    rD <<- NULL
  }
  list(driver = driver, kill = kill)
})

getrsDriver <- rsStuff$driver
killrsDriver <- rsStuff$kill
rm(rsStuff)

The idea is that I set remDr <- getrsDriver()$client, and it works for me. There seems to be a bug in RSelenium; if I try to print getrsDriver(), it dies with this error:

> getrsDriver()
$client
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  : 
  arguments imply differing number of rows: 1, 0

dmurdoch avatar Jan 06 '21 20:01 dmurdoch

This is very frustrating (it worked just yesterday!) - but thank you for lending a hand.

When I use your code and call remDr <- getrsDriver()$client, I get the following:

Error in getChromeDriverVersion(versions) : 
  could not find function "getChromeDriverVersion"

It seems like you might be on a Mac. Does that make a difference?

adrearlystate avatar Jan 06 '21 23:01 adrearlystate

Sorry, I forgot that was part of my code. Here it is:

getChromeDriverVersion <- function(versions = binman::list_versions("chromedriver")) {
  if ( xfun::is_unix() ) {
    chrome_driver_version <-
      system2(command = ifelse(xfun::is_macos(),
                               "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
                               "google-chrome-stable"),
              args = "--version",
              stdout = TRUE,
              stderr = TRUE) %>%
      stringr::str_extract(pattern = "(?<=Chrome )(\\d+\\.){3}")
    
    ## on Windows a plattform-specific bug prevents us from calling the Google Chrome binary directly to get its version number
    ## cf. https://bugs.chromium.org/p/chromium/issues/detail?id=158372
  } else if ( xfun::is_windows() ) {
    chrome_driver_version <-
      system2(command = "wmic",
              args = 'datafile where name="C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe" get Version /value',
              stdout = TRUE,
              stderr = TRUE) %>%
      stringr::str_extract(pattern = "(?<=Version=)(\\d+\\.){3}")
    
  } else rlang::abort(message = "Your OS couldn't be determined (Linux, macOS, Windows) or is not supported!")
  
  # ... and determine most recent ChromeDriver version matching it
  chrome_driver_version %>%
    magrittr::extract(!is.na(.)) %>%
    stringr::str_replace_all(pattern = "\\.",
                             replacement = "\\\\.") %>%
    paste0("^",  .) %>%
    stringr::str_subset(string = dplyr::last(versions)) %>%
    as.numeric_version() %>%
    max() %>%
    as.character()
}

dmurdoch avatar Jan 07 '21 00:01 dmurdoch

That works! Very, very much appreciate it!

adrearlystate avatar Jan 07 '21 00:01 adrearlystate

traceback() results in the following: 6: stop("Cannot find GitHub pull request ", params$username, "/", params$repo, "#", x, "\n", response$message) 5: github_resolve_ref.github_pull(meta$ref %||% ref, meta, host = host, auth_token = auth_token) 4: github_resolve_ref(meta$ref %||% ref, meta, host = host, auth_token = auth_token) 3: FUN(X[[i]], ...) 2: lapply(repo, github_remote, ref = ref, subdir = subdir, auth_token = auth_token, host = host) 1: remotes::install_github("#237")

(...)

Any advice?

The error message above seems to indicate you tried to install my PR branch's RSelenium version with remotes::install_github("#237") instead of remotes::install_github("ropensci/RSelenium#237") ... ?

But anyways, technically remotes::install_github("ropensci/RSelenium#237") should be equivalent to remotes::install_github(repo = "salim-b/RSelenium", ref = "chromedriver-detection"). Does the latter work? (Maybe the "repo#ref" syntax was introduced only recently to the remotes::install_* functions and your local version of the package is outdated?)

salim-b avatar Jan 07 '21 11:01 salim-b

I was encountering an error about "SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 91"

Commenting to confirm that remotes::install_github("ropensci/RSelenium#237") fixed this error running Chrome Version 90.0.4430.85 (Official Build) (64-bit) (V 91 is still in beta) and is working with this session configuration:

R version 4.0.2 (2020-06-22)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
[1] Rideshare2Vote_0.0.0.9000 RevoUtils_11.0.2         
[3] RevoUtilsMath_11.0.0     

loaded via a namespace (and not attached):
 [1] xfun_0.22            tidyselect_1.1.0     remotes_2.2.0       
 [4] purrr_0.3.4          vctrs_0.3.6.9000     generics_0.1.0      
 [7] testthat_3.0.1       usethis_1.6.3        yaml_2.2.1          
[10] utf8_1.2.1           blob_1.2.1           XML_3.99-0.6        
[13] rlang_0.4.10         pkgbuild_1.2.0       pillar_1.5.1        
[16] glue_1.4.2           withr_2.3.0          DBI_1.1.1           
[19] rappdirs_0.3.3       semver_0.2.0         sessioninfo_1.1.1   
[22] lifecycle_1.0.0      stringr_1.4.0        binman_0.1.2        
[25] devtools_2.3.2       caTools_1.18.2       memoise_1.1.0       
[28] wdman_0.2.5          callr_3.5.1          ps_1.6.0            
[31] curl_4.3             fansi_0.4.2          Rcpp_1.0.6          
[34] clipr_0.7.1          readr_1.4.0          openssl_1.4.3       
[37] desc_1.2.0           pkgload_1.1.0        jsonlite_1.7.2      
[40] RSelenium_1.7.7.9000 debugme_1.1.0        fs_1.5.0            
[43] hms_0.5.3            askpass_1.1          digest_0.6.27       
[46] stringi_1.5.3        processx_3.5.1       dplyr_1.0.5         
[49] rprojroot_2.0.2      cli_2.3.1            tools_4.0.2         
[52] bitops_1.0-6         magrittr_2.0.1       tibble_3.1.0        
[55] crayon_1.4.1         tidyr_1.1.3          pkgconfig_2.0.3     
[58] ellipsis_0.3.1       xml2_1.3.2           prettyunits_1.1.1   
[61] assertthat_0.2.1     httr_1.4.2           rstudioapi_0.13     
[64] R6_2.5.0             compiler_4.0.2 

Thank you @salim-b!

yogat3ch avatar Apr 23 '21 17:04 yogat3ch

Circling back to this because it looks like available ChromeDriver versions and available Chrome versions (92.0.4515.159) have de-synchronized making it such that there's no way to run RSelenium with Chrome (unless you happen to have a legacy version of Chrome).

Does anyone have a Chrome 32-bit installation MSI compatible with either of the current chromeDriver versions?

  • Latest beta release: ChromeDriver 93.0.4577.15

  • Latest stable release: ChromeDriver 92.0.4515.107

yogat3ch avatar Aug 27 '21 18:08 yogat3ch