Puppeteer - 在 page.select() 之后等待网络请求完成

dan*_*ong 5 javascript node.js puppeteer

有没有办法在页面上执行操作后等待网络请求解析,然后再在 Puppeteer 中执行新操作?

我需要与页面上的选择菜单进行交互,page.select()这会导致动态图像和字体加载到页面中。我需要等待这些请求完成才能执行下一步操作。

--

注意事项:

  1. 我无法重新加载页面或转到新网址。
  2. 我不知道请求类型可能是什么,也不知道有多少

--

// launch puppeteer
const browser = await puppeteer.launch({});

// load new page
const page = await browser.newPage();

// go to URL and wait for initial requests to resolve
await page.goto(pageUrl, {
  waitUntil: "networkidle0"
});

// START LOOP
for (let value of lotsOfValues) {

  // interact with select menu
  await page.select('select', value);

  // wait for network requests to complete (images, fonts)
  ??

  // screenshot page with new content
  await pageElement.screenshot({
    type: "jpeg",
    quality: 100
  });

} // END LOOP

// close
await browser.close();
Run Code Online (Sandbox Code Playgroud)

dan*_*ong 9

答案在于使用page.setRequestInterception(true);和监视后续请求,等待它们响应,然后再继续下一个任务(感谢@Guarev指出了正确的方向)。

这个模块(https://github.com/jtassin/pending-xhr-puppeteer)正是这样做的,但是对于 XHR 请求。我修改它来查找“图像”和“字体”类型。

最终代码如下所示:

// launch puppeteer
const browser = await puppeteer.launch({});

// load new page
const page = await browser.newPage();

// go to URL and wait for initial requests to resolve
await page.goto(pageUrl, {
  waitUntil: "networkidle0"
});

// enable this here because we don't want to watch the initial page asset requests (which page.goto above triggers) 
await page.setRequestInterception(true);

// custom version of pending-xhr-puppeteer module
let monitorRequests = new PuppeteerNetworkMonitor(page);

// START LOOP
for (let value of lotsOfValues) {

  // interact with select menu
  await page.select('select', value);

  // wait for network requests to complete (images, fonts)
  await monitorRequests.waitForAllRequests();

  // screenshot page with new content
  await pageElement.screenshot({
    type: "jpeg",
    quality: 100
  });

} // END LOOP

// close
await browser.close();
Run Code Online (Sandbox Code Playgroud)

NPM模块

class PuppeteerNetworkMonitor {

    constructor(page) {
        this.promisees = [];
        this.page = page;
        this.resourceType = ['image'];
        this.pendingRequests = new Set();
        this.finishedRequestsWithSuccess = new Set();
        this.finishedRequestsWithErrors = new Set();
        page.on('request', (request) => {
            request.continue();
            if (this.resourceType.includes(request.resourceType())) {
                this.pendingRequests.add(request);
                this.promisees.push(
                    new Promise(resolve => {
                        request.resolver = resolve;
                    }),
                );
            }
        });
        page.on('requestfailed', (request) => {
            if (this.resourceType.includes(request.resourceType())) {
                this.pendingRequests.delete(request);
                this.finishedRequestsWithErrors.add(request);
                if (request.resolver) {
                    request.resolver();
                    delete request.resolver;
                }
            }
        });
        page.on('requestfinished', (request) => {
            if (this.resourceType.includes(request.resourceType())) {
                this.pendingRequests.delete(request);
                this.finishedRequestsWithSuccess.add(request);
                if (request.resolver) {
                    request.resolver();
                    delete request.resolver;
                }
            }
        });
    }

    async waitForAllRequests() {
        if (this.pendingRequestCount() === 0) {
            return;
        }
        await Promise.all(this.promisees);
    }

    pendingRequestCount() {
        return this.pendingRequests.size;
    }
}

module.exports = PuppeteerNetworkMonitor;
Run Code Online (Sandbox Code Playgroud)