Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 需要从selenium服务器转储元素id为的整个DOM树_Python_Selenium_Ghostdriver - Fatal编程技术网

Python 需要从selenium服务器转储元素id为的整个DOM树

Python 需要从selenium服务器转储元素id为的整个DOM树,python,selenium,ghostdriver,Python,Selenium,Ghostdriver,我一直在使用python selenium进行web自动化测试。自动化的关键部分是在HTML页面中为用户可见的对象找到正确的元素。下面的API大部分时间都可以工作,但不是所有时间都可以 find_element_by_xxx, xxx can be id, name, xpath, tag_name etc. 当HTML页面太复杂时,我想搜索dom树。想知道是否可以要求selenium服务器序列化整个DOM(使用可用于通过webdriver服务器对其执行操作的元素id)。客户端(pytho

我一直在使用python selenium进行web自动化测试。自动化的关键部分是在HTML页面中为用户可见的对象找到正确的元素。下面的API大部分时间都可以工作,但不是所有时间都可以

find_element_by_xxx,  xxx can be id, name, xpath, tag_name etc. 
当HTML页面太复杂时,我想搜索dom树。想知道是否可以要求selenium服务器序列化整个DOM(使用可用于通过webdriver服务器对其执行操作的元素id)。客户端(python脚本)可以使用自己的搜索算法来查找正确的元素

请注意,python selenium可以通过

drv.page_source
然而,从selenium服务器的角度分析它并没有给出内部元素id,因此没有用处

EDIT1:
将其解释为更清楚(感谢@alecxe):这里需要的是selenium服务器中所有DOM元素的序列化表示(保留其DOM结构),此序列化表示可以发送到客户端(一个python selenium测试应用程序)它可以自己进行搜索。

您可以尝试利用页面对象模式。这听起来更接近您在本例中所寻找的内容。你可能不会改变所有的事情,但至少对于这一部分你可能会想这样。

您还可以循环浏览页面的所有元素,并一次保存一个元素,但应该有一些库可以做到这一点。我知道.Net有htmlAgility。关于python我不确定

更新 我发现了这个…也许它会对你有所帮助。 试试:

find_elements_by_xpath("//*")
应该匹配文档中的所有元素

更新(以匹配问题优化):

使用javascript并将DOM作为字符串返回:

execute_script("return document.documentElement.outerHTML")
问题 好的,在某些情况下,您可能需要在客户端(Python)而不是服务器(浏览器)端对页面执行一些实质性的处理。例如,如果您已经用Python编写了某种机器学习系统,并且在对其执行操作之前需要分析整个页面,那么尽管可以通过一系列
find_元素
调用来完成,但这会非常昂贵,因为每个调用都是客户机和服务器之间的往返过程。而且在浏览器中重写它可能太昂贵了

为什么Selenium的标识符不会这么做 但是,我看不到一种有效的方法可以将DOM的序列化与Selenium自己的标识符结合起来。当您调用
find\u元素
或从
execute\u脚本
调用返回DOM节点时(或传递到
execute\u async\u脚本
给脚本的回调),Selenium会根据需要创建这些标识符。但如果您调用
find_element
来获取每个元素的标识符,那么您就回到了原点。我可以想象在浏览器中用所需的信息装饰DOM,但是没有公共API来请求某种类型的
WebElement
id的预分配。事实上,这些标识符的设计是不透明的,因此即使解决方案设法获得所需信息,我也会担心跨浏览器的可行性和持续支持

解决办法 然而,有一种方法可以获得一个在双方都能工作的寻址系统:XPath。其思想是在客户端将DOM序列化解析为一棵树,然后获取感兴趣的节点的XPath,并使用它获取相应的WebElement。因此,如果您必须执行几十次客户机-服务器往返以确定需要执行单击操作的单个元素,那么您可以将其简化为对页面源代码的初始查询加上使用所需XPath的单个
find_元素
调用

这是一个超级简单的概念证明。它获取Google首页的主输入字段

from StringIO import StringIO

from selenium import webdriver
import lxml.etree

#
# Make sure that your chromedriver is in your PATH, and use the following line...
#
driver = webdriver.Chrome()
#
# ... or, you can put the path inside the call like this:
# driver = webdriver.Chrome("/path/to/chromedriver")
#

parser = lxml.etree.HTMLParser()

driver.get("http://google.com")

# We get this element only for the sake of illustration, for the tests later.
input_from_find = driver.find_element_by_id("gbqfq")
input_from_find.send_keys("foo")

html = driver.execute_script("return document.documentElement.outerHTML")
tree = lxml.etree.parse(StringIO(html), parser)

# Find our element in the tree.
field = tree.find("//*[@id='gbqfq']")
# Get the XPath that will uniquely select it.
path = tree.getpath(field)

# Use the XPath to get the element from the browser.
input_from_xpath = driver.find_element_by_xpath(path)

print "Equal?", input_from_xpath == input_from_find
# In JavaScript we would not call ``getAttribute`` but Selenium treats
# a query on the ``value`` attribute as special, so this works.
print "Value:", input_from_xpath.get_attribute("value")

driver.quit()
注:

  • 上面的代码没有使用
    driver.page_source
    ,因为Selenium的文档声明它返回的内容的新鲜度没有保证。它可以是当前DOM的状态,也可以是第一次加载页面时DOM的状态

  • 此解决方案遇到的问题与
    find\u元素
    遇到的关于动态内容的问题完全相同。如果在分析过程中DOM发生了变化,那么您正在处理一个过时的DOM表示

  • 如果在执行分析时必须生成JavaScript事件,并且这些事件改变了DOM,则需要再次获取DOM。(这与前一点类似,但是使用
    find\u element
    调用的解决方案可以通过仔细排序调用序列来避免我在这一点上所说的问题。)

  • lxml
    的树可能在结构上与DOM树不同,从
    lxml
    中获得的XPath不会寻址DOM中的相应元素。
    lxml
    处理的是浏览器传递给它的HTML的已清理序列化视图。因此,只要代码是为了防止我在第2点和第3点中提到的问题而编写的,我不认为这是一种可能的情况,但这并非不可能

  • 有关获取Selenium标识符的任何尝试的问题,请参阅my

    同样,问题是要减少大量的
    find_element
    调用,以避免与它们相关的往返

    与我的另一个答案不同的方法是使用
    execute\u script
    在浏览器上执行搜索,然后返回所需的所有元素。例如,此代码需要三次往返,但可以减少为一次往返:

    el, parent, text = driver.execute_script("""
    var el = document.querySelector(arguments[0]);
    return [el, el.parentNode, el.textContent];
    """, selector)
    
    这将返回元素、元素的父元素和元素的文本
    var s = 
    recurse(obj) {
        for(var i in obj) {
           return typeof(i) + ":" + i.toString() + ":" + JSON.stringify(obj[i]);
        }
    }