Кукольник: нажмите элемент с текстом

Есть ли какой-либо метод (не нашел в 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'});