ruby - 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]
- 硒网络驱动程序(3.142.3)
- 水豚 (3.28.0)
- 水豚 webkit (1.15.1)
- 社区/geckodriver 0.24.0-1
- 火狐 68.0.1 (64-битный)
非常感谢任何帮助。
解决方案
capybara-webkit
小事第一 -如果您使用 Selenium 驱动程序,则无需加载。
现在进入主要问题。执行 JS 时无需直接在驱动程序上调用方法,而只需调用 Capybara 方法execute_script
、evaluate_script
或evaluate_async_script
. 这些evaluate_xxx
方法适用于您期望返回值时,该execute_script
方法适用于您不关心任何返回值时。evaluate_async_script
接收回调函数作为需要调用以返回值的最后一个参数,但是您的 JS_GET_IMAGE 似乎从来没有这样做(也不需要,因为它不是异步的)所以最好只使用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 函数,使其更加灵活并利用 Capybara 等待元素出现
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
推荐阅读
- android - 重新启动android后计划的通知持续存在
- java - 我的 Java 代码需要全新的视角
- excel - 如何使用具有日期格式的 VBA 删除工作表?
- c# - 我可以进一步减少对 docker 镜像的依赖,以便由 docker 容器上的 asp.net web api 应用程序运行吗
- docker - 发生错误后继续构建 Docker 映像
- excel - VBA 打开批处理文件 - 执行后立即关闭窗口
- r - 如何检查向量是否为 LIFO/FIFO 递减
- python - tf.concat 给出“形状必须至少为 2 级,但为 1 级”的错误,即使两个张量的形状相同
- java - 通过 JDBC 找出插入语句的 Yarn application_id
- c - 无论我尝试什么,我的指针/地址都是错误的