puppeteer的內(nèi)部窗口和打開的外部窗口大小不一致
images
我們可以看到右側(cè)和下邊欄都有一個大的空白顾孽。
我們使用下面代碼
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
await page.goto('https://google.com');
關(guān)于這個原因是因為默認情況下開啟了ViewPort
的功能,這里可以通過defaultViewport:null選項來禁用
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null
});
waitUntil
waitUntil代表什么時候才認為導(dǎo)航加載成功。
- load: window.onload事件被觸發(fā)時候完成導(dǎo)航,某些情況下它根本不會發(fā)生声邦。
- domcontentloaded: Domcontentloaded事件觸發(fā)時候認為導(dǎo)航成功
- networkidle0: 在 500ms 內(nèi)沒有網(wǎng)絡(luò)連接時就算成功(全部的request結(jié)束),才認為導(dǎo)航結(jié)束
- networkidle2: 500ms 內(nèi)有不超過 2 個網(wǎng)絡(luò)連接時就算成功(還有兩個以下的request),就認為導(dǎo)航完成明郭。
我們對比了下加載時長 networkidle0> networkidle2>load>domcontentloaded
使用networkidle0的時候,隨時可能網(wǎng)絡(luò)加載時間在2s以上。我們希望500ms的時長是可配置的胚迫,因為500ms太長了。
function waitForNetworkIdle(page, timeout, maxInflightRequests = 0) {
page.on('request', onRequestStarted);
page.on('requestfinished', onRequestFinished);
page.on('requestfailed', onRequestFinished);
let inflight = 0;
let fulfill;
let promise = new Promise(x => fulfill = x);
let timeoutId = setTimeout(onTimeoutDone, timeout);
return promise;
function onTimeoutDone() {
page.removeListener('request', onRequestStarted);
page.removeListener('requestfinished', onRequestFinished);
page.removeListener('requestfailed', onRequestFinished);
fulfill();
}
function onRequestStarted() {
++inflight;
if (inflight > maxInflightRequests)
clearTimeout(timeoutId);
}
function onRequestFinished() {
if (inflight === 0)
return;
--inflight;
if (inflight === maxInflightRequests)
timeoutId = setTimeout(onTimeoutDone, timeout);
}
}
// Example
await Promise.all([
page.goto('https://google.com'),
waitForNetworkIdle(page, 500, 0), // 和 'networkidle0'效果相同
]);
evaluate, evaluateHandle, exposeFunction
evaluate
page.evaluate(pageFunction, …args) 返回的是一個可序列化的對象唾那。
const result = await page.evaluate((x) => {
return x;
}, 'abc')
上面這段代碼可以返回abc
字段
const result = await page.evaluate(
x => {
return x;
},
() => 'abc'
);
console.log(result); // 返回undefined
exposeFunction
這個 API 用來在頁面注冊全局函數(shù)访锻,因為有時候需要在頁面處理一些操作的時候需要用到一些函數(shù),雖然可以通過 page.evaluate()
API 在頁面定義函數(shù)。
await page.exposeFunction('md5', text => '__' + text);
const result = await page.evaluate(() => {
return window.md5('abc');
});
console.log(result); // 返回 __abc
但是這里也需要注意一點,exposeFunction 也不能傳遞,也是需要序列化的對象
evaluateHandle
Page.evaluateHandle(pageFunction, …args) 在 Page 上下文執(zhí)行一個 pageFunction, 返回 JSHandle 實體
evaluateHandle可以傳遞一個字符串或者函數(shù)期犬,返回promise對象河哑。
const func = () => 'abc';
const handle = await page.evaluateHandle(`(${func.toString()})`);
const abc = await page.evaluate(a => {
return a();
}, handle);