【问题标题】:How to Add a <script> into Head Using Selenium's JavascriptExecutor如何使用 Selenium JavascriptExecutor 将 <script> 添加到 Head 中
【发布时间】:2019-08-03 02:29:48
【问题描述】:

总结

我想找到一种方法,使用SeleniumJavascriptExecutor&lt;script&gt; 标签添加到DOM 的头部,或者任何其他方式都可以。


我尝试了很多方法,也发现了一些类似的主题,但没有一个能解决我的问题,这就是为什么我觉得有必要在这里提问。

例如:

Suggested solutions in this question 没有解决我的问题。有人说它对他们有用,但不,它不适合我。


我一直在尝试执行什么?

这是我要执行的代码的小sn-p:

            WebDriver driver = new FirefoxDriver();
            JavascriptExecutor jse = (JavascriptExecutor) driver;

            jse.executeScript("var s = document.createElement('script');");
            jse.executeScript("s.type = 'text/javascript';");
            jse.executeScript("s.text = 'function foo() {console.log('foo')}';");
            jse.executeScript("window.document.head.appendChild(s);");

我只是跳过了上面的代码,您使用driver.get() 等导航到网页,然后尝试执行脚本。

另外,s.text 将包含我想要使用的实际脚本,所以我只是放了一个 foo() 函数来给出想法。

上面的代码在运行时会抛出这个错误:

Exception in thread "main" org.openqa.selenium.JavascriptException: ReferenceError: s is not defined


到目前为止,我已经尝试了所有可以在 Internet 上找到的解决方案,但似乎都没有。

【问题讨论】:

  • 在 JavaScriptExecutor 中声明的变量在其脚本完成后是否仍然存在?可能是错的,但我不这么认为。
  • 不,它没有。那就是问题所在。你可以阅读我上面得到的错误。它说变量未定义。除此之外,我还尝试注入整个 JavaScript 文件,但这也不起作用。

标签: java selenium selenium-webdriver


【解决方案1】:

OP 提出了以下解决方案:

jse.executeScript("var s=window.document.createElement('script');" + 
"s.type = 'text/javascript';" + "s.text = function foo() {console.log('foo')};" + 
"window.document.head.appendChild(s);");

【讨论】:

  • 我刚试过这个,但是这个“\”字符有问题。我的意思是我们甚至可以在Java中使用它吗?因为当我尝试时,我得到了所有错误。但是,当我尝试使用+ 连接所有字符串以及删除函数定义周围的单引号后,它工作正常。 jse.executeScript("var s=window.document.createElement('script');" + "s.type = 'text/javascript';" + "s.text = function foo() {console.log('foo')};" + "window.document.head.appendChild(s);");
【解决方案2】:

首先,此行无效。

    jse.executeScript("s.text = 'function foo() {console.log('foo')}';");

请注意如何将单引号文本括在单引号中。使用一组作为"\""

我个人会这样做(经过编辑使其成为全局函数):

using OpenQA.Selenium.Support.Extensions;

driver.ExecuteJavascript("window.foo = function foo() {console.log('foo')}");

就这么简单。您正在通过这样做将 foo 注册为方法。执行完这段javascript后,可以手动进入浏览器开发者工具调用“foo()”查看。此外,您可以通过直接在控制台中注册来检查它。只需在浏览器控制台中输入“function foo() {console.log('foo')}”,然后调用“foo()”即可。

无需将此添加为脚本标签。

编辑#2:我修复了我上面的代码建议,以便将该方法分配给窗口,从而可以全局访问,并且在 javascript 执行程序运行代码的匿名脚本之外。这个不起作用的原始问题是至少在我的测试中解决了这个问题。

【讨论】:

  • 嗯,首先,感谢您纠正我的报价。你是对的。但是你对你后来的建议是错误的。如果我只是执行该脚本并转到控制台并尝试调用foo(),那么即使代码成功终止,我也会得到foo is not defined
  • 我添加了一个示例,说明我如何将其用作对上述帖子的编辑。请注意,我按照最初建议的方式定义方法,但与最初建议的不同,我也在定义方法后立即使用该方法。该方法可能仅存在于该执行程序会话中。如果是这种情况,并且您不想这样做,则最好添加一个脚本标签。
  • 是的,页面没有刷新。顺便说一句,我尝试了 C. Peck 的解决方案并结合了您的建议(我的意思是正确使用双引号和单引号)然后效果很好。我想将它添加为脚本标签,因为我将使用一个包含一些函数的 JS 文件,所以我想稍后在页面上使用这些函数。
  • 顺便说一句,你可能是对的,因为它在 javadoc 上是这么说的——“在当前选定的框架或窗口的上下文中执行 JavaScript。提供的脚本片段将是作为匿名函数的主体执行。在脚本中,使用 document 来引用当前文档。请注意,一旦脚本完成执行,局部变量将不可用,但全局变量将保持不变。 "link
  • 我更新了我的建议。当我像这样直接将它分配给窗口时它可以工作: driver.ExecuteJavascript("window.foo = function foo() {console.log('foo')}");我确认执行上述操作,只需调用“foo()”就可以完全按照您的预期工作。因此,它还有一个额外的好处,就是可能比建议的代码更干净、更简洁。
猜你喜欢
  • 2011-08-16
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 2016-05-22
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
相关资源
最近更新 更多