javascript - 完成所有操作后再进行一次抓取的最佳方法

标签 javascript puppeteer apify

我有以下场景:

  • 我的爬虫需要登录,所以我总是需要先点击一个登录页面
  • 然后我有一个包含 30 个 url 的列表,我可以根据需要异步抓取这些 url
  • 然后在最后,当所有这 30 个 url 都被抓取后,我需要点击最后一个单独的 url 以将 30 个 URL 抓取的结果放入 firebase 数据库并进行一些其他更改(例如地址的地理查找等等)

目前我有一个请求队列中的所有 30 个 url(通过 Apify 网络界面),我正在尝试查看它们何时全部完成。

但显然它们都是异步运行的,因此数据永远不可靠

 const queue = await Apify.openRequestQueue();
 let  pendingRequestCount  = await queue.getInfo();

我需要将最后一个 URL 分开的原因有两个:

  1. 最明显的原因是我需要确定我有 在我将所有内容发送到 DB 之前所有 30 次抓取的结果
  2. 这 30 个 URL 都不允许我进行 Ajax/Fetch 调用,这 我需要发送到 Firebase 并进行地址的地理查找

编辑:根据@Lukáš Křivka 的回答进行了尝试。 while 循环中的 handledRequestCount 达到最大值 2,而不是 4 ...,Puppeteer 正常结束。我将“return”放在 while 循环中,否则请求永远不会完成(当然)。

在我当前的测试设置中,我有 4 个要抓取的 url(在 Puppeteer Scraper(在 Apify.com 上)的 Start URLS 输入字段中和此代码:

let title = "";
const queue = await Apify.openRequestQueue();
let {handledRequestCount} = await queue.getInfo();
while (handledRequestCount < 4){
    await new Promise((resolve) => setTimeout(resolve, 2000)) // wait for 2 secs
    handledRequestCount = await queue.getInfo().then((info) => info.handledRequestCount);
    console.log(`Curently handled here: ${handledRequestCount} --- waiting`) // this goes max to '2'
    title = await page.evaluate(()=>{ return $('h1').text()});
    return {title};
}
log.info("Here I want to add another URL to the queue where I can do ajax stuff to save results from above runs to firebase db");
title = await page.evaluate(()=>{ return $('h1').text()});
return {title};

最佳答案

我需要查看您的代码才能完全正确地回答,但这有解决方案。

只需使用 Apify.PuppeteerCrawler对于 30 个 URL。然后使用 await crawler.run() 运行爬虫。

之后,您可以简单地通过以下方式从默认数据集中加载数据

const dataset = await Apify.openDataset();
const data = await dataset.getdata().then((response) => response.items);

无论对数据做什么,您甚至可以创建新的 Apify.PuppeteerCrawler 来抓取最后一个 URL 并使用数据。

不过,如果您使用的是 Web Scraper,那就有点复杂了。您可以:

1) 为 Firebase 上传创建一个单独的 actor,并从 Web Scraper 向其传递一个 webhook 以从中加载数据。如果您查看 Apify store ,我们已经有了一个 Firestore uploader 。

2) 添加一个逻辑,该逻辑将像您所做的那样轮询 requestQueue,并且仅当所有请求都已处理时,您才继续。您可以创建某种等待的循环。例如

const queue = await Apify.openRequestQueue();
let { handledRequestCount } = await queue.getInfo();
while (handledRequestCount < 30) {
    console.log(`Curently handled: ${handledRequestCount } --- waiting`)
    await new Promise((resolve) => setTimeout(resolve, 2000)) // wait for 2 secs
    handledRequestCount = await queue.getInfo().then((info) => info.handledRequestCount);
}
// Do your Firebase stuff

关于javascript - 完成所有操作后再进行一次抓取的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57472856/

相关文章:

javascript - Extjs 无法在文件已上传后再次上传文件

javascript - Flask 应用程序将数据发布到错误的资源?

javascript - Puppeteer - 自定义字体未加载到 pdf 中,但确实出现在屏幕截图中

javascript - 通过选择器获取动态元素

javascript - 如何在 JS/JQuery 中迭代 Xpath

puppeteer - session 和并发以及它们之间的关系

javascript - JavaScript 中的 this 是什么样的数组?

javascript 全局变量 - 保护

node.js - 无法让 Puppeteer 工作和安装

javascript - 网页无限滚动时如何让Apify Crawler滚动整页?