Puppeteer:在继续执行下一行之前等待N秒

149
puppeteer 中,我想在执行下一行代码之前等待一段定义的时间。我尝试在 evaluate 函数中使用 setTimeout,但似乎被简单地忽略了。
console.log('before waiting');
await page.evaluate(async() => {
  setTimeout(function(){
      console.log('waiting');
  }, 4000)
});
console.log('after waiting');

这段代码不等待,直接在等待之前等待之后写入。你知道如何做到这一点吗?


{btsdaf} - Osama
8个回答

233

你可以使用一个小的Promise函数,

function delay(time) {
   return new Promise(function(resolve) { 
       setTimeout(resolve, time)
   });
}

然后,每当你想要延迟时,调用它即可。

console.log('before waiting');
await delay(4000);
console.log('after waiting');

如果一定要使用Puppeteer,请使用内置的waitForTimeout函数。

await page.waitForTimeout(4000)

如果您仍然希望使用page.evaluate,请在4秒后解决它。您没有解决任何问题。

await page.evaluate(async() => {
    await new Promise(function(resolve) { 
           setTimeout(resolve, 1000)
    });
});

但我想你可以简单地使用前两个例子。


你确定这个工作正常吗?你不能在page.evaluate()中使用delay(),因为它不属于它的上下文。 - Thiago C. S Ventura
3
延迟函数和page.evaluate函数是两个不同的例子,我非常确定。 - Md. Abu Taher
3
waitFor已经被弃用,请使用waitForTimeout代替。 - Maxime Lechevallier
这很聪明。但我想不出为什么 "function delay(time) { return new Promise(function(resolve) { setTimeout(resolve, time) }); }" 能够工作... - Alston
1
waitForTimeout 也已经被弃用了。最好找到更好的断言来阻塞:waitForFunctionwaitForNetworkIdlewaitForResponsewaitForSelector 等等。 - ggorlen

120

我一直在使用:

await page.waitForTimeout(3000);

其中3000表示毫秒,这对我来说似乎有效。


9
waitfor() 已经被弃用,请使用 page.waitForTimeout(1000) 替代。 - A McGuinness
4
page.waitForTimeout() is now obsolete. Replace with new Promise(r => setTimeout(r, milliseconds)); - LeMoussel

61

您可以使用以下选项之一来等待一秒钟:

await page.waitFor(1000);
await frame.waitFor(1000);
await new Promise(r => setTimeout(r, 1000));

另外,Puppeteer还有许多功能包括内置的delay选项,这可能对于在某些事件之间等待非常方便:

// Click Delay
// Time to wait between mousedown and mouseup in milliseconds. Defaults to 0.

await page.click('#example', {delay: 1000});
await frame.click('#example', {delay: 1000});
await elementHandle.click({delay: 1000});
await page.mouse.click(0, 0, {delay: 1000});

// Type Delay
// Time to wait between key presses in milliseconds. Defaults to 0.

await page.type('#example', 'Hello, world!', {delay: 1000});
await frame.type('#example', 'Hello, world!', {delay: 1000});
await elementHandle.type('Hello, world!', {delay: 1000});
await page.keyboard.type('Hello, world!', {delay: 1000});

// Press Delay
// Time to wait between keydown and keyup in milliseconds. Defaults to 0.

await elementHandle.press('Backspace', {delay: 1000});
await page.keyboard.press('Backspace', {delay: 1000});

3
waitFor已经过时并将被移除。新函数是waitForTimeout。 https://github.com/puppeteer/puppeteer/issues/6214 - Scott Jodoin
1
waitForTimeout 也已经被弃用。 - Ciprian Tomoiagă

27

page.waitFor现已被弃用。

建议使用page.waitForTimeout来在继续执行之前暂停脚本执行给定的毫秒数:

await page.waitForTimeout(1000)

1
请更新文档链接。 - Muhammad Uzair

10
其他答案已经展示了如何睡眠,但是现在page.waitForTimeout已经最终被弃用,我觉得我应该添加我一直想要添加的答案:
不要睡眠!它会导致竞争条件,破坏Puppeteer的事件驱动性质,引入不必要的脆弱性。几乎总有更好的谓词可以等待,无论是显式地还是使用Locator API。
  • 你在等待CSS选择器、aria标签、文本或XPath出现吗?试试waitForSelector(可选使用适当的内置选择器)。
  • 你在等待导航吗?试试waitForNavigation或调整goto上的waitUntil选项。
  • 你在等待网络事件或状态吗?试试waitForRequestwaitForResponsewaitForNetworkIdle
  • 你在等待弹出窗口吗?试试page.on("dialog", ...}转换为Promise
  • 你在等待任意谓词,比如最少数量的子元素出现吗?试试waitForFunction
  • 你想要避免被检测吗?试试slowMo
  • 还有其他情况吗?运行一个evaluate块,并添加自己的代码来等待DOM变化,或使用setIntervalrequestAnimationFrame进行轮询,根据需要有效地重新实现waitForFunction

waitForFunction特别少用,但它增加了大量的可靠性和精确性,而waitForTimeout则没有。

如果其他方法都失败了,你可以延迟执行脚本,但我已经编写了数百个Puppeteer脚本,从来没有使用过任何睡眠变体,所以我相信它基本上是不必要的。

请参阅我的关于Puppeteer反模式的博文,了解更多关于为什么应该避免除了绝对最后手段之外的任何形式的睡眠的分析。

还请参阅Playwright文档中关于waitForTimeout的内容,它与Puppeteer方法基本相同:

不推荐

在生产环境中永远不要等待超时。等待时间的测试本质上是不稳定的。使用定位器操作和自动等待的Web断言。

上述内容有一个例外:在开发脚本时,睡眠可能对临时调试有用。


1
完全同意这句话:“尤其是waitForFunction,它被低估了,但它为waitForTimeout所没有的可靠性和精度增加了很多。” - Moinul Moin

4

尝试使用这个函数。

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

使用它

  async function demo() {
    console.log('Waiting...');
    await sleep(3000);
    console.log('ok');
  }

  demo();

-1
await new Promise(_func=> setTimeout(_func, 5000));

许多其他答案已经提供了清晰的解释。将 resolve 重命名为 _func 是奇怪的。并且,如果可能的话,我们实际上不应该在 Puppeteer 中使用它。 - ggorlen

-4

您的语法不完整。
尝试这个...

await page.evaluate(async() => {
    setTimeout(function(){
        console.log('waiting');
    }, 4000)
});

{btsdaf} - Pipo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接