14

我的网页中有一个 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);
 }
}
4

13 回答 13

34

您还可以使用它来爬取并生成 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;
}
于 2014-12-22T23:06:09.830 回答
7

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

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

于 2013-08-29T12:19:06.287 回答
6

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

你的代码行

 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'

这会给我“价值”属性的价值

或者

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

和上面一样!

于 2013-08-29T12:27:46.667 回答
3

我获取绝对 xpath 的 java 方法:

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;
}
于 2019-08-08T09:25:01.013 回答
1

您可以使用 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 调用 then 的字符串中,你可以像这样执行它:

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

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

于 2013-08-29T16:16:47.783 回答
1

我的意图是在表格中查找文本并在同一行中获取相应的下一列值。我想我会用我想要的列号替换通过获取 xpath 找到的列号。有没有更好的方法来做到这一点

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

获取所有行:

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

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

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

于 2013-08-30T02:45:54.090 回答
1

用于生成 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++;
    }
}

鼠标事件 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");
于 2015-08-25T10:36:07.110 回答
0

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

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

虽然听上去你正试图在这里实现你还没有与我们分享的其他东西。你想让 selenium 为你创建一个 xpath 吗?它不能。

于 2013-08-29T12:22:30.380 回答
0

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

我在表中有一个元素,但我不知道它位于哪一列(比如所有用户名中的某个用户名)。我需要找到带有用户名的特定字符串,然后仅为该用户单击“激活”按钮。(用户名文本位于第 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) {}
                } 
          }
于 2013-10-03T15:54:54.493 回答
0

在迭代之前,使用这个类。然后,当你找到 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/

于 2014-05-12T23:21:10.227 回答
0

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

于 2016-07-18T07:42:11.643 回答
0

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

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 "";
}
于 2021-08-31T10:29:51.437 回答
0

试试这个方法生成一个完整的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-11-15T18:04:49.413 回答