是否有任何方法(在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')
是否有任何方法(在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')
Answers:
此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()
不包括子节点的文本这是XPath表达式contains(., 'Text')
,适用于元素本身(包括其子节点):
//button[contains(., 'Start')]
将同时返回两个按钮//button[contains(., 'End')]
将再次返回两个按钮//button[contains(., 'Middle')]
将返回一个(最后一个按钮)因此,在大多数情况下,在XPath表达式中使用.
代替更有意义text()
。
//*[...]
改用。
您可以将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");
}
看看clickByText
在这个主旨为一个完整的例子。它负责转义引号,这对于XPath表达式来说有点棘手。
//a[contains
为//*[contains
以选择任何元素,而不仅仅是锚(a
)元素。
您还page.evaluate()
可以点击从document.querySelectorAll()
文本内容中过滤出来的元素:
await page.evaluate(() => {
[...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click();
});
或者,您可以使用和相应的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();
});
没有针对文本选择器或combinator选项的受支持的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
}
});
有很多答案提示,contains
但是鉴于OP的用例(从所有方面来看,它都是与目标字符串"Button text"
和element的精确匹配),我认为这种不精确性没有任何动机<button>Button text</button>
。
我更喜欢使用更精确的[text()="Button text"]
,这样可以避免在按钮为false时出现误报<button>Button text and more stuff</button>
:
const [el] = await page.$x('//*[@class="elements"]//a[text()="Button text"]');
el && (await el.click());
许多答案也错过了.elements
家长课堂的要求。