【问题标题】:Find an element by text and get xpath - selenium webdriver junit通过文本查找元素并获取 xpath - selenium webdriver junit
【发布时间】:2013-08-29 12:08:10
【问题描述】:

我的网页中有一个 9 行 6 列的表格。我想搜索文本“MakeGoodDisabled-Programwise_09_44_38_461(n)”并获取单元格的 xpath。我使用了以下内容,但它失败了,因为它无法在页面上找到文本。你能帮忙吗?我正在使用 Selenium Webdriver Junit 来编写代码。

List < WebElement > links = driver.findElements(By.tagName("td"));

Iterator < WebElement > itr = links.iterator();
while (itr.hasNext()) {
 String test = itr.next().getText();

 if (test.equals("MakeGoodDisabled-Programwise_09_44_38_461(n)")) {
  String xpath = driver.findElement(By.name(test)).getAttribute("xpath");
  System.out.println(xpath);
 }
}

【问题讨论】:

  • 你想做什么?
  • 解决手头问题的方法是错误的!您介意讨论这个问题吗,我们将为您提供如何进行的好方法(不要期望太多代码,快速的 google 会提供很多)!

标签: selenium junit selenium-webdriver


【解决方案1】:

您也可以使用它来爬取并生成 xpath:

调用下面的方法
generateXPATH(element, "");

输出将类似于:

/html[1]/body[1]/div[5]/div[1]/div[2]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/form[1]/div[2]/div[1]/input[2]

方法

private String generateXPATH(WebElement childElement, String current) {
    String childTag = childElement.getTagName();
    if(childTag.equals("html")) {
        return "/html[1]"+current;
    }
    WebElement parentElement = childElement.findElement(By.xpath("..")); 
    List<WebElement> childrenElements = parentElement.findElements(By.xpath("*"));
    int count = 0;
    for(int i=0;i<childrenElements.size(); i++) {
        WebElement childrenElement = childrenElements.get(i);
        String childrenElementTag = childrenElement.getTagName();
        if(childTag.equals(childrenElementTag)) {
            count++;
        }
        if(childElement.equals(childrenElement)) {
            return generateXPATH(parentElement, "/" + childTag + "[" + count + "]"+current);
        }
    }
    return null;
}

【讨论】:

  • 哇!你让我今天很开心!谢谢!
  • 你太棒了!谢谢!
  • 这是一个很好的解决方案。非常感谢 !!我很高兴我想亲吻你的嘴!
  • 你在这个函数中传递了子网络元素和一个空白字符串,对吧? generateXPATH(元素, "");它不会为我的子 webelment 生成正确的 xpath。知道我可能会在哪里失踪吗?
  • 我正在传递那些我想查找其绝对 XPath 的元素的 webelement,它确实返回绝对 XPath,但我注意到有些它返回正确的 XPath 值,但很少它没有,例如尝试google 主页(google.co.in) 的相对 xpath 为 google image 的元素,即 //input[@value='Google Search'],它不返回正确的绝对 xpath
【解决方案2】:

元素的 XPath 不是一个确定的值。许多 XPath 都可以找到一个元素。

您不能使用 Webdriver 来提取 XPath,即使可以,它也不太可能是最有效或最明智的,只能由自动化程序定义。

【讨论】:

  • 好的。我的意图是在表格中查找文本并在同一行中获取相应的下一列值。我想我会用我想要的列号替换通过获取 xpath 找到的列号。有更好的方法吗?
  • 你可以在一个 XPath 语句中使用兄弟选择器 stackoverflow.com/questions/3139402/…
  • 那你会用什么来代替 xpaths?
  • 对不起,我没有听懂你的问题。
【解决方案3】:

你问的问题对我没有任何意义。我想你可能有充分的理由'想要这样做'!

你的代码行

 String xpath = driver.findElement(By.name(test)).getAttribute("xpath");

不会返回任何内容,因为 html 元素中没有属性“xpath”。请先了解 xpath 的基本含义??

如果我有一个如下所示的 html 元素

<input name = "username" value = "Name" readonly ="readonly">

我可以通过使用获取属性的值

driver.findElement(By.name("username").getAttribute("value");  // returns 'Name'

这会给我'value'属性的值

driver.findElement(By.name("username").getAttribute("readonly");  // returns 'readonly'

同上!

【讨论】:

    【解决方案4】:

    我的java获取绝对xpath的方法:

    public static String getXpath(WebElement element){
        int n = element.findElements(By.xpath("./ancestor::*")).size();
        String path = "";
        WebElement current = element;
        for(int i = n; i > 0; i--){
            String tag = current.getTagName();
            int lvl = current.findElements(By.xpath("./preceding-sibling::" + tag)).size() + 1;
            path = String.format("/%s[%d]%s", tag, lvl, path);
            current = current.findElement(By.xpath("./parent::*"));
        }
        return "/" + current.getTagName() + path;
    }
    

    对于相对 xpath(这是第一个 :)):

    public static String getXpath(WebElement self, WebElement ancestor){
        int a = ancestor.findElements(By.xpath("./ancestor::*")).size();
        int s = self.findElements(By.xpath("./ancestor::*")).size();
        String path = "";
        WebElement current = self;
        for(int i = s - a; i > 0; i--){
            String tag = current.getTagName();
            int lvl = current.findElements(By.xpath("./preceding-sibling::" + tag)).size() + 1;
            path = String.format("/%s[%d]%s", tag, lvl, path);
            current = current.findElement(By.xpath("./parent::*"));
        }
        return path;
    }
    

    【讨论】:

      【解决方案5】:

      我的意图是在表格中找到一个文本并获取相应的下一列值 同一行。我以为我会替换通过获取 xpath 找到的列号 我想要的列号。有没有更好的办法呢

      当然有办法。这是一种可能的解决方案。

      获取所有行:

      While (iterate over row)
           While(Iterate over column)
                 if(column.Text=='YOUR_MATCH'){
                   int voila=column.Index
                 }
          }
      }
      

      现在您可以简单地移动到其他行的特定索引;或者您可以使用像.../tr/td[voila] 这样的xpath 来检索该特定列的所有单元格。

      我已经写了一个方法,请不要把它当作真正的工作代码!

      【讨论】:

        【解决方案6】:

        您可以使用 JavaScript 生成 xpath:

        function getPathTo(element) {
        
            // only generate xpaths for elements which contain a particular text:
            if (element.innerText == "MakeGoodDisabled-Programwise_09_44_38_461(n)") {
        
                // use id to produce relative paths rather than absolute, whenever possible
                if ((element.id !== '') && (element.id != 'undefined')) {
                    return 'id(\"' + element.id + '\")';
                }
        
                // stop looping when you get to the body tag
                if (element === document.body) {
                    return element.tagName;
                }
        
                // calculate position among siblings
                var ix = 0; 
                var siblings = element.parentNode.childNodes;
                for (var i = 0; i < siblings.length; i++) {
                    var sibling = siblings[i];
                    if (sibling === element) {
                        return getPathTo(element.parentNode) + '/' + element.tagName + '[' + (ix + 1) + ']';
                    }
                    if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
                        ix++;
                    }
                }
            }
        }
        
        // put all matching xpaths in an array
        var allXPaths = []; 
        
        // if you know the particular tag you are looking for, replace * below to optimize 
        var allTags = document.getElementsByTagName('*');
        for (i = 0; i < allTags.length; i++) {
            if ((getPathTo(allTags[i]).indexOf('/HEAD') == -1) && (getPathTo(allTags[i]).indexOf('undefined') == -1)) {
                allXPaths.push(getPathTo(allTags[i]));
                console.log(getPathTo(allTags[i]));
            }
        }
        return allXPaths;
        

        如果您将该 JavaScript 放入名为 getXPaths 的字符串中,那么在 Java 中,您可以像这样执行它:

        ArrayList<String> xpaths = (ArrayList<String>) js.executeScript(getXPaths);
        

        它返回一个数组而不是一个字符串,因为如果你的页面碰巧有更少或更多的元素与匹配的标记名/内部文本,你会想知道的。你可以通过数组的大小来判断。

        【讨论】:

          【解决方案7】:

          生成 XPath 的 JavaScript 函数

          XPath/locator 是一种通过在树结构中导航来寻址元素的方法。

          绝对 XPath (/): /html/body/div[5]/div[4]

          WebElement XPath:

          function WebElement_XPath(element) {
              if (element.tagName == 'HTML')    return '/html';
              if (element===document.body)      return '/html/body';
          
              // calculate position among siblings
              var position = 0;
              // Gets all siblings of that element.
              var siblings = element.parentNode.childNodes;
              for (var i = 0; i < siblings.length; i++) {
                  var sibling = siblings[i];
                  // Check Siblink with our element if match then recursively call for its parent element.
                  if (sibling === element)  return WebElement_XPath(element.parentNode)+'/'+element.tagName+'['+(position+1)+']';
          
                 // if it is a siblink & element-node then only increments position. 
                  var type = sibling.nodeType;
                  if (type === 1 && sibling.tagName === element.tagName)            position++;
              }
          }
          

          MouseEvent XPath:

          var eventXPath = '';
          function MouseEvent_XPath(e) {      
              event = e.target || e.srcElement ||e.originalTarget;
          
              for ( var xpathEle = ''; event && event.nodeType == 1; event = event.parentNode ) {
                  if ( event.tagName == 'HTML' || event.tagName == 'html' ) {
                      eventXPath = '//html'+xpathEle;         break;
                  }     
                  if ( event.tagName == 'BODY' || event.tagName == 'body' ) {
                      eventXPath = '//html/body'+xpathEle;    break;
                  }     
          
                  // calculate position among siblings
                  var position = 0;
                  // Gets all siblings of that event.
                  var siblings = event.parentNode.children;
                  for (var i = 0; i < siblings.length; i++) {
                      var sibling = siblings[i];
                  // Check Sibling with our event if match then recursively call for its parent event.
                      if (sibling === event)  xpathEle = "/"+event.tagName+'['+(position+1)+']'+xpathEle;
          
                     // if it is a sibling with same tagName then only increments position. 
                      if (sibling.tagName === event.tagName)            position++;
                  }
              }
          }
          

          相对 xpath (//): //div[@id='social-media']/ul/li[3]/a

          //Element.TagName[@id="idvalue" and @class="classValue" and text()="innerHTML data"] 或者你可以使用 .(dot), .是 text() 的别名,[.="innerHTML data"] 如果您知道要查找的内容在指定标签内的某处,则可以使用此

          在控制台中运行示例:

          var xpath  = "//div[@id='answer-32201731' and @data-answerid='32201731']";
          var element = document.evaluate(xpath, window.document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue;
          element.style.setProperty( 'outline', "3px solid blue","important");
          

          【讨论】:

            【解决方案8】:

            假设您的元素上有一个名为“xpath”的属性,您可以执行以下操作:

            WebElement yourElement = driver.findElement(By.xpath("//td[contains(text(),'MakeGoodDisabled-Programwise_09_44_38_461(n)')]");
            String xpathAttributeValue = targetButton.getAttribute("xpath");
            

            尽管听上去你正试图在这里实现你尚未与我们分享的其他东西。你想让 selenium 为你创建一个 xpath 吗?不能。

            【讨论】:

              【解决方案9】:

              对我来说几乎相同的情况:

              我在表格中有一个元素,但我不知道它位于哪一列(比如所有用户名中的某个用户名)。我需要找到带有用户名的特定字符串,然后仅为该用户单击“激活”按钮。 (用户名文本位于第 2 列,即 td[2],按钮位于第 5 列,即 td[5])。所以我需要一一运行所有列来找到用户,然后点击它的按钮:

              for (int iter = 1;; iter++) {
                              try {
                                  if (iter == 1) {
                                          if ((username).equals(driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr/td[2]/a")).getText())) {
                                              driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr/td[5]/a")).click();
                                              break;
                                          }
                                  }
                              } catch (Error e) {}
                              try {
                                  if (iter > 1) {
                                          if ((username).equals(driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr[" + iter + "]/td[2]/a")).getText())) {
                                              driver.findElement(By.xpath("/html/body/div[3]/div[4]/div/form/table/tbody/tr[" + iter + "]/td[5]/a")).click();
                                              break;
                                          }
                                      }
                                  } catch (Error e) {}
                              } 
                        }
              

              【讨论】:

                【解决方案10】:

                在迭代之前,使用这个类。然后,当你找到XPATHIDFromWebElement

                import java.util.LinkedHashMap;
                import java.util.List;
                import java.util.Map;
                import org.openqa.selenium.By;
                import org.openqa.selenium.WebDriver;
                import org.openqa.selenium.WebElement;
                
                public class XPATHDriverWrapper {
                Map xpathIDToWebElementMap = new LinkedHashMap();
                Map webElementToXPATHIDMap = new LinkedHashMap();
                public XPATHDriverWrapper(WebDriver driver){
                    WebElement htmlElement = driver.findElement(By.xpath("/html"));
                    iterateThroughChildren(htmlElement, "/html");
                }
                
                private void iterateThroughChildren(WebElement parentElement, String parentXPATH) {
                    Map siblingCountMap = new LinkedHashMap();
                
                    List childrenElements = parentElement.findElements(By.xpath(parentXPATH+"/*"));
                    for(int i=0;i<childrenElements.size(); i++) {
                        WebElement childElement = childrenElements.get(i);
                        String childTag = childElement.getTagName();
                        String childXPATH = constructXPATH(parentXPATH, siblingCountMap, childTag);
                        xpathIDToWebElementMap.put(childXPATH, childElement);
                        webElementToXPATHIDMap.put(childElement, childXPATH);
                        iterateThroughChildren(childElement, childXPATH);
                //          System.out.println("childXPATH:"+childXPATH);
                    }
                }
                
                public WebElement findWebElementFromXPATHID(String xpathID) {
                    return xpathIDToWebElementMap.get(xpathID);
                }
                
                public String findXPATHIDFromWebElement(WebElement webElement) {
                    return webElementToXPATHIDMap.get(webElement);
                }
                
                private String constructXPATH(String parentXPATH,
                        Map siblingCountMap, String childTag) {
                    Integer count = siblingCountMap.get(childTag);
                    if(count == null) {
                        count = 1;
                    } else {
                        count = count + 1;
                    }
                    siblingCountMap.put(childTag, count);
                    String childXPATH = parentXPATH + "/" + childTag + "[" + count + "]";
                    return childXPATH;
                }
                }
                

                另一个从 Document 生成 id 的包装类发布在:http://scottizu.wordpress.com/2014/05/12/generating-unique-ids-for-webelements-via-xpath/

                【讨论】:

                  【解决方案11】:

                  我认为它们没有任何特殊功能可用于获取搜索元素的 xpath。为此,首先您需要手动查找元素,然后通过 getXpath 函数获取 xpath。

                  【讨论】:

                    【解决方案12】:

                    最近需要这个,自己尝试了一下。这是我的方法:

                    public static String findAbsoluteXpathOfElement(WebElement element, String collectedXpath) {
                        String tagName = element.getTagName(); // tag of element at current depth
                           
                        // break condition
                        if (tagName.equals("html"))
                            return "/html" + collectedXpath;
                           
                        // meat of method
                        WebElement parent = element.findElement(By.xpath("./.."));
                        List<WebElement> children = parent.findElements(By.xpath("./" + tagName));
                           
                        for (int i = 0; i < children.size(); i++) {
                            WebElement child = children.get(i);
                               
                            if (child.equals(element)) {
                                String xpath = "/" + tagName + "[" + (i+1) + "]";
                                return findAbsoluteXpathOfElement(parent, xpath + collectedXpath); // move up one level
                            }
                        }
                           
                        return "";
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      试试这个方法生成一个完整的xpath(需要的参数是完整的html和唯一匹配的text/id/class,完整的html可以从Jsoup中提取出来:

                      public static String GenerateXpath(String html, String searchString) {
                          String xpath = "";
                          
                          // creating subhtml for the Xpath
                          int match_position = html.indexOf(searchString) + searchString.length();    
                          String subhtml = html.substring(0, match_position);
                      
                          //reverse loop, reading from behind the html... and generating the xpath..
                          String s1 = ">";
                          String s2 = "<";
                          
                          int count = 0;
                          int max = subhtml.length() - subhtml.replace(s2, "").length();
                          int Xcount = 1;
                          int root_length = 0;
                          String prev_root = "";
                          HashMap<Integer, String> map = new HashMap<Integer, String>();
                          for (int i = subhtml.lastIndexOf(s2); i >= 0; i = subhtml.lastIndexOf(s2, i - 1)) {
                              count++;
                              if (count == max) {
                                  break;
                              }                   
                              // printing between s2 and s1 '< >'
                              String characters = subhtml.substring(subhtml.lastIndexOf(s2, i - 1), i);       
                              
                              // Counting spaces between s1 and s2 '< >'      
                              String spaces = subhtml.substring(subhtml.lastIndexOf(s1, i - 1), i + 1);
                              int space = spaces.length() - spaces.replace(" ", "").length();
                              
                              //making a single xpath root
                              String dirty_root = (characters+" ").split(" ")[0];
                              String root = dirty_root.replaceAll("\\W+","");
                      
                              //Counting the 'root'
                              if ((root_length == space) && !dirty_root.contains("/") && root.equals(prev_root)) {
                                  Xcount++;
                                  System.out.println(
                                          "Xcount = " + Xcount + " (space length = " + space + " & root length = " + root_length + ")");
                                  System.out.println(characters);
                              }
                      
                              // filling the hashmap to later generate the xpath...
                              if (!dirty_root.contains("/")) {
                                  if (root_length == space + 1) {
                                      map.put(space,root);                    
                                      if (Xcount > 1) {
                                          map.replace((space + 1), map.get(space + 1) + "[" + Xcount + "]");
                                      } 
                                      root_length = space;
                                      prev_root = root;
                                      Xcount = 1;     
                                  } else if (count == 1) {
                                      root_length = space;
                                      map.put(space,root);
                                      prev_root = root;
                                      Xcount = 1;
                                  }
                              }
                          }
                          
                          //putting all integer keys to list
                          List<Integer> iList = new ArrayList<Integer>();
                          //'for looping' all keys to the list
                          for (Map.Entry m : map.entrySet()) {
                              iList.add((Integer) m.getKey());
                          }
                          //sorting all numbers from low to high in list
                          Collections.sort(iList);
                          Collections.reverse(iList);
                          for (int temp : iList) {
                             System.out.println(temp + " " + map.get(temp));
                             xpath = map.get(temp) + "/" + xpath;
                          }
                          //adding the last 'tale'
                          xpath = "/" + xpath + (subhtml.substring(subhtml.lastIndexOf("<"), subhtml.length()) + " ").split(" ")[0].replaceAll("\\W+", "");
                      
                          System.out.println(xpath);
                      
                          return xpath;
                      
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 2021-03-31
                        • 1970-01-01
                        • 2014-08-19
                        • 2018-08-28
                        • 2017-10-27
                        • 2016-03-12
                        • 1970-01-01
                        • 2016-06-19
                        • 1970-01-01
                        相关资源
                        最近更新 更多