جاوااسکریپت - Puppeteer منتظر بمانید تا صفحه کاملاً بارگذاری شود
من در حال کار روی ایجاد فایل 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 استفاده کنم چون صفحه دارای نمودارها و گرافهایی است که پس از محاسبات رندر میشوند.
کمک قدردانی خواهد شد.
پاسخ شماره ۱
شما میتوانید از 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,
});
پاسخ شماره ۲
گاهی اوقات رویدادهای networkidle همیشه نشاندهنده بارگذاری کامل صفحه نیستند. ممکن است هنوز چند JS script در حال تغییر محتوای صفحه باشند. بنابراین مشاهده تکمیل تغییرات کد منبع 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.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
پاسخ شماره ۴
من همیشه دوست دارم منتظر انتخابکنندهها بمانم، زیرا بسیاری از آنها نشانگر خوبی هستند که صفحه به طور کامل بارگذاری شده است:
await page.waitForSelector('#blue-button');
پاسخ شماره ۵
در آخرین نسخه Puppeteer، networkidle2 برای من کار کرد:
await page.goto(url, { waitUntil: 'networkidle2' });
پاسخ شماره ۶
توابع page.click و page.waitForNavigation را در یک Promise.all بپیچید
await Promise.all([
page.click('#submit_button'),
page.waitForNavigation({ waitUntil: 'networkidle0' })
]);
