【问题标题】:webdriver: get element's xpath?webdriver:获取元素的 xpath?
【发布时间】:2016-09-14 02:27:38
【问题描述】:

是否可以返回 WebElement 的 xpath ?

【问题讨论】:

    标签: webdriver


    【解决方案1】:

    不是直接来自 WebDriver,但如果你真的需要,你可以伪造它:

    public String getElementXPath(WebDriver driver, WebElement element) {
        return (String)((JavascriptExecutor)driver).executeScript("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]).toLowerCase();", element);
    }
    

    Javascript 来自this post,已缩小到一行。它可能并不完美,但可以让你知道去哪里。大多数驱动程序都实现了JavascriptExecutor 接口,并具有在浏览器中执行Javascript 的能力。 executeScript 可以返回任何原始 JavaScript 类型、HTML 元素或任何前述内容的非嵌套列表。

    Not all browsers support xpath the same way,所以在使用这些 xpath 选择元素时要小心。此外,并非所有浏览器都支持原生 xpath(cough IE cough),所以在这种情况下它是伪造的。

    【讨论】:

    • 太棒了 :) 与 Chrome 62 完美搭配。感谢 dflems :)
    【解决方案2】:

    如果 WebElement 被 By.xpath 找到: 在 Java 上:

    public static String GetWebElementXpath(WebElement El) throws AssertionError{
            if ((El instanceof WebElement)){
                Object o = El;
                String text = o.toString();
            /* text is smth like this
            [[FirefoxDriver: firefox on WINDOWS (9170d4a5-1554-4018-adac-f3f6385370c0)] -> xpath: //div[contains(@class,'forum-topic-preview')]//div[contains(@class,'small-human')]]
            */
                text = text.substring( text.indexOf("xpath: ")+7,text.length()-1);
                return text;
            }else   {   Assert.fail("Argument is not an WebElement, his actual class is:"+El.getClass());       }
            return "";
        }
    

    【讨论】:

      【解决方案3】:

      以上两个答案都存在同样的问题。通过调用 .toLowerCase() 函数返回完整的 XPath,任何包含大写字母 id 的 XPath 都将不起作用。

      示例://div[@id="deviceblock-1111"] 不适用于标签 &lt;div id="deviceBlock-1111"&gt;

      但是,您可以只删除返回的 .toLowerCase() 调用,但您最终会得到 XPath 的样子://DIV[@id="deviceBlock-1111"]/DIV[2]/SELECT[1]/OPTION[5]

      要解决这个问题,请使用以下函数。

      public String GetElementXPath(WebElement element, WebDriver driver)
      {
          return (String) ((JavascriptExecutor) driver).executeScript(
          "getXPath=function(node)" +
          "{" +
              "if (node.id !== '')" +
              "{" +
                  "return '//' + node.tagName.toLowerCase() + '[@id=\"' + node.id + '\"]'" +
              "}" +
      
              "if (node === document.body)" +
              "{" +
                  "return node.tagName.toLowerCase()" +
              "}" +
      
              "var nodeCount = 0;" +
              "var childNodes = node.parentNode.childNodes;" +
      
              "for (var i=0; i<childNodes.length; i++)" +
              "{" +
                  "var currentNode = childNodes[i];" +
      
                  "if (currentNode === node)" +
                  "{" +
                      "return getXPath(node.parentNode) + 
                          '/' + node.tagName.toLowerCase() + 
                          '[' + (nodeCount+1) + ']'" +
                  "}" +
      
                  "if (currentNode.nodeType === 1 && " +
                      "currentNode.tagName.toLowerCase() === node.tagName.toLowerCase())" +
                  "{" +
                      "nodeCount++" +
                  "}" +
              "}" +
          "};" +
      
          "return getXPath(arguments[0]);", element);
      }
      

      这将从您的 WebElement 返回格式正确、唯一的 XPath。

      //div[@id="deviceBlock-1111"]/div[2]/select[1]/option[5]

      【讨论】:

        【解决方案4】:
        public String getElementXPath(WebDriver driver, WebElement element) {
        
            String javaScript = "function getElementXPath(elt){" +
                                    "var path = \"\";" +
                                    "for (; elt && elt.nodeType == 1; elt = elt.parentNode){" +
                                        "idx = getElementIdx(elt);" +
                                        "xname = elt.tagName;" +
                                        "if (idx > 1){" +
                                            "xname += \"[\" + idx + \"]\";" +
                                        "}" +
                                        "path = \"/\" + xname + path;" +
                                    "}" + 
                                    "return path;" +
                                "}" +
                                "function getElementIdx(elt){" +
                                    "var count = 1;" +
                                    "for (var sib = elt.previousSibling; sib ; sib = sib.previousSibling){" +
                                        "if(sib.nodeType == 1 && sib.tagName == elt.tagName){" +
                                            "count++;" +
                                        "}" +
                                    "}" +
                                    "return count;" + 
                                "}" +
                                "return getElementXPath(arguments[0]).toLowerCase();";      
        
            return (String)((JavascriptExecutor)driver).executeScript(javaScript, element);     
        
        }
        

        【讨论】:

        • 上面的方法签名不适合灰色区域,所以请务必注意...
        【解决方案5】:

        我会直接评论dflems'answer,但我没有这样做的声誉。

        将整个 xpath 转换为小写是可以的,除非 xpath 包含的 id 值不是全部小写。下面是 dflems 的 Javascript 的修改版本,但使用的是 Python 而不是 Java:

        def get_xpath_from_element(driver, element):
            return driver.execute_script("gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName.toLowerCase()+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]);", element)
        

        【讨论】:

        • 在 tbselenium 和 Tor 浏览器上也能完美运行(Firefox Quantum 8.0.2(基于 Mozilla Firefox 60.2.1esr)(64 位))
        【解决方案6】:

        有一种方法可以在不使用 JavaScript 的情况下获取元素 XPath。

        1. 定义外部 XPath 的起点,例如 body 标签。
        2. 用 selenium 检查所有可能的内向标签 NoSuchElementException
        3. 检查 getText 以获取生成的 XPath 列表。

        【讨论】:

          【解决方案7】:
          public static String getXPathFromElement(WebElement element) {
                  String elementDescription = element.toString();
                  return elementDescription.substring(elementDescription.lastIndexOf("-> ") + 3, elementDescription.lastIndexOf("]"));
          }
          

          Web 元素 toString() 如下所示:

          '[[FirefoxDriver: WINDOWS 上的 firefox (ceb69f9f-bef4-455d-b626-ab439f195be6)] -> id: pageBeanfundDescription]'

          我只是提取 id/xpath。

          【讨论】:

            【解决方案8】:
            /**
             * This method return By reference for the WebElement passed to it as a parameter.
             * @param element
             * @return
             */
            public static By convertWebElementToByReference(WebElement element) 
            {
                By byLocator = null;
                String elementDescription = element.toString();
                String elementTypeAndValue[] = (elementDescription.substring(elementDescription.lastIndexOf("-> ") + 3, elementDescription.lastIndexOf("]"))).split(":");        
            
                switch (elementTypeAndValue[0].trim()) 
                {
                    case "id": byLocator = By.id(elementTypeAndValue[1].trim());
                       break;
            
                    case "xpath": byLocator = By.xpath(elementTypeAndValue[1].trim());
                       break;
            
                    case "link text": byLocator = By.linkText(elementTypeAndValue[1].trim());
                       break;
            
                    case "tag name": byLocator = By.tagName(elementTypeAndValue[1].trim());
                       break;
            
                    case "class name": byLocator = By.className(elementTypeAndValue[1].trim());
                       break;
            
                    case "partial link text": byLocator = By.partialLinkText(elementTypeAndValue[1].trim());
                       break;
            
                    case "name": byLocator = By.name(elementTypeAndValue[1].trim());
                       break;
            
                    case "css selector": byLocator = By.cssSelector(elementTypeAndValue[1].trim());
                       break;
            
                    default:
                        throw new RuntimeException("Invalid locator type: " + elementTypeAndValue[0].trim());
                }
            
                return byLocator;
            }
            

            【讨论】:

            • 请在示例代码中包含一些描述。
            猜你喜欢
            • 1970-01-01
            • 2016-06-19
            • 2019-03-24
            • 2021-03-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-05-14
            • 1970-01-01
            相关资源
            最近更新 更多