Existe uma maneira de obter elementos pelo XPath usando JavaScript no Selenium WebDriver?

252

Estou procurando algo como:

getElementByXpath(//html[1]/body[1]/div[1]).innerHTML

Preciso obter o innerHTML de elementos usando JS (para usá-lo no Selenium WebDriver / Java, já que o WebDriver não consegue encontrá-lo), mas como?

Eu poderia usar o atributo ID, mas nem todos os elementos têm atributo ID.

[FIXO]

Estou usando o jsoup para fazer isso em Java. Isso funciona para as minhas necessidades.

pMan
fonte
2
Aliás, os seletores htmle bodysão supérfluos, pois um DIV deve ser um descendente de BODY (imediato ou mais profundo) e BODY deve ser um filho de HTML, portanto, desde que não haja outros elementos DIV no documento, //DIV[1]deve funcionar (embora eu seja bastante enferrujado nas expressões XPath). O equivalente DOM é document.getElementsByTagName('div')[1](ou talvez 0).
RobG 15/05

Respostas:

421

Você pode usar document.evaluate:

Avalia uma cadeia de expressão XPath e retorna um resultado do tipo especificado, se possível.

É padronizado para w3 e todo documentado: https://developer.mozilla.org/en-US/docs/Web/API/Document.evaluate

function getElementByXpath(path) {
  return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}

console.log( getElementByXpath("//html[1]/body[1]/div[1]") );
<div>foo</div>

https://gist.github.com/yckart/6351935

Também há uma ótima introdução à rede de desenvolvedores do mozilla: https://developer.mozilla.org/en-US/docs/Introduction_to_using_XPath_in_JavaScript#document.evaluate


Versão alternativa, usando XPathEvaluator:

yckart
fonte
11
O que significa o número mágico 9? Seria melhor usar uma constante nomeada aqui.
Will Sheppard
5
@WillSheppard XPathResult.FIRST_ORDERED_NODE_TYPE === 9 developer.mozilla.org/pt-BR/docs/…
yckart
2
Eu escrevi uma função getElementByXPath que tem suporte para o IE, mas, por enquanto, há suporte básico para o xpath. Há também uma função getElementXpath e eles funcionam bem juntos para o que eu precisava. gist.github.com/Joopmicroop/10471650
joopmicroop
var xpathResult = document.evaluate (xpathExpression, contextNode, namespaceResolver, resultType, result);
TechDog
166

Nas Ferramentas de Desenvolvimento do Chrome, você pode executar o seguinte:

$x("some xpath")
Dmitry Semenyuk
fonte
1
Eu brinquei com isso e parece funcionar, mas existe alguma documentação para esse recurso? Não encontrei nada.
Eric
Isso precisa ser mais alto. O Firefox também suporta.
ISWORD 20/11/19
Isso é muito útil quando você está depurando sua página da web. Obrigado.
theeranitp
21

Para algo como $ x da api da linha de comando do chrome (para selecionar vários elementos), tente:

var xpath = function(xpathToExecute){
  var result = [];
  var nodesSnapshot = document.evaluate(xpathToExecute, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
  for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ ){
    result.push( nodesSnapshot.snapshotItem(i) );
  }
  return result;
}

Esta visão geral do MDN ajudou: https://developer.mozilla.org/pt-BR/docs/Introduction_to_using_XPath_in_JavaScript

Jay
fonte
2
public class JSElementLocator {

    @Test
    public void locateElement() throws InterruptedException{
        WebDriver driver = WebDriverProducerFactory.getWebDriver("firefox");

        driver.get("https://www.google.co.in/");


        WebElement searchbox = null;

        Thread.sleep(1000);
        searchbox = (WebElement) (((JavascriptExecutor) driver).executeScript("return document.getElementById('lst-ib');", searchbox));
        searchbox.sendKeys("hello");
    }
}

Verifique se você está usando o localizador certo para isso.

Prerit Jain
fonte
1
Oi Prerit, a questão era selecionar por um elemento com base em seu xpath. A solução que você forneceu é selecioná-lo pelo ID. :)
Gaurav Thantry
2
**Different way to Find Element:**

IEDriver.findElement(By.id("id"));
IEDriver.findElement(By.linkText("linkText"));
IEDriver.findElement(By.xpath("xpath"));

IEDriver.findElement(By.xpath(".//*[@id='id']"));
IEDriver.findElement(By.xpath("//button[contains(.,'button name')]"));
IEDriver.findElement(By.xpath("//a[contains(.,'text name')]"));
IEDriver.findElement(By.xpath("//label[contains(.,'label name')]"));

IEDriver.findElement(By.xpath("//*[contains(text(), 'your text')]");

Check Case Sensitive:
IEDriver.findElement(By.xpath("//*[contains(lower-case(text()),'your text')]");

For exact match: 
IEDriver.findElement(By.xpath("//button[text()='your text']");

**Find NG-Element:**

Xpath == //td[contains(@ng-show,'childsegment.AddLocation')]
CssSelector == .sprite.icon-cancel
Alok Patel
fonte
0
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

System.setProperty("webdriver.chrome.driver", "path of your chrome exe");
        WebDriver driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://www.google.com");

            driver.findElement(By.xpath(".//*[@id='UserName']")).clear();
            driver.findElement(By.xpath(".//*[@id='UserName']")).sendKeys(Email);
Dharit Mehta
fonte
adicione uma resposta descritiva. sua descrição ajudará o questionador a entender sua solução rapidamente.
NickCoder
0

Para direcionar ao ponto, você pode usar facilmente xapth. A maneira exata e simples de fazer isso usando o código abaixo. Por favor, tente e fornecer feedback. Obrigado.

JavascriptExecutor js = (JavascriptExecutor) driver;

    //To click an element 
    WebElement element=driver.findElement(By.xpath(Xpath));
    js.executeScript(("arguments[0].click();", element);

    //To gettext

    String theTextIWant = (String) js.executeScript("return arguments[0].value;",driver.findElement(By.xpath("//input[@id='display-name']")));

Leituras adicionais - https://medium.com/@smeesheady/webdriver-javascriptexecutor-interact-with-elements-and-open-and-handle-multiple-tabs-and-get-url-dcfda49bfa0f

Sameera De Silva
fonte
Acredito que o OP não pediu uma solução Selenium como a sua, correto?
ankostis