Javascript 按类名收集元素,然后单击每个元素-Puppeter
使用Puppeter,我希望获得页面上具有特定类名的所有元素,然后循环并单击每个元素 使用jQuery,我可以通过以下方式实现这一点:Javascript 按类名收集元素,然后单击每个元素-Puppeter,javascript,node.js,google-chrome-devtools,puppeteer,headless-browser,Javascript,Node.js,Google Chrome Devtools,Puppeteer,Headless Browser,使用Puppeter,我希望获得页面上具有特定类名的所有元素,然后循环并单击每个元素 使用jQuery,我可以通过以下方式实现这一点: var elements = $("a.showGoals").toArray(); for (i = 0; i < elements.length; i++) { $(elements[i]).click(); } var elements=$(“a.showGoals”).toArray(); 对于(i=0;i{ 让元素=$('a.showGo
var elements = $("a.showGoals").toArray();
for (i = 0; i < elements.length; i++) {
$(elements[i]).click();
}
var elements=$(“a.showGoals”).toArray();
对于(i=0;i
我如何使用木偶演员来实现这一点
更新
在下面尝试了Chridam的答案,但我无法让它发挥作用(尽管答案很有用,所以感谢你),所以我尝试了以下方法,效果很好:
await page.evaluate(() => {
let elements = $('a.showGoals').toArray();
for (i = 0; i < elements.length; i++) {
$(elements[i]).click();
}
});
等待页面。评估(()=>{
让元素=$('a.showGoals').toArray();
对于(i=0;i
使用执行JS:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.evaluate(() => {
let elements = document.getElementsByClassName('showGoals');
for (let element of elements)
element.click();
});
// browser.close();
});
要获取所有元素,应该使用方法,该方法与reqular browser API中的
[…document.querySelectorAll]
(在数组中展开)相同
然后,您可以循环浏览它(映射,例如,任何您喜欢的内容),并评估每个链接:
const getThemAll = await page.$$('a.showGoals')
getThemAll.forEach(async link => {
await page.evaluate(() => link.click())
})
由于您还希望对所获得的内容执行操作,因此我建议使用which,它将执行与上面相同的操作,并在一行中使用数组中的每个元素运行求值函数。例如:
await page.$$eval('a.showGoals', links => links.forEach(link => link.click()))
为了更好地解释上面的行,$$eval
返回一个链接数组,然后以链接
作为参数执行回调函数,然后通过forEach
方法运行每个链接,最后在每个链接中执行单击
函数
也请检查,它们有很好的示例。page.$$()/elementHandle.click()
可以使用基于给定选择器创建数组,然后可以使用单击每个元素:
const elements = await page.$$('a.showGoals');
elements.forEach(async element => {
await element.click();
});
注意:记住在函数中单击。否则,您将收到以下错误:
SyntaxError:await仅在异步函数中有效
迭代for
循环与Array.map()/Array.forEach()中的puppeter异步方法
由于所有puppeter方法都是异步的,因此我们如何迭代它们并不重要。我对最常用的推荐和使用选项进行了比较和评级
为此,我创建了一个React.Js示例页面,其中包含许多React按钮(我称之为lotofreact按钮)。这里(1)我们可以设置页面上要呈现的按钮数量(2)我们可以通过单击黑色按钮将其激活为绿色。我认为这是一个与OP相同的用例,也是浏览器自动化的一个普遍情况(如果我们在页面上做了一些事情,我们预期会发生一些事情)。
假设我们的用例是:
Scenario outline: click all the buttons with the same selector
Given I have <no.> black buttons on the page
When I click on all of them
Then I should have <no.> green buttons on the page
特产
- 返回另一个数组
- .map方法内部的并行执行
- 快速
132按钮场景结果:❌
持续时间:891毫秒
通过在人头攒动模式下观察浏览器,它看起来可以工作,但是如果我们检查页面。屏幕截图发生的时间:我们可以看到点击仍在进行中。这是因为默认情况下不能等待数组.map
。幸运的是,在浏览器未关闭之前,脚本有足够的时间解决所有元素上的所有单击
1320个按钮场景结果:❌
持续时间:6868毫秒
如果我们增加同一选择器的元素数,我们将遇到以下错误:
未处理PromisejectionWarning:错误:节点不可见或不是HTMLElement
,因为我们已经到达了等待页面。屏幕截图()
和等待浏览器。关闭()
:当浏览器已经关闭时,异步单击仍在进行中
二,。数组.forEach
所有的迭代对象都将被执行,但是forEach将在它们全部完成执行之前返回,这在异步函数的许多情况下都不是理想的行为。就木偶演员而言,这与Array.map
非常相似,除了:forArray.forEach
不返回新数组
代码示例
const elHandleArray=等待页面。$$(“按钮”)
elHandleArray.forEach(异步el=>{
等待元素。单击()
})
等待页面。屏幕截图({path:'clicks_foreach.png'})
等待浏览器关闭()
特产
- .forEach方法内部的并行执行
- 快速
132按钮场景结果:❌
持续时间:1058毫秒
通过在人头攒动模式下观察浏览器,它看起来可以工作,但是如果我们检查页面。屏幕截图发生的时间:我们可以看到点击仍在进行中
1320个按钮场景结果:❌
持续时间:5111毫秒
如果使用相同的选择器增加元素的数量,我们将遇到以下错误:
未处理PromisejectionWarning:错误:节点不可见或不是HTMLElement
,因为我们已经到达了等待页面。屏幕截图()
和等待浏览器。关闭()
:当浏览器已经关闭时,异步单击仍在进行中
三、 第页$$eval+forEach
性能最好的解决方案是稍微修改一下bside的版本。页面。$$eval()在页面内运行Array.from(document.querySelectorAll(selector))
,并将其作为第一个参数传递给pageFunction
。它作为forEach的包装器,因此可以完美地等待它
代码示例
wait page.$$eval('button',elHandles=>elHandles.forEach(el=>el.click())
等待页面。屏幕截图({path:'clicks_eval_foreach.png'})
等待浏览器关闭()
特产
- 在.forEach方法中使用异步puppeter方法没有副作用
- .forEach方法内部的并行执行
- 极快
132按钮场景结果:✅
持续时间:711毫秒
通过在人头模式下观察浏览器,我们可以看到效果是立竿见影的,