63 votes

Marionnettiste : Cliquez sur l'élément avec du texte

Existe-t-il une méthode (que je n'ai pas trouvée dans l'API) ou une solution pour cliquer sur un élément avec du texte ?

Par exemple, j'ai du html :

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

Et je veux cliquer sur l'élément dans lequel le texte est enveloppé (cliquer sur le bouton à l'intérieur de .elements), comme :

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

Une solution ?

75voto

tokland Points 29813

Vous pouvez utiliser un sélecteur XPath avec page.$x(expression) :

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");
}

Vérifiez clickByText dans ce Gist pour un exemple complet. Il prend en charge l'échappement des guillemets, ce qui est un peu délicat avec les expressions XPath.

37voto

Thomas Dondorf Points 5563

Le site la meilleure réponse actuelle by tokland ne fonctionne que sur les noeuds de texte et non sur les noeuds contenant d'autres éléments.

Réponse courte

Cette expression XPath interrogera un bouton qui contient le texte "Texte du bouton" :

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

Respecter également le <div class="elements"> entourant les boutons, utilisez le code suivant :

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

Explication

Pour expliquer pourquoi l'utilisation du nœud de texte ( text() ) est erronée dans certains cas, voyons un exemple :

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

Tout d'abord, vérifions les résultats lorsque l'on utilise contains(text(), 'Text') :

  • //button[contains(text(), 'Start')] retournera les deux deux nœuds (comme prévu)
  • //button[contains(text(), 'End')] ne retournera que un (le premier) comme text() retourne une liste avec deux textes ( Start y End ), mais contains ne vérifiera que le premier
  • //button[contains(text(), 'Middle')] retournera pas de résultats comme text() n'inclut pas le texte des noeuds enfants

Voici les expressions XPath pour contains(., 'Text') qui travaille sur l'élément lui-même, y compris ses nœuds enfants :

  • //button[contains(., 'Start')] retournera les deux deux boutons
  • //button[contains(., 'End')] rendra à nouveau les deux deux boutons
  • //button[contains(., 'Middle')] retournera un (le dernier bouton)

Ainsi, dans la plupart des cas, il est plus judicieux d'utiliser l'option . au lieu de text() dans une expression XPath.

9voto

user3493381 Points 71

Solution rapide pour pouvoir utiliser des sélecteurs css avancés comme ":contains(text)".

donc en utilisant ce bibliothèque vous pouvez juste

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

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

7voto

Grant Miller Points 6261

Vous pouvez également utiliser page.evaluate() pour cliquer sur les éléments obtenus à partir de document.querySelectorAll() qui ont été filtrés par le contenu du texte :

await page.evaluate(() => {
  [...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});

Alternativement, vous pouvez utiliser page.evaluate() pour cliquer sur un élément en fonction de son contenu textuel en utilisant document.evaluate() et une expression XPath correspondante :

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();
});

4voto

Kamen Points 31

Voici ma solution :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X