Puppeteer 等待页面完全加载
Puppeteer wait until page is completely loaded
我正在从网页创建 PDF。
我正在处理的应用程序是单页应用程序。
我在 https://github.com/GoogleChrome/puppeteer/issues/1412
上尝试了很多选项和建议
但是没用
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 报告。
我不想写任何类型的延迟,即 await page.waitFor(2000);
我无法执行 waitForSelector,因为该页面包含计算后呈现的图表。
将不胜感激。
我总是喜欢等待 选择器,因为其中很多都是页面已完全加载的重要指标:
await page.waitForSelector('#blue-button');
您可以使用 page.waitForNavigation()
等待新页面完全加载后再生成 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 中,请考虑使用 page.waitForSelector()
以确保内容可见:
await page.waitForSelector('#example', {
visible: true,
});
将 page.click
和 page.waitForNavigation
包裹在 Promise.all
中
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' });
您可以在 puppeteer 文档中查看:
https://pptr.dev/#?product=Puppeteer&version=v11.0.0&show=api-pagewaitfornavigationoptions
在最新的 Puppeteer 版本中,networkidle2
对我有用:
await page.goto(url, { waitUntil: 'networkidle2' });
有时 networkidle
事件并不总是指示页面已完全加载。可能还有一些JSscripts
在修改页面内容。因此,等待浏览器完成 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.waitForTimeout(checkDurationMsecs);
}
};
您可以在页面 load
/ click
函数调用之后和处理页面内容之前使用它。例如
await page.goto(url, {'timeout': 10000, 'waitUntil':'load'});
await waitTillHTMLRendered(page)
const data = await page.content()
您还可以使用 来确保所有元素都已呈现
await page.waitFor('*')
至于 2020 年 12 月,waitFor
函数已弃用,正如代码中的警告所示:
waitFor is deprecated and will be removed in a future release. See
https://github.com/puppeteer/puppeteer/issues/6214 for details and how
to migrate your code.
您可以使用:
sleep(millisecondsCount) {
if (!millisecondsCount) {
return;
}
return new Promise(resolve => setTimeout(resolve, millisecondsCount)).catch();
}
并使用它:
(async () => {
await sleep(1000);
})();
我在处理离屏渲染器时遇到了与 networkidle
相同的问题。我需要一个基于 WebGL 的引擎来完成渲染,然后才制作屏幕截图。对我有用的是 page.waitForFunction() 方法。在我的例子中,用法如下:
await page.goto(url);
await page.waitForFunction("renderingCompleted === true")
const imageBuffer = await page.screenshot({});
在渲染代码中,完成后我只是将 renderingCompleted
变量设置为 true。如果您无权访问页面代码,您可以使用其他一些现有标识符。
我不能发表评论,但我为任何认为有用的人(即如果他们使用 pyppeteer)制作了一个 python 版本的 Anand 答案。
async def waitTillHTMLRendered(page: Page, timeout: int = 30000):
check_duration_m_secs = 1000
max_checks = timeout / check_duration_m_secs
last_HTML_size = 0
check_counts = 1
count_stable_size_iterations = 0
min_stabe_size_iterations = 3
while check_counts <= max_checks:
check_counts += 1
html = await page.content()
currentHTMLSize = len(html);
if(last_HTML_size != 0 and currentHTMLSize == last_HTML_size):
count_stable_size_iterations += 1
else:
count_stable_size_iterations = 0 # reset the counter
if(count_stable_size_iterations >= min_stabe_size_iterations):
break
last_HTML_size = currentHTMLSize
await page.waitFor(check_duration_m_secs)
我正在从网页创建 PDF。
我正在处理的应用程序是单页应用程序。
我在 https://github.com/GoogleChrome/puppeteer/issues/1412
上尝试了很多选项和建议但是没用
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 报告。
我不想写任何类型的延迟,即 await page.waitFor(2000);
我无法执行 waitForSelector,因为该页面包含计算后呈现的图表。
将不胜感激。
我总是喜欢等待 选择器,因为其中很多都是页面已完全加载的重要指标:
await page.waitForSelector('#blue-button');
您可以使用 page.waitForNavigation()
等待新页面完全加载后再生成 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 中,请考虑使用 page.waitForSelector()
以确保内容可见:
await page.waitForSelector('#example', {
visible: true,
});
将 page.click
和 page.waitForNavigation
包裹在 Promise.all
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' });
您可以在 puppeteer 文档中查看: https://pptr.dev/#?product=Puppeteer&version=v11.0.0&show=api-pagewaitfornavigationoptions
在最新的 Puppeteer 版本中,networkidle2
对我有用:
await page.goto(url, { waitUntil: 'networkidle2' });
有时 networkidle
事件并不总是指示页面已完全加载。可能还有一些JSscripts
在修改页面内容。因此,等待浏览器完成 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.waitForTimeout(checkDurationMsecs);
}
};
您可以在页面 load
/ click
函数调用之后和处理页面内容之前使用它。例如
await page.goto(url, {'timeout': 10000, 'waitUntil':'load'});
await waitTillHTMLRendered(page)
const data = await page.content()
您还可以使用 来确保所有元素都已呈现
await page.waitFor('*')
至于 2020 年 12 月,waitFor
函数已弃用,正如代码中的警告所示:
waitFor is deprecated and will be removed in a future release. See https://github.com/puppeteer/puppeteer/issues/6214 for details and how to migrate your code.
您可以使用:
sleep(millisecondsCount) {
if (!millisecondsCount) {
return;
}
return new Promise(resolve => setTimeout(resolve, millisecondsCount)).catch();
}
并使用它:
(async () => {
await sleep(1000);
})();
我在处理离屏渲染器时遇到了与 networkidle
相同的问题。我需要一个基于 WebGL 的引擎来完成渲染,然后才制作屏幕截图。对我有用的是 page.waitForFunction() 方法。在我的例子中,用法如下:
await page.goto(url);
await page.waitForFunction("renderingCompleted === true")
const imageBuffer = await page.screenshot({});
在渲染代码中,完成后我只是将 renderingCompleted
变量设置为 true。如果您无权访问页面代码,您可以使用其他一些现有标识符。
我不能发表评论,但我为任何认为有用的人(即如果他们使用 pyppeteer)制作了一个 python 版本的 Anand 答案。
async def waitTillHTMLRendered(page: Page, timeout: int = 30000):
check_duration_m_secs = 1000
max_checks = timeout / check_duration_m_secs
last_HTML_size = 0
check_counts = 1
count_stable_size_iterations = 0
min_stabe_size_iterations = 3
while check_counts <= max_checks:
check_counts += 1
html = await page.content()
currentHTMLSize = len(html);
if(last_HTML_size != 0 and currentHTMLSize == last_HTML_size):
count_stable_size_iterations += 1
else:
count_stable_size_iterations = 0 # reset the counter
if(count_stable_size_iterations >= min_stabe_size_iterations):
break
last_HTML_size = currentHTMLSize
await page.waitFor(check_duration_m_secs)