与Puppeteer同时进行页面抓取

mal*_*ich 3 javascript puppeteer

如何让puppeteer在新页面实例中跟踪多个链接,以并发和异步方式评估它们?

Mar*_*kát 5

几乎每个Puppeteer方法都返回一个Promise.因此,您可以使用https://www.npmjs.com/package/es6-promise-pool包.

首先,您需要创建一个处理一个url的异步函数:

const crawlUrl = async (url) => {
    // Open new tab.
    const page = await browser.newPage();
    await page.goto(url);

    // Evaluate code in a context of page and get your data.
    const result = await page.evaluate(() => {
        return {
            title: document.title,
            url: window.location.href,
        };
    });
    results.push(result);

    // Close it.
    await page.close();
};
Run Code Online (Sandbox Code Playgroud)

然后你需要承诺生产者.每次调用此函数时,它都会从URLS_TO_BE_CRAWLED常量中获取一个url 并返回crawlUrl(url)promise.一旦URLS_TO_BE_CRAWLED变空,它返回null完成池.

const promiseProducer = () => {
    const url = URLS_TO_BE_CRAWLED.pop();

    return url ? crawlUrl(url) : null;
};
Run Code Online (Sandbox Code Playgroud)

最后,使用您选择的CONCURRENCY执行此操作:

const pool = new PromisePool(promiseProducer, CONCURRENCY);
await pool.start();
Run Code Online (Sandbox Code Playgroud)

由于这是经常被问到的问题,我还在我们的Apify平台上做了一个工作示例https://www.apify.com/mtrunkat/puppeteer-promise-pool-example


编辑12.10.2018

我还要补充一点,我们最近构建了完整的开源SDK,围绕Puppeteer进行并发抓取.它解决了主要的痛苦,例如:

  • 基于CPU和内存自动缩放并发
  • 使用请求队列重试请求失败
  • 浏览器的轮换(切换代理)

请查看:https://github.com/apifytech/apify-js


Tho*_*orf 5

Mareks解决方案适用于几页,但是如果您要同时爬网大量页面,建议您查看我的库puppeteer-cluster

它并行运行任务(例如Mareks解决方案),但同时还要注意错误处理,重试和其他一些事情。您可以在下面看到一个最小的示例。也可以在更复杂的设置中使用库。

const { Cluster } = require('puppeteer-cluster');

(async () => {
  const cluster = await Cluster.launch({
    concurrency: Cluster.CONCURRENCY_CONTEXT, // use one browser per worker
    maxConcurrency: 4, // cluster with four workers
  });

  // Define a task to be executed for your data
  await cluster.task(async ({ page, data: url }) => {
    await page.goto(url);
    const screen = await page.screenshot();
    // ...
  });

  // Queue URLs
  cluster.queue('http://www.google.com/');
  cluster.queue('http://www.wikipedia.org/');
  // ...

  // Wait for cluster to idle and close it
  await cluster.idle();
  await cluster.close();
})();
Run Code Online (Sandbox Code Playgroud)