Puppeteer:如何单击其后代中包含特定值的元素

问题描述 投票:0回答:1

我第一次使用 Puppeteer,我有这个代码来单击某个元素:

await page.waitForSelector('.item-table > .grid-item > .grid-item-container > .grid-table-container > .grid-option-table:nth-child(1) > .grid-option:nth-child(1) > .grid-option-selectable > div');
await page.click('.item-table > .grid-item > .grid-item-container > .grid-table-container > .grid-option-table:nth-child(1) > .grid-option:nth-child(1) > .grid-option-selectable > div');

由于页面上有很多

.item-table
元素,我想让它单击在其后代之一中具有特定文本的元素(我不知道后代的级别)。 我已经在文档中甚至在SO问题中搜索了解决方案,但我找不到任何有用的东西。

我尝试添加

> :contains("Foo bar")
,但也许这是错误的方法。事实上,这是行不通的。

await page.waitForSelector('.item-table > :contains("Foo Bar") > .grid-item > .grid-item-container > .grid-table-container > .grid-option-table:nth-child(1) > .grid-option:nth-child(1) > .grid-option-selectable > div');
await page.click('.item-table > :contains("Foo Bar") > .grid-item-container > .grid-table-container > .grid-option-table:nth-child(1) > .grid-option:nth-child(1) > .grid-option-selectable > div');

那么,如何使用 Puppeteer 来实现呢?

编辑: 这是我试图抓取的标记:

<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table"></div>
<div class="item-table">
    <div class="grid-item">
        <div class="grid-item-container">
            <div class="grid-table-container>
                <div class="grid-option-header">
                    <div class="grid-option-caption">
                        <div class="grid-option-name">
                            Foo Bar
                            <span>some other text</span>
                        </div>
                    </div>
                </div>
                <div class="grid-option-table">
                    <div class="grid-option">
                        <div class="grid-option-selectable">
                            <div></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="item-table"></div>
<div class="item-table"></div>

因此,我想单击

div
div 中的
grid-option-selectable
,位于
item-table
div 中,其中包含
Foo Bar
的后代。

javascript puppeteer selector
1个回答
1
投票

我将对您的标记进行轻微调整,以帮助验证代码是否有效:

<!-- ... same ... -->
<div class="grid-option-selectable">
    <div>You got me!</div>
</div>
<!-- ... same ... -->

添加一些具有不匹配文本的相同结构兄弟姐妹也不是一个坏主意,以确保我们不会产生误报。

我们将尝试的策略是这个答案中描述的策略(这个答案在同一线程中提供替代方案并且这个单独的线程相关):在目标文本之间相互共享的目标父级上使用xpath进行查询和可点击元素的后代文本,然后查询父级以获取可点击元素。

const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch(/*{dumpio: true}*/);
  const page = await browser.newPage();
  await page.goto("http://localhost:8000");
  const xp = `
    //div[@class="item-table" 
          and descendant::*[contains(text(), "Foo Bar")]]
    //div[@class="grid-option-selectable"]
  `;
  const [el] = await page.$x(xp);
  console.log(await el.evaluate(el => el.innerText));
  await el.click();
  await browser.close();
})();

输出:

You got me!

请注意,我使用的是精确的类匹配,但如果您的目标元素上可能有多个类,则需要使用

contains
放宽查询。所以你可以这样写 xpath 表达式:

//div[contains(@class, "item-table")
      and .//*[contains(text(), "Foo Bar")]]
//div[contains(@class, "grid-option-selectable")]

自从发布此答案以来,

page.$x
已从库中删除。有关详细信息,请参阅如何通过 xpath 获取元素?

© www.soinside.com 2019 - 2024. All rights reserved.