Puppeteer 在加载所有 iframe 之前创建 PDF

Puppeteer creates PDF before all iframes have loaded

我需要为包含大约 20 个显示一些图表的 iframe 的网页创建 PDF。显然,我需要等到所有 iframe 都加载完毕。为此,我尝试了以下(片段):

const browser = await puppeteer.launch({ args: ['--no-sandbox'] })
const page = await browser.newPage()

const navigationPromise = page.waitForNavigation({waitUntil: 'networkidle0'})
await page.goto(url)  
await navigationPromise

const pdf = await page.pdf()
await browser.close()

我的理解是 waitUntil: 'networkidle0' 选项应该等待 500 毫秒,直到完全没有网络流量。但是,iframe 并不总是显示,有些显示,有些不显示。

我也试过 networkidle2 但没有改善(这应该适用于长期 运行 网络连接,但我们的情况并非如此)。

还有什么其他方法可以确保所有 iframe 都已加载?

一般来说,loadnetworkidle* 事件应该在帧加载后触发。但是,如果框架在 page.waitForNavigation 解决后附加到页面,您可能需要专门监听要加载的框架。

framenavigated事件,即"emitted when a frame is navigated to a new url"。如果您知道需要收听的帧数,您可以像这样等到所有帧都加载完毕:

const EXPECTED_NUMBER_OF_FRAMES = 5;
await Promise.all([
    new Promise(resolve => { // wait until all frames are navigated
        let numberOfLoadedFrames = 0;
        page.on('framenavigated', () => {
            numberOfLoadedFrames += 1;
            if (numberOfLoadedFrames === (EXPECTED_NUMBER_OF_FRAMES + 1)) {
                resolve();
            }
        });
    }),
    page.goto('...')
]);

代码将监听 framenavigated 事件调用的数量,并在达到预期数量时监听 resolve Promise。请记住,主框架也会触发一次 framenavigated 事件,因此我的代码中的 EXPECTED_NUMBER_OF_FRAMES + 1

根据页面的复杂程度,您还可以监听发出的 frameattached 事件数,这将表明页面中有多少帧。这样您就可以自动检测页面中有多少帧。但是,在这种情况下,您应该先等待几毫秒,以确保捕捉到所有帧。