ruby 硒 execute_script Net::ReadTimeout

ruby selenium execute_script Net::ReadTimeout

我正在使用我的脚本(不是测试)中的 Capybara::Selenium 从外部站点获取一些图像。 页面加载正常,所有图像也都加载了并且我看到了它们,但是任何执行函数 page.session.driver.evaluate_script 的尝试总是抛出 Net::ReadTimeout: Net::ReadTimeout with #<TCPSocket:(closed)>.

完整代码:

require 'capybara-webkit'
require 'selenium-webdriver'

JS_GET_IMAGE = <<~EJSGETIMAGE
  var img = document.getElementById('requestImage');
  const cvs = document.createElement('canvas');
  cvs.width = img.width;
  cvs.height = img.height;
  cvs.getContext('2d').drawImage( img, 0, 0 );
return cvs.toDataURL("image/png");
EJSGETIMAGE

session = Capybara::Session.new :selenium
page = session.visit Cfg.site.url
driver = session.driver.browser
driver.manage.timeouts.script_timeout = 5000

@img = driver.execute_async_script JS_GET_IMAGE

好的,我开始测试非常简单的脚本,但也出现了同样的错误。

page.session.driver.browser.execute_async_script("setTimeout(arguments[0], 2000)")

我也用了 session = Capybara::Session.new :selenium_headless 得到了同样的错误。

非常感谢任何帮助。

小事优先 - 如果您使用的是 Selenium 驱动程序,则无需加载 capybara-webkit

现在进入主要问题。执行JS时不需要直接在driver上调用方法,而应该只调用Capybara方法execute_scriptevaluate_scriptevaluate_async_scriptevaluate_xxx 方法适用于您期望 return 值的情况,execute_script 方法适用于您不关心任何 return 值的情况。 evaluate_async_script 收到一个回调函数作为最后一个参数,需要将其调用到 return 一个值,但是您的 JS_GET_IMAGE 似乎从来没有这样做过(也不需要这样做,因为它不是async) 所以最好只使用 evaluate_scriptevaluate_script 的另一个要求是评估的代码需要是单个语句。为了满足该要求,我们可以使用 IIFE。

require "capybara/dsl"

JS_GET_IMAGE = <<~EJSGETIMAGE
  (function(){
     var img = document.getElementById('requestImage');
     const cvs = document.createElement('canvas');
     cvs.width = img.width;
     cvs.height = img.height;
     cvs.getContext('2d').drawImage( img, 0, 0 );
     return cvs.toDataURL("image/png");
  })()
EJSGETIMAGE

session = Capybara::Session.new :selenium
session.visit Cfg.site.url
@img = session.evaluate_script JS_GET_IMAGE

尽管恕我直言,最好让 Capybara 找到元素并将其传递给 JS 函数,使其更加灵活并利用 Capybaras 等待元素出现的优势

require "capybara/dsl"

JS_GET_IMAGE = <<~EJSGETIMAGE
  (function(img){
     const cvs = document.createElement('canvas');
     cvs.width = img.width;
     cvs.height = img.height;
     cvs.getContext('2d').drawImage( img, 0, 0 );
     return cvs.toDataURL("image/png");
  })(arguments[0])
EJSGETIMAGE

session = Capybara::Session.new :selenium
session.visit Cfg.site.url
img_element = session.find('#requestImage')
@img = session.evaluate_script JS_GET_IMAGE, img_element