在 Firefox 中通过 Selenium 访问 ShadowRoot 返回 JavascriptException: Cyclic object value

Tij*_*men 2 javascript python selenium

我正在尝试使用 Python 和 Selenium 自动化www.freeinvaders.org版本的 Space Invaders。实际的游戏通过一个 HTML5 画布元素运行,该元素被包裹在一个 Shadow-root 中。

使用这个问题的答案,我尝试扩展影子根,这样我就可以单击画布并“玩”游戏。

我当前的代码:

  def expand_shadow_element(element):
     shadowRoot = browser.execute_script('return arguments[0].shadowRoot', element)
     return shadowRoot
  

  browser = webdriver.Firefox()
  browser.get("http://www.freeinvaders.org/")

  #wait for element to load

  el = WebDriverWait(browser, timeout=20).until(lambda d:d.find_element_by_tag_name("ruffle-player"))
  time.sleep(5)

  #expand the shadowroot and click the canvas
  host = browser.find_element_by_tag_name("ruffle-player")
  shadowRoot = expand_shadow_element(host)
  canvas = shadowRoot.find_element_by_tag_name("canvas")
  canvas.click()
Run Code Online (Sandbox Code Playgroud)

页面的 HTML 结构如下:(为了易读性进行了删节)

<!DOCTYPE html> 
<html lang="en-US">
<head>

<title>Free Invaders</title>

</head>
<body>
<div id='full-page-container'>  
<main>
  <div id="game-container">
       
    <ruffle-player>
  #shadow-root (open)
  <div id="container" style="visibility: visible;">
      
    <canvas width="1600" height="760" style="touch-action: none; cursor: auto;"></canvas>
    </div><!--container-->
  </ruffle-player>
  </div><!--game-container-->

</div><!--fullpagecontainer-->
</body>
Run Code Online (Sandbox Code Playgroud)

运行上面的 Pyhton 脚本时,在这一行失败:

shadowRoot = browser.execute_script('return arguments[0].shadowRoot', element)

出现 JavaScript 错误:

selenium.common.exceptions.JavascriptException: Message: Cyclic object value

我知道该错误应该意味着返回的 JSON 字符串中有一个自引用项,但这里不应该是这种情况。

任何人都可以帮助我解释为什么会发生此错误以及采取什么措施可以缓解该问题?

我使用的是 Python 3.8.5、Selenium 3.141.0 和 Firefox 86.0。所有这些都运行在 Linux Mint 20.1 上。

编辑 我也尝试过替代的Javascript:

shadowRoot = browser.execute_script('document.querySelector("ruffle-player").shadowRoot')
Run Code Online (Sandbox Code Playgroud)

但这只会返回另一个错误:

AttributeError: 'NoneType' object has no attribute 'find_element_by_tag_name'
Run Code Online (Sandbox Code Playgroud)

这表明它甚至没有找到任何物体。

bmc*_*ley 5

这似乎是bugzilla上提交的已知问题。

geckodriver 开发人员还表示 WebDriver 规范需要更新。请参阅:w3c/webdriver#350

不过,CAVah已在此处找到并发布了此问题的解决方法。

按照返回 Shadowroot 子级的建议,return arguments[0].shadowRoot.children它找到了 4 个元素:

[<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1dd0fedf-1a8c-42f2-a4de-0ed7df478212", element="252a6352-4fe0-409d-a626-18456a973da5")>, 
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1dd0fedf-1a8c-42f2-a4de-0ed7df478212", element="47d76aed-5f44-4933-9718-53267a6417bf")>, 
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1dd0fedf-1a8c-42f2-a4de-0ed7df478212", element="d3fcad48-7cbb-4de3-a247-49d7d227e982")>, 
<selenium.webdriver.firefox.webelement.FirefoxWebElement (session="1dd0fedf-1a8c-42f2-a4de-0ed7df478212", element="abb5012e-79bf-494b-b5f2-ff28dfecab0f")>]
Run Code Online (Sandbox Code Playgroud)

检查这些之后,看起来第三个元素包含画布并且可以单击。

以下代码似乎对我有用:

def expand_shadow_element(element):
    # return a list of elements
    shadowRoot = browser.execute_script('return arguments[0].shadowRoot.children', element)
    return shadowRoot


browser = webdriver.Firefox()
browser.get("http://www.freeinvaders.org/")

#wait for element to load

el = WebDriverWait(browser, timeout=20).until(lambda d:d.find_element_by_tag_name("ruffle-player"))
time.sleep(5)

#expand the shadowroot and click the canvas
host = browser.find_element_by_tag_name("ruffle-player")
shadowRoot = expand_shadow_element(host)

canvas = shadowRoot[2].find_element_by_tag_name("canvas")
canvas.click()
Run Code Online (Sandbox Code Playgroud)