是否有任何方法(在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')
任何解决方案?
答案 0 :(得分:54)
您可以将XPath选择器与page.$x(expression):
一起使用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");
}
查看此gist中的clickByText
以获取完整示例。它负责转义引号,这对于XPath表达式来说有点棘手。
答案 1 :(得分:5)
提出了一种快速解决方案,可以使用高级的CSS选择器,例如“:contains(text)”
因此,使用此library您可以
const select = require ('puppeteer-select');
const element = await select(page).getElement('button:contains(Button text)');
await element.click()
答案 2 :(得分:4)
您还可以使用page.evaluate()
单击从document.querySelectorAll()
获得的已按文本内容过滤的元素:
await page.evaluate(() => {
[...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});
或者,您可以使用page.evaluate()
和相应的XPath表达式,使用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();
});
答案 3 :(得分:4)
此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
和End
)的列表,但contains
仅会检查第一个//button[contains(text(), 'Middle')]
将返回否结果,因为text()
不包含子节点的文本以下是contains(., 'Text')
的XPath表达式,它可用于元素本身(包括其子节点):
//button[contains(., 'Start')]
将同时返回两个两个按钮//button[contains(., 'End')]
将再次返回两个两个按钮//button[contains(., 'Middle')]
将返回一个(最后一个按钮)因此,在大多数情况下,在XPath表达式中使用.
代替text()
更有意义。
答案 4 :(得分:2)
这是我的解决方案:
let selector = 'a';
await page.$$eval(selector, anchors => {
anchors.map(anchor => {
if(anchor.textContent == 'target text') {
anchor.click();
return
}
})
});
答案 5 :(得分:2)
解决方案是
(await page.$$eval(selector, a => a
.filter(a => a.textContent === 'target text')
))[0].click()
答案 6 :(得分: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());
这预见了this answer的相反情况,它试图尽可能地宽松。
许多答案还没有达到.elements
父类的要求。
答案 7 :(得分:0)
文本选择器或组合器选项没有受支持的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
}
});
答案 8 :(得分:-1)
我必须:
await this.page.$eval(this.menuSelector, elem => elem.click());