木偶操纵者不等到页面加载完成
Puppeteer Not Waiting Until Page Load Complete
我写了一个脚本来截取网页上的 50 个尺寸图表。每个图表都包含在一个元素中。有趣的是,只有前三个 table 图表被捕获,其余的 PNG 文件是空白的,完全是白色的。
由于图表是从数据库中提取的,我认为可能是在截屏之前页面尚未完成加载,所以我添加了 { "waitUntil": "networkidle0" } 但是那没有解决任何问题。不过,该脚本仅创建前三个图表 0.png、1.png 和 2.png 的屏幕截图。其余 PNG 文件 3.png - 49.png 已创建,但只是白色数据。
可能是什么问题?如果我在浏览器上访问该页面,所有 50 个图表都能完美加载,那么为什么 Puppeteer 只截取前三个图表?这是我的脚本:
const puppeteer = require( 'puppeteer' );
( async() => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto( 'http://www.example.com/size-charts.php', { "waitUntil": "networkidle0" } );
// Get a list of all elements.
const elements = await page.$$( 'div.chartContainer' );
for( let i = 0; i < elements.length; i++ ) {
try {
// get screenshot of a particular element
await elements[ i ].screenshot( { path: `${ i }.png` } );
}
catch( e ) {
console.log( `Couldn't take a screenshot of the element with the index of: ${ i }. Reason: `, e );
}
}
await browser.close();
} )();
虽然实际的解决方案 can/should 是等待每个元素可见,但还有一些可能的其他解决方案可用。
可能的解决方案 1
您可以滚动到该元素,等待片刻以正确呈现,然后截取屏幕截图。
elementHandle.screenshot()
滚动到元素,但无法延迟或等待元素可见。
A quick search on official repo 显示目前至少有 19 个未解决的问题提到 blank screenshot
。
相反,我们可以使用自定义 .evaluate 或 .hover 等在截屏之前滚动到元素。
elementHandle.hover()
: This method scrolls element into view if needed, and then uses page.mouse to hover over the center of the element. If the element is detached from DOM, the method throws an error.
让我们使用它,
// Get a list of all elements.
const elements = await page.$$('div.chartContainer');
for (let i = 0; i < elements.length; i++) {
// scrolls into view and hovers the element
await elements[i].hover();
// wait for some random number
await page.waitFor(1000);
// get screenshot of a particular element
await elements[i].screenshot({
path: `${ i }.png`
});
}
可能的解决方案 2
一些人报告说使用 elementHandle.boundingBox()
解决了他们的问题。它的作用是获取元素的位置、高度、宽度等并将其用于屏幕截图。
// Get a list of all elements.
const elements = await page.$$('div.chartContainer');
for (let i = 0; i < elements.length; i++) {
// get screenshot of a particular area
await page.screenshot({ // <-- use page here
path: `${ i }.png`,
clip: await elements[i].boundingBox() // <-- use clip here
});
}
我将回答我自己的问题,希望它能帮助到其他人。在我的特殊情况下,解决方案是将视口高度设置为非常大的数字,例如:
page.setViewport( { width: 1920, height: 100000 } );
之后,脚本能够创建所有选定元素的屏幕截图。
我写了一个脚本来截取网页上的 50 个尺寸图表。每个图表都包含在一个元素中。有趣的是,只有前三个 table 图表被捕获,其余的 PNG 文件是空白的,完全是白色的。
由于图表是从数据库中提取的,我认为可能是在截屏之前页面尚未完成加载,所以我添加了 { "waitUntil": "networkidle0" } 但是那没有解决任何问题。不过,该脚本仅创建前三个图表 0.png、1.png 和 2.png 的屏幕截图。其余 PNG 文件 3.png - 49.png 已创建,但只是白色数据。
可能是什么问题?如果我在浏览器上访问该页面,所有 50 个图表都能完美加载,那么为什么 Puppeteer 只截取前三个图表?这是我的脚本:
const puppeteer = require( 'puppeteer' );
( async() => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto( 'http://www.example.com/size-charts.php', { "waitUntil": "networkidle0" } );
// Get a list of all elements.
const elements = await page.$$( 'div.chartContainer' );
for( let i = 0; i < elements.length; i++ ) {
try {
// get screenshot of a particular element
await elements[ i ].screenshot( { path: `${ i }.png` } );
}
catch( e ) {
console.log( `Couldn't take a screenshot of the element with the index of: ${ i }. Reason: `, e );
}
}
await browser.close();
} )();
虽然实际的解决方案 can/should 是等待每个元素可见,但还有一些可能的其他解决方案可用。
可能的解决方案 1
您可以滚动到该元素,等待片刻以正确呈现,然后截取屏幕截图。
elementHandle.screenshot()
滚动到元素,但无法延迟或等待元素可见。
A quick search on official repo 显示目前至少有 19 个未解决的问题提到 blank screenshot
。
相反,我们可以使用自定义 .evaluate 或 .hover 等在截屏之前滚动到元素。
elementHandle.hover()
: This method scrolls element into view if needed, and then uses page.mouse to hover over the center of the element. If the element is detached from DOM, the method throws an error.
让我们使用它,
// Get a list of all elements.
const elements = await page.$$('div.chartContainer');
for (let i = 0; i < elements.length; i++) {
// scrolls into view and hovers the element
await elements[i].hover();
// wait for some random number
await page.waitFor(1000);
// get screenshot of a particular element
await elements[i].screenshot({
path: `${ i }.png`
});
}
可能的解决方案 2
一些人报告说使用 elementHandle.boundingBox()
解决了他们的问题。它的作用是获取元素的位置、高度、宽度等并将其用于屏幕截图。
// Get a list of all elements.
const elements = await page.$$('div.chartContainer');
for (let i = 0; i < elements.length; i++) {
// get screenshot of a particular area
await page.screenshot({ // <-- use page here
path: `${ i }.png`,
clip: await elements[i].boundingBox() // <-- use clip here
});
}
我将回答我自己的问题,希望它能帮助到其他人。在我的特殊情况下,解决方案是将视口高度设置为非常大的数字,例如:
page.setViewport( { width: 1920, height: 100000 } );
之后,脚本能够创建所有选定元素的屏幕截图。