我第一次使用 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
的后代。
我将对您的标记进行轻微调整,以帮助验证代码是否有效:
<!-- ... 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 获取元素?。