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')

2
여기에 답변을 공유했습니다 : stackoverflow.com/a/47829000/6161265
Md. Abu Taher

답변을 찾았습니까?
Shubham Batra

도움이된다면 클릭을 수행하려는 페이지에 jQuery가로드되어 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')]예상대로 노드를 모두 반환합니다.
  • //button[contains(text(), 'End')]두 개의 텍스트 ( 및 ) 가있는 목록을 반환하므로 하나의 노드 (첫 번째) 만 반환 하지만 첫 번째 노드 만 확인합니다.text()Start Endcontains
  • //button[contains(text(), 'Middle')] 반환하지 않습니다 같은 결과를 text()자식 노드의 텍스트를 포함하지 않는다

에 대한 XPath 표현식 contains(., 'Text')은 하위 노드를 포함하여 요소 자체에서 작동합니다.

  • //button[contains(., 'Start')] 버튼을 모두 반환 합니다.
  • //button[contains(., 'End')]다시 두 개의 버튼을 모두 반환 합니다.
  • //button[contains(., 'Middle')]하나 를 반환합니다 (마지막 버튼).

따라서 대부분의 경우 XPath 표현식에서 대신를 사용하는 .것이 더 합리적 text()입니다.


1
모든 유형의 요소와 함께 작동하는 것? 텍스트 등 버튼, AP, 사업부, 스팬 내에 있을지 나는 알 수 없다
안드레아 Bisello

6
@AndreaBisello //*[...]대신 사용할 수 있습니다 .
Thomas Dondorf

92

page. $ x (expression) 과 함께 XPath 선택기를 사용할 수 있습니다 .

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

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

15

": 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

제안하는 많은 답변이 contains있지만 OP의 사용 사례를 감안할 때이 부정확성에 대한 동기는 보이지 않습니다. 모든 외관상 대상 문자열 "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부모 클래스 요구 사항을 놓쳤습니다 .


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.