是否有任何方法(在API中找不到)或解决方案点击带有文本的元素?
例如我有html:
<div class="elements">
<button>Button text</button>
<a href=#>Href text</a>
<div>Div text</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我想点击包含文字的元素(点击.elements里面的按钮),如:
Page.click('Button text', '.elements')
Run Code Online (Sandbox Code Playgroud)
有解决方案吗
tok*_*and 68
您可以将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");
}
Run Code Online (Sandbox Code Playgroud)
请查看clickByText此要点以获取完整示例.它负责转义引号,这对于XPath表达式来说有点棘手.
Tho*_*orf 25
此XPath表达式将查询包含文本“按钮文本”的按钮:
const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
await button.click();
}
Run Code Online (Sandbox Code Playgroud)
为了也尊重<div class="elements">周围的按钮,请使用以下代码:
const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
Run Code Online (Sandbox Code Playgroud)
为了说明为什么text()在某些情况下使用文本节点()是错误的,我们来看一个示例:
<div>
<button>Start End</button>
<button>Start <em>Middle</em> End</button>
</div>
Run Code Online (Sandbox Code Playgroud)
首先,让我们检查使用时的结果contains(text(), 'Text'):
//button[contains(text(), 'Start')]将返回两个节点(按预期方式)//button[contains(text(), 'End')]将仅返回一个节点(第一个),并text()返回包含两个文本(Start和End)的列表,但contains仅检查第一个节点//button[contains(text(), 'Middle')] 将不返回任何结果,因为text()不包括子节点的文本这是的XPath表达式contains(., 'Text'),可用于元素本身(包括其子节点):
//button[contains(., 'Start')]将同时返回两个按钮//button[contains(., 'End')]将再次返回两个按钮//button[contains(., 'Middle')] 将返回一个(最后一个按钮)因此,在大多数情况下,在XPath表达式中使用.代替更有意义text()。
ggo*_*len 12
Puppeteer 19.7.1 添加了“p”(伪)选择器,因此text/已弃用::-p-text,取而代之的是选择子字符串。例如:
const el = await page.waitForSelector("::-p-text(Button text)");
Run Code Online (Sandbox Code Playgroud)
伪选择器可以与 CSS 选择器结合使用,例如
const el = await page.$(".elements button::-p-text(Button text)");
Run Code Online (Sandbox Code Playgroud)
在 Puppeteer >= 18.0.0 中,选择器有一个text/前缀,用于选择元素文本的子字符串:
const el = await page.waitForSelector("text/Button text");
Run Code Online (Sandbox Code Playgroud)
具体到 XPath,与 18.0.0 之前的 Puppeteer 最相关:
由于 OP 的用例似乎与目标字符串 完全匹配"Button text",<button>Button text</button>,text()似乎是正确的方法,而不是不太精确的方法contains()。
尽管托马斯对何时存在子元素、避免误报做出了很好的论证,但当按钮是 时,使用 可以避免误报,这似乎很可能是一种情况。手头同时拥有这两种工具非常有用,这样您就可以根据具体情况选择更合适的工具。containstext()<button>Button text and more stuff</button>
const xp = '//*[@class="elements"]//button[text()="Button text"]';
const [el] = await page.$x(xp);
await el?.click();
Run Code Online (Sandbox Code Playgroud)
请注意,许多其他答案都忽略了.elements父类的要求。
另一个 XPath 函数是[normalize-space()="Button text"]“从字符串中去除前导和尾随空白,用单个空格替换空白字符序列”,并且对于某些情况可能很有用。
此外,使用waitForXPathwhich 等待然后返回与 XPath 匹配的元素通常很方便,如果在指定的超时内未找到则抛出异常:
const xp = '//*[@class="elements"]//button[text()="Button text"]';
const el = await page.waitForXPath(xp);
await el.click();
Run Code Online (Sandbox Code Playgroud)
另一种适用于所有环境的灵活方法是使用浏览器 JS 通过文本来.find()或.filter()移出您想要的元素:
// untrusted click (ignores visibility, sometimes useful):
await page.$$eval(".elements *", els =>
els
.find(el => el.textContent.trim().toLowerCase() === "button text")
.click()
);
// trusted click:
const el = await page.evaluateHandle(() =>
[...document.querySelectorAll(".elements *")]
.find(el => el.textContent.trim().toLowerCase() === "button text")
);
await el.click();
Run Code Online (Sandbox Code Playgroud)
或者:
// untrusted clicks
const els = await page.$$eval(".elements *", els =>
els
.filter(el => el.textContent.trim().toLowerCase() === "button text")
.forEach(el => el.click())
);
// trusted clicks (not ideal)
const els = await page.evaluateHandle(`
[...document.querySelectorAll(".elements *")]
.filter(el => el.textContent.trim().toLowerCase() === "button text")
`);
const length = await els.evaluate(els => els.length);
for (let i = 0; i < length; i++) {
const el = await els.evaluateHandle((els, i) => els[i], i);
await el.click();
}
Run Code Online (Sandbox Code Playgroud)
如果您需要等待此文本,您可以使用waitForFunction:
const el = await page.waitForFunction(`
[...document.querySelectorAll(".elements *")]
.find(el => el.textContent.trim().toLowerCase() === "button text")
`);
await el.click();
Run Code Online (Sandbox Code Playgroud)
如果您正在操作的页面恰好有 jQuery(或者您自己导入它),则可以使用:containssizzle 伪选择器语法:
const el = await page.evaluateHandle(`
$('.elements :contains("Button text")').first()
`);
Run Code Online (Sandbox Code Playgroud)
小智 8
做出了快速的解决方案,以能够使用高级的CSS选择器,例如“:contains(text)”
所以使用这个库,你可以
const select = require ('puppeteer-select');
const element = await select(page).getElement('button:contains(Button text)');
await element.click()
Run Code Online (Sandbox Code Playgroud)
您还page.evaluate()可以点击从document.querySelectorAll()文本内容中过滤出来的元素:
await page.evaluate(() => {
[...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用和相应的XPath表达式page.evaluate()来基于元素的文本内容单击元素document.evaluate():
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();
});
Run Code Online (Sandbox Code Playgroud)
小智 6
解决办法是
(await page.$$eval(selector, a => a
.filter(a => a.textContent === 'target text')
))[0].click()
Run Code Online (Sandbox Code Playgroud)
小智 5
这是我的解决方案:
let selector = 'a';
await page.$$eval(selector, anchors => {
anchors.map(anchor => {
if(anchor.textContent == 'target text') {
anchor.click();
return
}
})
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
46608 次 |
| 最近记录: |