Czy jest jakaś metoda (nie znaleziona w API) lub rozwiązanie, aby kliknąć element z tekstem?
Na przykład mam html:
<div class="elements">
<button>Button text</button>
<a href=#>Href text</a>
<div>Div text</div>
</div>
I chcę kliknąć element, w którym zawinięty jest tekst (kliknij przycisk wewnątrz .elementów), na przykład:
Page.click('Button text', '.elements')
Odpowiedzi:
Aktualnym top odpowiedź przez tokland działa tylko na węzłach tekstowych, a nie na węzłach z innymi elementami wnętrza.
Krótka odpowiedź
To wyrażenie XPath będzie sprawdzać przycisk zawierający tekst „Tekst przycisku”:
const [button] = await page.$x("//button[contains(., 'Button text')]"); if (button) { await button.click(); }
Aby również uszanować
<div class="elements">
otoczenie przycisków, użyj następującego kodu:const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
Wyjaśnienie
Aby wyjaśnić, dlaczego
text()
w niektórych przypadkach używanie węzła tekstowego ( ) jest nieprawidłowe, spójrzmy na przykład:<div> <button>Start End</button> <button>Start <em>Middle</em> End</button> </div>
Najpierw sprawdźmy wyniki przy użyciu
contains(text(), 'Text')
://button[contains(text(), 'Start')]
powróci zarówno dwa węzły (prawidłowo)//button[contains(text(), 'End')]
zwróci tylko jeden węzeł (pierwszy) jakotext()
zwraca listę z dwoma tekstami (Start
iEnd
), alecontains
sprawdzi tylko pierwszy//button[contains(text(), 'Middle')]
nie zwróci żadnych wyników, ponieważtext()
nie zawiera tekstu węzłów potomnychOto wyrażenia XPath dla
contains(., 'Text')
, które działają na samym elemencie, w tym na jego węzłach podrzędnych://button[contains(., 'Start')]
zwróci zarówno dwa przyciski//button[contains(., 'End')]
ponownie zwróci oba dwa przyciski//button[contains(., 'Middle')]
zwróci jeden (ostatni przycisk)Dlatego w większości przypadków bardziej sensowne jest użycie w wyrażeniu XPath
.
zamiasttext()
.źródło
//*[...]
zamiast tego.Możesz użyć selektora XPath ze stroną. $ X (wyrażenie) :
Zapoznaj się
clickByText
z tym streszczeniem, aby uzyskać pełny przykład. Dba o unikanie cudzysłowów, co jest nieco trudne w przypadku wyrażeń XPath.źródło
//a[contains
ze//*[contains
wybrać dowolny element, a nie tylko (anchora
) element.Możesz również użyć
page.evaluate()
do klikania elementów uzyskanych zdocument.querySelectorAll()
przefiltrowanych według treści tekstowej:await page.evaluate(() => { [...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click(); });
Alternatywnie możesz
page.evaluate()
kliknąć element na podstawie jego zawartości tekstowej przy użyciudocument.evaluate()
i odpowiedniego wyrażenia XPath: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(); });
źródło
stworzyliśmy szybkie rozwiązanie, aby móc korzystać z zaawansowanych selektorów css, takich jak „: zawiera (tekst)”
więc korzystając z tej biblioteki możesz po prostu
źródło
Oto moje rozwiązanie:
źródło
Rozwiązaniem jest
źródło
Nie ma obsługiwanej składni selektora css dla selektora tekstu lub opcji kombinatora, moim obejściem byłoby:
źródło
Istnieje wiele sugerujących odpowiedzi,
contains
ale nie widzę motywacji do tej nieprecyzyjności, biorąc pod uwagę przypadek użycia OP, który, jak się wydaje, jest dokładnym dopasowaniem z docelowym ciągiem"Button text"
i elementem<button>Button text</button>
.Wolę używać bardziej precyzyjne
[text()="Button text"]
, co pozwala uniknąć fałszywie dodatni, gdy przycisk jest, powiedzmy<button>Button text and more stuff</button>
:To przewiduje odwrotny scenariusz tej odpowiedzi, który stara się być jak najbardziej liberalny.
Wiele odpowiedzi nie
.elements
spełniało również wymagań dotyczących klasy rodzicielskiej.źródło
Musiałem:
await this.page.$eval(this.menuSelector, elem => elem.click());
źródło