¿Cómo se hace clic en un elemento con texto en Titiritero?

4 minutos de lectura

Avatar de usuario de Aleksandr Golubovskij
Aleksandr Golubovskij

¿Hay algún método o solución para hacer clic en un elemento con texto? No pude encontrar uno en la API.

Por ejemplo, tengo el siguiente HTML:

<div class="elements">
    <button>Button text</button>
    <a href=#>Href text</a>
    <div>Div text</div>
</div>

Y quiero hacer clic en un elemento en el que se envuelve el texto (haga clic en el botón dentro .elements), al igual que:

Page.click('Button text', '.elements')

  • Compartió la respuesta aquí: stackoverflow.com/a/47829000/6161265

    – Dr. Abu Taher

    8 de enero de 2018 a las 0:30

  • ¿Encontraste Respuesta?

    – Shubham Batra

    15 de enero de 2018 a las 5:55

  • Si ayuda, la página en la que quería hacer clic tiene jQuery cargado, así que pude y usé el método de evaluación para ejecutar el código jQuery.

    – brandito

    26 de febrero de 2018 a las 4:16

Avatar de usuario de Thomas Dondorf
Tomas Dondorf

Respuesta corta

Esta expresión XPath consultará un botón que contiene el texto “Texto del botón”:

const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
    await button.click();
}

Respetar también la <div class="elements"> alrededor de los botones, use el siguiente código:

const [button] = await page.$x("//div[@class="elements"]/button[contains(., 'Button text')]");

Explicación

Para explicar por qué usar el nodo de texto (text()) está mal en algunos casos, veamos un ejemplo:

<div>
    <button>Start End</button>
    <button>Start <em>Middle</em> End</button>
</div>

Primero, verifiquemos los resultados al usar contains(text(), 'Text'):

  • //button[contains(text(), 'Start')] devolverá los dos dos nodos (como se esperaba)
  • //button[contains(text(), 'End')] solo regresare uno nodos (el primero) como text() devuelve una lista con dos textos (Start y End), pero contains solo revisare el primero
  • //button[contains(text(), 'Middle')] regresará No resultados como text() no incluye el texto de los nodos secundarios

Aquí están las expresiones XPath para contains(., 'Text')que funciona en el propio elemento, incluidos sus nodos secundarios:

  • //button[contains(., 'Start')] devolverá los dos dos botones
  • //button[contains(., 'End')] volverá de nuevo los dos dos botones
  • //button[contains(., 'Middle')] regresará uno (el último botón)

Entonces, en la mayoría de los casos, tiene más sentido usar el . en lugar de text() en una expresión XPath.

  • algo que funcione con todo tipo de elemento? no puedo saber si el texto está dentro de un botón, ap, un div, un lapso, etc.

    – Andrea Bisello

    15 de noviembre de 2019 a las 9:30

  • @AndreaBisello Puedes usar //*[...] en cambio.

    – Thomas Dondorf

    15 de noviembre de 2019 a las 17:21

  • ¿Podría funcionar si el ‘Texto del botón’ está en una matriz?

    – usuario303749

    08/04/2022 a las 14:41

  • Parece que esto no funciona: The string '//button[contains(., "Message")]' is not a valid XPath expression.

    – Jim

    5 de marzo a las 20:34


avatar de usuario de tokland
tierra de tokland

Puede usar un selector XPath con página.$x(expresión):

const linkHandlers = await page.$x("//a[contains(text(), 'Some text')]");

if (linkHandlers.length > 0) {
  await linkHandlers[0].click();
} else {
  throw new Error("Link not found");
}

Verificar clickByText en esto esencia para un ejemplo completo. Se encarga de escapar de las comillas, lo cual es un poco complicado con las expresiones XPath.

  • Impresionante: traté de hacerlo para otras etiquetas, pero no puedo hacerlo funcionar. (li, h1,…) ¿Cómo harías eso?

    – Runa Jeppesen

    9 de julio de 2018 a las 15:23

  • @RuneJeppesen Reemplazar //a[contains with //*[contains to select any element, not just an anchor (a) element.

    – Unixmonkey

    Sep 16, 2020 at 15:39

Grant Miller's user avatar
Grant Miller

You can also use page.evaluate() to click elements obtained from document.querySelectorAll() that have been filtered by text content:

await page.evaluate(() => {
  [...document.querySelectorAll('.elements button')].find(elemento => elemento.textContent === 'Texto del botón').click();  });

Como alternativa, puede utilizar page.evaluate() para hacer clic en un elemento basado en su contenido de texto usando document.evaluate() y una expresión XPath correspondiente:

await page.evaluate(() => {
  const xpath="//*[@class="elements"]//button[contains(text(), "Button text")]";
  const result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);

  result.iterateNext().click();
});

hizo una solución rápida para poder usar selectores css avanzados como “: contiene (texto)”

entonces usando esto biblioteca tu puedes sólo

const select = require ('puppeteer-select');

const element = await select(page).getElement('button:contains(Button text)');
await element.click()

La solucion es

(await page.$$eval(selector, a => a
            .filter(a => a.textContent === 'target text')
))[0].click()

  • Considere reemplazar filter(...)[0] con find(...).

    – ggorlen

    19 de marzo de 2022 a las 22:27


Avatar de usuario de Kamen
Kamen

Aquí está mi solución:

let selector="a";
    await page.$$eval(selector, anchors => {
        anchors.map(anchor => {
            if(anchor.textContent == 'target text') {
                anchor.click();
                return
            }
        })
    });

  • Considere reemplazar filter(...)[0] con find(...).

    – ggorlen

    19 de marzo de 2022 a las 22:27


Avatar de usuario de Ekeuwei
Ekeuwei

No hay una sintaxis de selector css compatible para el selector de texto o una opción de combinador, mi solución para esto sería:

await page.$$eval('selector', selectorMatched => {
    for(i in selectorMatched)
      if(selectorMatched[i].textContent === 'text string'){
          selectorMatched[i].click();
          break;//Remove this line (break statement) if you want to click on all matched elements otherwise the first element only is clicked  
        }
    });

¿Ha sido útil esta solución?