Puppeteer'da metin içeren öğeye nasıl tıklanır


91

Metin içeren öğeye tıklamak için herhangi bir yöntem (API'de bulunmayan) veya çözüm var mı?

Örneğin html var:

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

Ve metnin sarıldığı öğeye tıklamak istiyorum (.elements içindeki düğmeye tıklayın), örneğin:

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

2
Yanıtı burada paylaştı: stackoverflow.com/a/47829000/6161265
Md. Abu Taher

Cevap buldunuz mu?
Shubham Batra

Yardımcı oluyorsa, tıklamak istediğim sayfada jQuery yüklendi, böylece jQuery kodunu yürütmek için değerlendirme yöntemini kullanabildim ve kullandım.
Brandito

Yanıtlar:


84

Kısa cevap

Bu XPath ifadesi, "Düğme metni" metnini içeren bir düğmeyi sorgular:

const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
    await button.click();
}

<div class="elements">Düğmelerin etrafına da uymak için aşağıdaki kodu kullanın:

const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");

Açıklama

text()Bazı durumlarda metin düğümünü ( ) kullanmanın neden yanlış olduğunu açıklamak için bir örneğe bakalım:

<div>
    <button>Start End</button>
    <button>Start <em>Middle</em> End</button>
</div>

Öncelikle, kullanırken sonuçları kontrol edelim contains(text(), 'Text'):

  • //button[contains(text(), 'Start')]her iki düğümü de döndürecektir (beklendiği gibi)
  • //button[contains(text(), 'End')]yalnızca bir düğüm (ilki) text()döndürür, çünkü iki metin ( Start ve End) içeren bir liste döndürür , ancak containsyalnızca ilkini kontrol eder
  • //button[contains(text(), 'Middle')]alt düğümlerin metnini içermediği için hiçbir sonuç döndürmeyecektext()

Alt contains(., 'Text')düğümleri de dahil olmak üzere öğenin kendisi üzerinde çalışan XPath ifadeleri şunlardır :

  • //button[contains(., 'Start')]iki düğmeyi de döndürecek
  • //button[contains(., 'End')]yine iki düğmeyi de döndürecek
  • //button[contains(., 'Middle')] dönecektir birini (son düğmesi)

Bu yüzden çoğu durumda, bir XPath ifadesi .yerine kullanmak daha mantıklıdır text().


1
her tür öğeyle çalışan bir şey? metnin bir düğme, ap, bir div, bir aralık vb. içinde olup olmadığını bilemiyorum
Andrea Bisello

6
@AndreaBisello Bunun //*[...]yerine kullanabilirsiniz .
Thomas Dondorf

92

. $ X (ifade) sayfasıyla bir XPath seçici kullanabilirsiniz :

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

Check out clickByTextbu esasından tam örneğin. XPath ifadelerinde biraz zor olan alıntılardan kaçışla ilgilenir.


Harika - Diğer etiketler için yapmayı denedim ama çalışmasını sağlayamıyorum. (li, h1, ...) Bunu nasıl yaparsınız?
Rune Jeppesen

3
@RuneJeppesen Yalnızca bir bağlantı ( ) öğesini değil, herhangi bir öğeyi seçmek için //a[containsile değiştirin . //*[containsa
Unixmonkey

17

Metin içeriğine göre filtrelenmiş page.evaluate()olanlardan elde edilen öğeleri tıklamak için de kullanabilirsiniz document.querySelectorAll():

await page.evaluate(() => {
  [...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});

Alternatif olarak, page.evaluate()metin içeriğine bağlı olarak bir öğeyi document.evaluate()ve karşılık gelen bir XPath ifadesini tıklatmak için kullanabilirsiniz :

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

": içerir (metin)" gibi gelişmiş css seçicileri kullanabilmek için hızlı bir çözüm yaptı

bu yüzden bu kitaplığı kullanarak şunları yapabilirsiniz:

const select = require ('puppeteer-select');

const element = await select(page).getElement('button:contains(Button text)');
await element.click()

5

İşte benim çözümüm:

let selector = 'a';
    await page.$$eval(selector, anchors => {
        anchors.map(anchor => {
            if(anchor.textContent == 'target text') {
                anchor.click();
                return
            }
        })
    });

5

Çözüm şudur

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

1

Metin seçici veya bir birleştirici seçeneği için desteklenen bir css seçici sözdizimi yok, bunun için çalışmam şöyle olacaktır:

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

Öneren birçok cevap var, containsancak OP'nin kullanım durumu göz önüne alındığında, bu belirsizlik için herhangi bir motivasyon görmüyorum, ki bu, görünüşe göre, bir hedef dizesi "Button text"ve bir öğe ile tam bir eşleşme <button>Button text</button>.

Daha kesin [text()="Button text"]olanı kullanmayı tercih ederim , bu da düğme şöyle olduğunda yanlış pozitifliği önler <button>Button text and more stuff</button>:

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

Bu , mümkün olduğunca izin verici olmaya çalışan bu cevabın zıt senaryosunu öngörür .

Pek çok cevap, .elementsebeveyn sınıfı şartını da kaçırdı .


-1

Yapmak zorundaydım:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.