【问题标题】:Why Running Multiple Data Scraping Tasks Take More Time Asynchronsly In Comparsion To Individually?与单独运行相比,为什么异步运行多个数据抓取任务需要更多时间?
【发布时间】:2020-09-14 15:39:20
【问题描述】:

我在 Node.JS 中使用 puppeteer 来运行数据抓取任务,该任务试图一次从多个页面获取数据。每个页面都有一个选项卡式结构,我需要从 4 个选项卡中获取数据。我单击一个选项卡并使用“等待”从选项卡获取数据。最后,我将获得的数据写入excel文件。除了完成所需的时间外,代码可以正常工作。 如果我为单个 URL 运行代码,则需要 7 到 10 秒来获取每个 URL 的数据并将数据写入 Excel 文件。但是,如果我在“for”循环中运行 16 个 URL 的代码,则几乎需要 30 到 33 秒。我认为完成这项工作需要不到 12 秒的时间,因为它是异步运行的。在一个 for 循环中运行 16 个任务期间,CPU 中的所有线程都被占用 100%。代码太长,这里就写代码结构:

由于我不知道如果任务失败如何重复任务,我编写了 2 个 try-catch 结构,因为它们是嵌套的。

for (i = 0; i < URL.length; i++) {
    try {
        UpdateTable(URL[i], i, 1);
    } catch (e) {
        try {
            UpdateTable(URL[i], i, 2);
        } catch (e) {
            UpdateTable(URL[i], i, 3);
        }
    }
}

async function UpdateTable(URL, ii, Ind) {
    return new Promise((resolve, reject) => {
        var temp = [];
        temp = (async () => {
            console.time(("i: " + ii + ": " + Ind).toString());
            console.timeLog("i: " + ii + ": " + Ind);
            try {
                const browser = await puppeteer.launch({headless: true});
                const page = await browser.newPage();
                await page.goto(URL); //Bourse


                //Tab 1:
                await page.evaluate(() => {
                    document.getElementsByClassName('torq')[0].click();
                })
                await page.waitForSelector("tr.ev", {visible: true}).then(() => {
                });

                var temp = [];
                var temp_1col = [];
                var temp1_1col = [];
                temp = await page.evaluate(() => {
                //
                //
                //
                //
                //
                }
                
                
                //Tab 2:
                await page.evaluate(() => {
                    document.getElementsByClassName('vio')[0].click();
                })
                await page.waitForSelector("div.CalMon", {visible: true}).then(() => {
                });

                var temp1 = [];
                temp1 = await page.evaluate(() => {
                //
                //
                //
                //
                //
                }
                
                
                //Tab 3:
                await page.evaluate(() => {
                    document.querySelectorAll('a.re')[0].click();
                })
                var tt = await page.evaluate(() => {
                    return document.getElementById("d12").innerText;
                })

                while (tt === undefined || tt === "") {
                    tt = await page.evaluate(() => {
                        return document.getElementById("d12").innerText;
                    })
                }

                var temp2 = [];
                temp2 = await page.evaluate(() => {
                //
                //
                //
                //
                //
                }
                
                //Tab 4:
                await page.evaluate(() => {
                    document.querySelectorAll('a.ye')[0].click();
                })
                await page.waitForXPath("//div[@class='Main']//span//tr[5]//td[2]", {visible: true}).then(() => {
                });

                var temp4 = await page.evaluate(() => {
                //
                //
                //
                //
                //
                }
                
                
                //Writing to Excel file Using: "exceljs" module:
                const sheet8 = workbook3.addWorksheet("Adjusted");
                sheet8.views = [{rightToLeft: true}];
                sheet8.addRows(temp_adj);
                
                await browser.close();
                console.timeEnd(("i: " + ii + ": " + Ind).toString());
                return temp;
                } catch (e) {
                    console.log("Error In: " + URL);
            }
        })();
    });
}
                            

我测量了每个循环完成的时间:

i: 0: 1: 0.065ms
i: 1: 1: 0.020ms
i: 2: 1: 0.004ms
i: 3: 1: 0.004ms
i: 4: 1: 0.028ms
i: 5: 1: 0.007ms
i: 6: 1: 0.003ms
i: 7: 1: 0.018ms
i: 8: 1: 0.018ms
i: 9: 1: 0.005ms
i: 10: 1: 0.003ms
i: 11: 1: 0.003ms
i: 12: 1: 0.003ms
i: 13: 1: 0.003ms
i: 14: 1: 0.003ms
i: 15: 1: 0.003ms
i: 13: 1: 13728.609ms
i: 0: 1: 14846.398ms
i: 15: 1: 14857.476ms
i: 4: 1: 18383.652ms
i: 6: 1: 18504.466ms
i: 10: 1: 22255.862ms
i: 5: 1: 29188.227ms
i: 7: 1: 29187.398ms
i: 14: 1: 30093.722ms
i: 8: 1: 30297.994ms
i: 2: 1: 30381.256ms
i: 1: 1: 30426.768ms
i: 11: 1: 30644.432ms
i: 12: 1: 30677.942ms
i: 3: 1: 30689.566ms
i: 9: 1: 30710.694ms

正如您在时间日志中看到的,URL[13] 需要 13728.609 毫秒,而如果我运行此 URL 的代码,则只需 8000 毫秒。为什么与单个任务相比,一起运行 16 个任务需要更多时间?为什么异步运行需要30710.694ms,而一个任务的最长时间却低于10000ms?

如果您能帮助我解决这个挑战,我将不胜感激。

【问题讨论】:

  • 如果您不启动多个浏览器而只是在同一个浏览器中创建新页面怎么办?
  • 我检查了它:“browser.newPage();”打开一个新标签:stackoverflow.com/a/48554636/13864833;你能详细描述一下你的想法吗?
  • 我的意思是如果你取消这个调用:const browser = await puppeteer.launch({headless: true}); 并重用单个浏览器会怎样?您可以将其传递给函数或使其成为全局变量。
  • 我阅读了 puppeteer 文档。据我了解doc,'puppeteer.launch' 仅用于设置浏览器的属性,它不会打开浏览器。顺便说一句,我测试了您的建议并将“浏览器”作为输入传递给函数,但这会导致错误。你能看看文档吗?也许我错了。
  • 我考虑了这里提到的所有要点,但还有另一个挑战:并行打开的新标签有库存。我找到了this,现在代码可以正常工作了。并行抓取 19 个 URL 的时间和消耗的 RAM 是:“使用新的 Chrome 应用程序:41 秒和 5.3GB”和“使用新的 Chrome 选项卡:37 秒和 4.4GB”。时间减少 10%,RAM 消耗减少 17%。我真的很感谢你们所有人。但是 10 秒和 37 秒之间仍然存在很长的差异。

标签: node.js asynchronous puppeteer


【解决方案1】:

在类似的情况下,我观​​察到内存耗尽并且系统开始交换。在内存和磁盘之间移动数据的速度很慢,而且很快就达到了似乎需要很长时间才能完成的地步。 100% 的 CPU 利用率很好,但也要注意使用了多少内存。

【讨论】:

  • 根据您的观点,我检查了 Ram。启动任务前,占用内存为7.8GB,运行任务时达到12.2GB。安装的Ram是16GB,但是Ram慢慢的占用很流畅,完成任务后突然下降到7.8GB。我将 URL 的数量从 16 个增加到 19 个,现在任务需要 41103.325ms,这意味着时间效率变差了。
猜你喜欢
  • 2012-06-28
  • 2020-06-05
  • 1970-01-01
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
  • 2020-06-08
  • 1970-01-01
相关资源
最近更新 更多