【问题标题】:How to use Selenium chromedriver without being forced to update?如何在不强制更新的情况下使用 Selenium chromedriver?
【发布时间】:2023-03-20 09:54:01
【问题描述】:

我一直在 nwjs/node.js 中开发一个浏览器自动化应用程序,它使用数据驱动的 DSL 指令。

我决定通过我的 package.json 中的以下依赖项为 chromedriver 和 selenium webdriver 使用 npm 包:

  "dependencies": {
    "selenium-webdriver": "~3.0.0-beta-2",
    "chromedriver": "~2.23.1"
  }

一切都很顺利,直到最近应用程序在启动 chromedriver 时停止工作:

var webdriver = require("selenium-webdriver");
var driver = new webdriver.Builder().forBrowser('chrome').build();

以下是在我的 Macbook 上终端运行时出现的错误:

/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/promise.js:654
    throw error;
    ^

SessionNotCreatedError: session not created exception
from unknown error: Runtime.evaluate missing 'wasThrown'
  (Session info: chrome=54.0.2840.71)
  (Driver info: chromedriver=2.23.409710 (0c4084804897ac45b5ff65a690ec6583b97225c0),platform=Mac OS X 10.11.5 x86_64)
    at WebDriverError (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/error.js:27:5)
    at SessionNotCreatedError (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/error.js:214:5)
    at Object.checkLegacyResponse (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/error.js:505:15)
    at parseHttpResponse (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/http.js:396:13)
    at doSend.then.response (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/http.js:328:11)
    at process._tickCallback (internal/process/next_tick.js:103:7)
From: Task: WebDriver.createSession()
    at Function.createSession (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/webdriver.js:366:24)
    at Driver (/Users/matthewsanders/test1/node_modules/selenium-webdriver/chrome.js:804:38)
    at Builder.build (/Users/matthewsanders/test1/node_modules/selenium-webdriver/index.js:546:16)
    at Object.<anonymous> (/Users/matthewsanders/test1/index.js:4:59)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.runMain (module.js:590:10)
From: Task: WebDriver.navigate().to(http://www.google.com)
    at Driver.schedule (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/webdriver.js:414:17)
    at Navigation.to (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/webdriver.js:1042:25)
    at Driver.get (/Users/matthewsanders/test1/node_modules/selenium-webdriver/lib/webdriver.js:832:28)
    at Object.<anonymous> (/Users/matthewsanders/test1/index.js:6:8)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.runMain (module.js:590:10)

我还针对我当时制作的几个测试应用程序进行了测试,以确保这不是我在项目中引入的问题。

然后我在下载geckodriver 后尝试在forBrowser 方法中使用“firefox”,效果很好。

看起来好像 chromedriver 的某种自动更新破坏了我的项目。我注意到有关 stackoverflow 的其他几个与类似错误相关的问题,尽管没有一个包含 Runtime.evaluate missing 'wasThrown' 错误,这似乎表明我的理论可能是正确的。

可以直接切换到 geckodriver,但我不确定我是否会遇到类似的问题。

我想这里真正的问题是......

如何禁用自动更新以保持此应用程序作为独立项目运行?

同样,这并不是一个不断更新的测试套件,而是一个由自定义语言驱动的浏览器自动化应用程序。它既可以通过托管的 node.js 实例作为自动化解决方案运行,也可以作为运行 nwjs 的操作员驱动的 gui 应用程序运行。

编辑:

到目前为止,我已经找到了一种很有前途的方法。如果我觉得它符合我的喜好,我会添加一个答案。

Selenium Documentation 包含有关如何自定义 chromedriver 选项的信息。我已经下载了Chromium 的一个版本并使用这个逻辑来连接它:

var chrome = require("selenium-webdriver/chrome");
var service = new chrome.ServiceBuilder().build();

var options = new chrome.Options();
options.setChromeBinaryPath("PATH/TO/MY/CHROMIUM");

var driver = new chrome.Driver(options, service);

注意:在 mac 上,您必须提供应用程序包中实际可执行文件的路径,例如:'Chromium.app/Contents/MacOS/Chromium'。

到目前为止,我使用的是 Chromium 而不是 Chrome,版本仍然不正确,但我确实验证了它与我在没有设置路径的情况下运行的不同。从理论上讲,如果我能够可靠地冻结自动更新过程,同时仍然独立打包应用程序,我应该能够以相同的方式运行 Chrome。如果这不起作用,我可能会求助于使用 Chromium。

【问题讨论】:

  • 我似乎只需要更新 chromedriver 以匹配更新后的 Chrome。最新版本是 2.25,你的是 2.23。
  • 感谢您的回复。这正是我想要避免的。 chromedriver 只是使用我的原生 chrome 吗?我可以将它指向一个固定版本吗?我需要在此处进行“设置并忘记它”设置,因为这将被打包为应用程序,除非 DSL 更改,否则不需要更新。
  • 还有另一个问题似乎表明我可以做我想做的事情here
  • 这次您可以更新ChromeDriver 以匹配您当前的 Chrome 版本(因为我不知道无法降级 Chrome 或获取较旧的安装程序),然后阻止 Chrome从升级。您可以通过转到 Chrome 安装文件夹并删除更新文件夹来做到这一点。
  • 是的...但是我如何打包所有依赖项,以便下一个人在他们的系统上使用该应用程序时不会发生这种情况?

标签: node.js selenium selenium-webdriver selenium-chromedriver nwjs


【解决方案1】:

另一个非常接近@Matthew Sanders 建议的解决方案是将Chromium 与以下设置一起使用

var webdriver = require("selenium-webdriver");
var chrome = require("selenium-webdriver/chrome");

var options = new chrome.Options().setChromeBinaryPath("/usr/bin/chromium-browser")
// options.headless()
var driver = new webdriver.Builder()
    .forBrowser('chrome')
    .setChromeOptions(options)
    .build();

【讨论】:

    【解决方案2】:

    您可以将 docker 与 selenium hub 一起使用来设置一个独立于您安装的浏览器的隔离环境。集线器有不同的浏览器,但正如您之前使用 chrome 一样,我会推荐以下内容:

    https://hub.docker.com/r/selenium/standalone-chrome/

    安装好 docker 之后,就可以启动服务器了

    docker run -d -p 4444:4444 selenium/standalone-chrome:latest
    

    然后您可以通过端口 4444 连接到它。

    当一切启动并运行时,只需在代码中告诉它,确保您的 webdriver 使用远程 selenium 集线器:

    var webdriver = require("selenium-webdriver");
    var driver = new webdriver.Builder()
        .forBrowser('chrome')
        .usingServer('http://localhost:4444/wd/hub')
        .build();
    

    编辑:

    正如@sircapsalot 指出的那样,您可以通过自己构建映像来指定您的版本https://github.com/SeleniumHQ/docker-selenium/wiki/Building-your-own-images#specify-chromedriver-and-chrome-versions

    【讨论】:

    • 很高兴知道此选项存在。在这个特定的客户端应用程序中,我不希望将 docker 添加到混合中增加复杂性,但我可以在其他应用程序中看到该实用程序。我已经找到了解决方案,并将发布我的答案。
    • 我是这些 docker 容器的维护者 - 我还创建了这个 wiki page,它告诉我们如何使用对应的驱动程序管理特定版本的浏览器。
    【解决方案3】:

    如何在不强制更新的情况下使用Selenium chromedriver?

    简单回答:

    禁用您的自动浏览器更新。

    通过让自动更新发生,您可能会遇到带有 Chromedriver 的不同版本的 Chrome。 Firefox 和 Geckodriver 也会发生同样的情况。

    最好有一个更可控的升级过程。当您准备好更新时,手动更新到最新的 chrome 和 chromedriver 版本。

    【讨论】:

    • 然而,并不是那么简单,这就是我正在研究的想法。我需要能够使用我的应用程序打包特定的 chrome 二进制文件。我目前看到的大部分内容都建议在不同的用户帐户上安装 chrome,但是,在这种情况下我也没有这种能力。最接近的是铬或 CEF。
    • "not that simple" 您无权更改浏览器的自动更新吗?为什么不使用我们的docker containers?你可以在那些管理specific versions
    • 我确实可以访问我自己的系统...但我需要将浏览器我的应用程序打包在一起。我不想弄乱用户系统上的现有浏览器。实际的应用程序也已经是基于浏览器的,因为它使用的是 CEF,但由于 Selenium 的限制,它必须启动一个单独的浏览器来进行自动化。第二个浏览器当前是由 chromedriver 驱动的 chrome。
    • 我确信我可以下载 chromium 作为另一种选择,但是,我知道它与 Chrome 本身的构建略有不同。所以我希望 Chrome 减去更新并将其与我的应用程序捆绑在一起。
    【解决方案4】:

    我能够通过使用Chromium 解决我的问题,但是,我进行了测试以确保它也可以与 Chrome 一起使用。 Chrome 的问题在于您无法轻松找到旧版本,它们可以(并且确实)改变您禁用更新版本自动更新的方式。有一些建议可以在 Chrome 中禁用自动更新,其中一些建议比其他建议更有效。

    我决定按照网站上的指南下载以前版本的 Chromium(在本例中它使用版本 44 作为示例):

    1. http://googlechromereleases.blogspot.com/search/label/Stable%20updates 最后一次“44”。被提及。
    2. Position Lookup 中循环该版本历史记录(“44.0.2403.157”)
    3. 在这种情况下,它返回一个基本位置“330231”。这是 44 版本分支的提交,早在 2015 年 5 月。*
    4. 打开continuous builds archive
    5. 点击您的平台 (Linux/Mac/Win)
    6. 将“330231”粘贴到顶部的过滤器字段中,然后等待所有结果到 XHR 中。

    注意:有时数字不匹配,您必须滚动列表到您看到的下一个最低匹配项。在我的情况下,我不得不返回几场比赛才能找到工作副本。

    一旦你有了一个二进制文件,这里就是使用它的 javascript 逻辑(更多信息可以在Selenium Docs 中找到):

    // get the webdriver for future operations
    var webdriver = require("selenium-webdriver");
    // configure the chromedriver
    var chrome = require("selenium-webdriver/chrome");
    // here I get the path of chromedriver to avoid using path variables
    var path = new require("chromedriver").path;
    var service = new chrome.ServiceBuilder(path).build();
    
    var options = new chrome.Options();
    // Note: on mac you need to reach in the .app folder
    options.setChromeBinaryPath("Chromium.app/Contents/MacOS/Chromium");
    
    var driver = new chrome.Driver(options, service);
    

    【讨论】:

      猜你喜欢
      • 2020-05-04
      • 2016-05-11
      • 2017-11-27
      • 1970-01-01
      • 2011-04-28
      • 2017-10-16
      • 2015-06-08
      • 2020-10-15
      • 2016-04-11
      相关资源
      最近更新 更多