Javascript 木偶演员等待页面完全加载

Javascript 木偶演员等待页面完全加载,javascript,pdf-generation,puppeteer,google-chrome-headless,Javascript,Pdf Generation,Puppeteer,Google Chrome Headless,我正在从网页上创建PDF 我正在处理的应用程序是单页应用程序 我尝试了很多选择和建议 但它不起作用 const browser = await puppeteer.launch({ executablePath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', ignoreHTTPSErrors: true, headless: true, devtools: fals

我正在从网页上创建PDF

我正在处理的应用程序是单页应用程序

我尝试了很多选择和建议

但它不起作用

    const browser = await puppeteer.launch({
    executablePath: 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
    ignoreHTTPSErrors: true,
    headless: true,
    devtools: false,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
});

const page = await browser.newPage();

await page.goto(fullUrl, {
    waitUntil: 'networkidle2'
});

await page.type('#username', 'scott');
await page.type('#password', 'tiger');

await page.click('#Login_Button');
await page.waitFor(2000);

await page.pdf({
    path: outputFileName,
    displayHeaderFooter: true,
    headerTemplate: '',
    footerTemplate: '',
    printBackground: true,
    format: 'A4'
});
我要做的是在页面完全加载后立即生成PDF报告

我不想写任何类型的延迟,即等待页面。等待(2000)

我不能等待选择,因为页面上有经过计算后呈现的图表


非常感谢您的帮助。

我总是喜欢等待选择器,因为它们中的许多都是页面已完全加载的重要指标:

await page.waitForSelector('#blue-button');

我总是喜欢等待选择器,因为它们中的许多都是页面已完全加载的重要指标:

await page.waitForSelector('#blue-button');
在生成PDF之前,您可以使用等待新页面完全加载:

await page.goto(fullUrl, {
  waitUntil: 'networkidle0',
});

await page.type('#username', 'scott');
await page.type('#password', 'tiger');

await page.click('#Login_Button');

await page.waitForNavigation({
  waitUntil: 'networkidle0',
});

await page.pdf({
  path: outputFileName,
  displayHeaderFooter: true,
  headerTemplate: '',
  footerTemplate: '',
  printBackground: true,
  format: 'A4',
});

如果有一个动态生成的元素包含在PDF中,请考虑使用以确保内容可见:

await page.waitForSelector('#example', {
  visible: true,
});
在生成PDF之前,您可以使用等待新页面完全加载:

await page.goto(fullUrl, {
  waitUntil: 'networkidle0',
});

await page.type('#username', 'scott');
await page.type('#password', 'tiger');

await page.click('#Login_Button');

await page.waitForNavigation({
  waitUntil: 'networkidle0',
});

await page.pdf({
  path: outputFileName,
  displayHeaderFooter: true,
  headerTemplate: '',
  footerTemplate: '',
  printBackground: true,
  format: 'A4',
});

如果有一个动态生成的元素包含在PDF中,请考虑使用以确保内容可见:

await page.waitForSelector('#example', {
  visible: true,
});

包装
页面。单击
页面。在承诺中等待导航
。全部

  await Promise.all([
    page.click('#submit_button'),
    page.waitForNavigation({ waitUntil: 'networkidle0' })
  ]);

包装
页面。单击
页面。在承诺中等待导航
。全部

  await Promise.all([
    page.click('#submit_button'),
    page.waitForNavigation({ waitUntil: 'networkidle0' })
  ]);

在某些情况下,我的最佳解决方案是:

await page.goto(url, { waitUntil: 'domcontentloaded' });

您可以尝试的其他选项包括:

await page.goto(url, { waitUntil: 'load' });
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.goto(url, { waitUntil: 'networkidle0' });
await page.goto(url, { waitUntil: 'networkidle2' });
您可以在Puppeter文档中查看这一点:
在某些情况下,对我来说最好的解决方案是:

await page.goto(url, { waitUntil: 'domcontentloaded' });

您可以尝试的其他选项包括:

await page.goto(url, { waitUntil: 'load' });
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.goto(url, { waitUntil: 'networkidle0' });
await page.goto(url, { waitUntil: 'networkidle2' });
您可以在Puppeter文档中查看这一点:

在最新的木偶演员版本中,
networkidle2
为我工作:

wait page.goto(url,{waitUntil:'networkidle2'});

在最新的木偶演员版本中,
networkidle2
为我工作:

wait page.goto(url,{waitUntil:'networkidle2'});

有时
networkidle
事件并不总是表示页面已完全加载。仍然可能有一些JS
脚本修改页面上的内容。因此,通过浏览器查看
HTML
源代码修改的完成情况似乎会产生更好的结果。这是一个你可以使用的函数-

const waitTillHTMLRendered = async (page, timeout = 30000) => {
  const checkDurationMsecs = 1000;
  const maxChecks = timeout / checkDurationMsecs;
  let lastHTMLSize = 0;
  let checkCounts = 1;
  let countStableSizeIterations = 0;
  const minStableSizeIterations = 3;

  while(checkCounts++ <= maxChecks){
    let html = await page.content();
    let currentHTMLSize = html.length; 

    let bodyHTMLSize = await page.evaluate(() => document.body.innerHTML.length);

    console.log('last: ', lastHTMLSize, ' <> curr: ', currentHTMLSize, " body html size: ", bodyHTMLSize);

    if(lastHTMLSize != 0 && currentHTMLSize == lastHTMLSize) 
      countStableSizeIterations++;
    else 
      countStableSizeIterations = 0; //reset the counter

    if(countStableSizeIterations >= minStableSizeIterations) {
      console.log("Page rendered fully..");
      break;
    }

    lastHTMLSize = currentHTMLSize;
    await page.waitFor(checkDurationMsecs);
  }  
};

有时,
networkidle
事件并不总是表示页面已完全加载。仍然可能有一些JS
脚本修改页面上的内容。因此,通过浏览器查看
HTML
源代码修改的完成情况似乎会产生更好的结果。这是一个你可以使用的函数-

const waitTillHTMLRendered = async (page, timeout = 30000) => {
  const checkDurationMsecs = 1000;
  const maxChecks = timeout / checkDurationMsecs;
  let lastHTMLSize = 0;
  let checkCounts = 1;
  let countStableSizeIterations = 0;
  const minStableSizeIterations = 3;

  while(checkCounts++ <= maxChecks){
    let html = await page.content();
    let currentHTMLSize = html.length; 

    let bodyHTMLSize = await page.evaluate(() => document.body.innerHTML.length);

    console.log('last: ', lastHTMLSize, ' <> curr: ', currentHTMLSize, " body html size: ", bodyHTMLSize);

    if(lastHTMLSize != 0 && currentHTMLSize == lastHTMLSize) 
      countStableSizeIterations++;
    else 
      countStableSizeIterations = 0; //reset the counter

    if(countStableSizeIterations >= minStableSizeIterations) {
      console.log("Page rendered fully..");
      break;
    }

    lastHTMLSize = currentHTMLSize;
    await page.waitFor(checkDurationMsecs);
  }  
};

还可以使用以确保已渲染所有元素

await page.waitFor('*')

参考:

您还可以使用以确保所有元素都已渲染

await page.waitFor('*')

参考资料:

截至2020年12月,
waitFor
功能已被弃用,代码中的警告说明:

waitFor已弃用,将在将来的版本中删除。看见 有关详细信息以及如何 迁移您的代码

您可以使用:

sleep(millisecondsCount) {
    if (!millisecondsCount) {
        return;
    }
    return new Promise(resolve => setTimeout(resolve, millisecondsCount)).catch();
}
并使用它:

(async () => {
    await sleep(1000);
})();

对于2020年12月,
waitFor
函数被弃用,代码中的警告告诉我们:

waitFor已弃用,将在将来的版本中删除。看见 有关详细信息以及如何 迁移您的代码

您可以使用:

sleep(millisecondsCount) {
    if (!millisecondsCount) {
        return;
    }
    return new Promise(resolve => setTimeout(resolve, millisecondsCount)).catch();
}
并使用它:

(async () => {
    await sleep(1000);
})();

我在使用屏幕外渲染器时遇到了与networkidle相同的问题。我需要一个基于WebGL的引擎来完成渲染,然后再做一个屏幕截图。对我有效的是一种方法。就我而言,用法如下:

await page.goto(url);
await page.waitForFunction("renderingCompleted === true")
const imageBuffer = await page.screenshot({});

在渲染代码中,我只是在完成时将
renderingCompleted
变量设置为true。如果您没有访问页面代码的权限,可以使用其他现有标识符。

我在使用屏幕外渲染器时遇到了与
networkidle
相同的问题。我需要一个基于WebGL的引擎来完成渲染,然后再做一个屏幕截图。对我有效的是一种方法。就我而言,用法如下:

await page.goto(url);
await page.waitForFunction("renderingCompleted === true")
const imageBuffer = await page.screenshot({});


在渲染代码中,我只是在完成时将
renderingCompleted
变量设置为true。如果您没有访问页面代码的权限,可以使用其他现有标识符。

信号“networkidle0”的文档在哪里?“networkidle0”在这里有文档记录。waitForSelector应在
页面之后调用。转到
之前还是之后调用?您能回答我提出的类似问题吗?当我可以使用默认加载事件时,为什么我要使用networkidle0?使用networkidle0是否更快?信号“networkidle0”的文档在哪里?“networkidle0”在此处文档化,应
页面。waitForSelector
页面后调用。转到
或之前调用?您能回答我提出的类似问题吗?当我可以使用默认加载事件时,为什么我要使用networkidle0?使用networkidle0更快吗?我不知道为什么这个答案没有得到更多的“爱”。事实上,很多时候,我们只需要确保JavaScript在抓取页面之前弄乱了页面。网络事件无法实现这一点,如果您有动态生成的内容,那么您并不总能可靠地执行“waitForSelector/visible:true”操作on@anand-玛哈扬超级英雄!非常感谢:DThanks@roberto-顺便说一句,我刚刚更新了答案,您可以将其用于“load”事件,而不是“networkidle2”。我觉得这样会更好一点。我已经在生产中进行了测试,可以确认它工作得很好!这是一个很好的解决方案。谢谢分享!伟大的解决方案,应该是木偶图库的一部分,但请不要等待是不推荐的一个将被删除我