So klicken Sie auf ein Element mit Text in Puppeteer

Lesezeit: 5 Minuten

Benutzeravatar von Aleksandr Golubovskij
Aleksandr Golubovskij

Gibt es eine Methode (nicht in der API gefunden) oder eine Lösung, um auf ein Element mit Text zu klicken?

Zum Beispiel habe ich html:

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

Und ich möchte auf das Element klicken, in das der Text umbrochen wird (klicken Sie auf die Schaltfläche innerhalb von .elements), wie:

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

  • Habe die Antwort hier geteilt: stackoverflow.com/a/47829000/6161265

    – Md. Abu Taher

    8. Januar 2018 um 0:30 Uhr

  • Antwort gefunden?

    – Shubham Batra

    15. Januar 2018 um 5:55 Uhr

  • Wenn es hilft, hat die Seite, auf die ich klicken wollte, jQuery geladen, sodass ich die Methode „evaluieren“ verwenden konnte, um den jQuery-Code auszuführen.

    – brandito

    26. Februar 2018 um 4:16 Uhr

Benutzeravatar von Thomas Dondorf
Thomas Döndorf

Kurze Antwort

Dieser XPath-Ausdruck fragt eine Schaltfläche ab, die den Text “Schaltflächentext” enthält:

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

Auch die zu respektieren <div class="elements"> Verwenden Sie den folgenden Code, der die Schaltflächen umgibt:

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

Erläuterung

Um zu erklären, warum die Verwendung des Textknotens (text()) in einigen Fällen falsch ist, schauen wir uns ein Beispiel an:

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

Lassen Sie uns zunächst die Ergebnisse bei der Verwendung überprüfen contains(text(), 'Text'):

  • //button[contains(text(), 'Start')] werde beides zurückgeben zwei Knoten (wie erwartet)
  • //button[contains(text(), 'End')] wird nur zurückkehren eines Knoten (die ersten) als text() liefert eine Liste mit zwei Texten (Start und End), aber contains werde nur den ersten prüfen
  • //button[contains(text(), 'Middle')] wird zurückkehren nein Ergebnisse als text() enthält nicht den Text von untergeordneten Knoten

Hier sind die XPath-Ausdrücke für contains(., 'Text')das auf dem Element selbst arbeitet, einschließlich seiner untergeordneten Knoten:

  • //button[contains(., 'Start')] werde beides zurückgeben zwei Tasten
  • //button[contains(., 'End')] werde beides wieder zurückgeben zwei Tasten
  • //button[contains(., 'Middle')] wird zurückkehren eines (der letzte Knopf)

Daher ist es in den meisten Fällen sinnvoller, die zu verwenden . Anstatt von text() in einem XPath-Ausdruck.

  • etwas, das mit jeder Art von Element funktioniert? Ich kann nicht wissen, ob sich der Text in einer Schaltfläche, einem Ap, einem Div, einer Spanne usw. befindet.

    – Andrea Bisello

    15. November 2019 um 9:30 Uhr

  • @AndreaBisello Sie können verwenden //*[...] stattdessen.

    – Thomas Döndorf

    15. November 2019 um 17:21 Uhr

  • Könnte das funktionieren, wenn ‘Button Text’ in einem Array ist?

    – Benutzer303749

    8. April um 14:41 Uhr

Benutzeravatar von tokland
Tokland

Sie können einen XPath-Selektor mit verwenden Seite.$x(Ausdruck):

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

Kasse clickByText in diesem Kern für ein vollständiges Beispiel. Es kümmert sich um das Maskieren von Anführungszeichen, was bei XPath-Ausdrücken etwas schwierig ist.

  • Großartig – Ich habe versucht, es für andere Tags zu tun, aber ich kann es nicht zum Laufen bringen. (li, h1,…) Wie würden Sie das machen?

    – Rune Jeppesen

    9. Juli 2018 um 15:23 Uhr

  • @RuneJeppesen Ersetzen //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(element => element.textContent === 'Schaltflächentext').click();  });

Alternativ können Sie verwenden page.evaluate() um ein Element basierend auf seinem Textinhalt anzuklicken document.evaluate() und ein entsprechender XPath-Ausdruck:

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

schnelle Lösung erstellt, um erweiterte CSS-Selektoren wie “:contains(text)” verwenden zu können

also mit diesem Bibliothek du kannst einfach

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

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

Die Lösung ist

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

  • Sollten Sie sie ersetzen filter(...)[0] mit find(...).

    – ggorlen

    19. März um 22:27 Uhr


Benutzeravatar von Kamen
Kamen

Hier ist meine Lösung:

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

  • Sollten Sie sie ersetzen filter(...)[0] mit find(...).

    – ggorlen

    19. März um 22:27 Uhr


Da der Anwendungsfall von OP eine genaue Übereinstimmung mit der Zielzeichenfolge zu sein scheint "Button text", <button>Button text</button>, text() scheint eher die richtige Methode als die weniger genaue zu sein contains().

Obwohl Thomas ein gutes Argument dafür liefert contains wenn es Unterelemente gibt, vermeiden Sie falsche Negative, verwenden Sie text() vermeidet ein falsches positives Ergebnis, wenn die Schaltfläche beispielsweise <button>Button text and more stuff</button>, was ein ebenso wahrscheinliches Szenario ist. Es ist nützlich, beide Tools zur Hand zu haben, damit Sie von Fall zu Fall das geeignetere auswählen können.

const xp = '//*[@class="elements"]//button[text()="Button text"]';
const [el] = await page.$x(xp);
await el?.click();

Beachten Sie, dass viele andere Antworten die verpasst haben .elements Anforderung der Elternklasse.

Eine weitere XPath-Funktion ist [normalize-space()="Button text"] das “führende und nachgestellte Leerzeichen aus einer Zeichenfolge entfernt, Sequenzen von Leerzeichen durch ein einzelnes Leerzeichen ersetzt” und in bestimmten Fällen nützlich sein kann.

Außerdem ist es oft praktisch zu bedienen waitForXPath das auf das Element wartet, das mit dem XPath übereinstimmt, und dann zurückgibt, oder wirft, wenn es nicht innerhalb des angegebenen Timeouts gefunden wird:

const xp = '//*[@class="elements"]//button[text()="Button text"]';
const el = await page.waitForXPath(xp);
await el?.click();

1412290cookie-checkSo klicken Sie auf ein Element mit Text in Puppeteer

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy