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
得到了同样的错误。
- ruby 2.6.3p62(2019-04-16 修订版 67580)[x86_64-linux]
- selenium-webdriver (3.142.3)
- 水豚 (3.28.0)
- 水豚-webkit (1.15.1)
- community/geckodriver 0.24.0-1
- 火狐 68.0.1 (64-битный)
非常感谢任何帮助。
小事优先 - 如果您使用的是 Selenium 驱动程序,则无需加载 capybara-webkit
。
现在进入主要问题。执行JS时不需要直接在driver上调用方法,而应该只调用Capybara方法execute_script
、evaluate_script
或evaluate_async_script
。 evaluate_xxx
方法适用于您期望 return 值的情况,execute_script
方法适用于您不关心任何 return 值的情况。 evaluate_async_script
收到一个回调函数作为最后一个参数,需要将其调用到 return 一个值,但是您的 JS_GET_IMAGE 似乎从来没有这样做过(也不需要这样做,因为它不是async) 所以最好只使用 evaluate_script
。 evaluate_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
我正在使用我的脚本(不是测试)中的 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
得到了同样的错误。
- ruby 2.6.3p62(2019-04-16 修订版 67580)[x86_64-linux]
- selenium-webdriver (3.142.3)
- 水豚 (3.28.0)
- 水豚-webkit (1.15.1)
- community/geckodriver 0.24.0-1
- 火狐 68.0.1 (64-битный)
非常感谢任何帮助。
小事优先 - 如果您使用的是 Selenium 驱动程序,则无需加载 capybara-webkit
。
现在进入主要问题。执行JS时不需要直接在driver上调用方法,而应该只调用Capybara方法execute_script
、evaluate_script
或evaluate_async_script
。 evaluate_xxx
方法适用于您期望 return 值的情况,execute_script
方法适用于您不关心任何 return 值的情况。 evaluate_async_script
收到一个回调函数作为最后一个参数,需要将其调用到 return 一个值,但是您的 JS_GET_IMAGE 似乎从来没有这样做过(也不需要这样做,因为它不是async) 所以最好只使用 evaluate_script
。 evaluate_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