如何让puppeteer跟随新页面实例中的多个链接,以并发和异步方式评估它们?
答案 0 :(得分: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();
};
然后你需要承诺生产者。每次调用此函数时,它都会从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;
};
最后,您可以选择CONCURRENCY执行此操作:
const pool = new PromisePool(promiseProducer, CONCURRENCY);
await pool.start();
由于这是经常被问到的问题,我也在我们的Apify平台上做了一个工作示例https://www.apify.com/mtrunkat/puppeteer-promise-pool-example
编辑12.10.2018
我还想补充一点,我们最近围绕Puppeteer的并发抓取构建了完整的开源SDK。它解决了主要的痛苦,如:
答案 1 :(得分:3)
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();
})();