Кукольник: нажмите элемент с текстом
Есть ли какой-либо метод (не нашел в API) или решение, чтобы щелкнуть элемент с текстом?
Например, у меня есть html:
<div class="elements">
<button>Button text</button>
<a href=#>Href text</a>
<div>Div text</div>
</div>
И я хочу щелкнуть элемент, в котором текст завернут (нажмите кнопку внутри.), например:
Page.click('Button text', '.elements')
Любое решение?
Ответы
Ответ 1
Вы можете использовать XPath-селектор со страницей. $ X (выражение):
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");
}
Проверьте clickByText
в этом суть для полного примера. Он заботится о экранировании кавычек, что немного сложно с выражениями XPath.
Ответ 2
Вы также можете использовать page.evaluate()
чтобы щелкнуть элементы, полученные из document.querySelectorAll()
, которые были отфильтрованы по текстовому содержимому:
await page.evaluate(() => {
[...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});
Кроме того, вы можете использовать page.evaluate()
чтобы щелкнуть элемент на основе его текстового содержимого, используя document.evaluate()
и соответствующее выражение 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();
});
Ответ 3
Текущий топ-ответ по токланду работает только на текстовых узлах, а не на узлах с другими элементами внутри.
Короткий ответ
Это выражение XPath будет запрашивать кнопку, которая содержит текст "Текст кнопки":
const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
await button.click();
}
Чтобы также соблюдать <div class="elements">
окружающие кнопки, используйте следующий код:
const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
объяснение
Чтобы объяснить, почему использование текстового узла (text()
) в некоторых случаях некорректно, давайте рассмотрим пример:
<div>
<button>Start End</button>
<button>Start <em>Middle</em> End</button>
</div>
Во-первых, давайте проверим результаты, если в нем contains(text(), 'Text')
:
-
//button[contains(text(), 'Start')]
вернет оба два узла (как и ожидалось) -
//button[contains(text(), 'End')]
будет возвращать только один узел (первый), так как text()
возвращает список с двумя текстами (Start
и End
), но contains
будет проверять только первый -
//button[contains(text(), 'Middle')]
не будет возвращать никаких результатов, как text()
не включает в себя текст дочерних узлов
Вот XPath-выражения для contains(., 'Text')
, которые работают с самим элементом, включая его дочерние узлы:
-
//button[contains(., 'Start')]
вернет обе две кнопки -
//button[contains(., 'End')]
будет снова возвращать обе две кнопки -
//button[contains(., 'Middle')]
вернет один (последняя кнопка)
Так что в большинстве случаев имеет смысл использовать .
вместо text()
в выражении XPath.
Ответ 4
сделал быстрое решение, чтобы иметь возможность использовать расширенные селекторы CSS, такие как ": содержит (текст)"
так что с помощью этой библиотеки вы можете просто
const select = require ('puppeteer-select');
const element = await select(page).getElement('button:contains(Button text)');
await element.click()
Ответ 5
Вот мое решение:
let selector = 'a';
await page.$$eval(selector, anchors => {
anchors.map(anchor => {
if(anchor.textContent == 'target text') {
anchor.click();
return
}
})
});
Ответ 6
Решение
(await page.$$eval(selector, a => a
.filter(a => a.textContent === 'target text')
))[0].click()
Ответ 7
Первое, а простой способ - добавить идентификатор к кнопке, чтобы убедиться, что вы нажмете правильную кнопку.
В этом случае я буду использовать две функции кукловода и условие:
let my_button = await page.$eval(".elements > button", btn => btn.textContent);
if(my_button == "Button text") {
await page.click(".elements > button");
}
Просто проверьте, нет ли больше div с одним и тем же классом ".elements", в этом случае используйте другой и специальный селектор. Я уверен, что есть более чистые решения, но также я новичок в кукловоде.
Ответ 8
Вам не нужно указывать текст, чтобы щелкнуть его, действие page.click() будет искать селектор и щелкнуть по середине. Если вы не можете связаться с этим классом, попробуйте щелкнуть правой кнопкой мыши элемент в инструментах разработчика, и "Copy > Copy Selector" должен работать.
В этом случае
await page.click('.elements');
Должно быть достаточно. Если это не сработает, добавьте параметр 'button'. Это помогает мне в редких случаях:
await page.click('.elements', {button: 'left'});