Puppeteerでテキスト付きの要素をクリックする方法


91

テキスト付きの要素をクリックする方法(APIで見つかりませんでした)または解決策はありますか?

たとえば、私はhtmlを持っています:

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

そして、次のように、テキストが折り返されている要素をクリックしたいと思います(.elements内のボタンをクリックします)。

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


答えは見つかりましたか?
ShubhamBatra18年

それが役に立ったら、クリックを実行したいページにjQueryがロードされているので、evaluateメソッドを使用してjQueryコードを実行することができました。
Brandito 2018

回答:


84

簡潔な答え

この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')]2つのノードの両方を返します(予想どおり)
  • //button[contains(text(), 'End')]のみを返します1つのノード(最初の)として、text()2つのテキスト(と戻りリストStart との End)が、contains最初のものだけをチェックします
  • //button[contains(text(), 'Middle')] 戻らないだろう何のような結果をtext()子ノードのテキストが含まれていません。

のXPath式はcontains(., 'Text')、子ノードを含む要素自体で機能します。

  • //button[contains(., 'Start')]2つのボタンの両方を返します
  • //button[contains(., 'End')]再び2つのボタンの両方を返します
  • //button[contains(., 'Middle')]1つ(最後のボタン) を返します

したがって、ほとんどの場合、XPath式では.なくを使用する方が理にかなっていますtext()


1
すべてのタイプの要素で機能するものはありますか?テキストは等のボタン、AP、DIV、スパン内にある場合、私は知ることができない
アンドレアBisello

6
@AndreaBisello//*[...]代わりに使用できます。
トーマスドン

92

あなたはでの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式では少し注意が必要です。


素晴らしい-私は他のタグのためにそれをやろうとしましたが、それを機能させることができません。(li、h1、...)どうしますか?
Rune Jeppesen 2018

3
@RuneJeppesen置換//a[contains//*[containsて、アンカー(a)要素だけでなく任意の要素を選択します。
Unixmonkey

17

テキストコンテンツでフィルタリングされた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();
});

14

「:contains(text)」のような高度な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
            }
        })
    });

5

解決策は

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

1

テキストセレクターまたはコンビネーターオプションでサポートされているcssセレクター構文はありません。これに対する私の回避策は次のとおりです。

await page.$$eval('selector', selectorMatched => {
    for(i in selectorMatched)
      if(selectorMatched[i].textContent === 'text string'){
          selectorMatched[i].click();
          break;//Remove this line (break statement) if you want to click on all matched elements otherwise the first element only is clicked  
        }
    });

1

示唆する多くの答えがありますが、containsOPのユースケースを考えると、この不正確さの動機はわかりません。これは、すべての外観で、と"Button text"要素のターゲット文字列と完全に一致します<button>Button text</button>

私はより正確なを使用したいと思います。これにより[text()="Button text"]、ボタンが次のような場合の誤検知を回避できます<button>Button text and more stuff</button>

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

これは、可能な限り寛容になろうとするこの回答の反対のシナリオを予期しています。

多くの回答も.elements親クラスの要件を見逃していました。


-1

そうしなければならなかった:

await this.page.$eval(this.menuSelector, elem => elem.click());

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.