【问题标题】:How to increase efficiency while web scraping?网页抓取时如何提高效率?
【发布时间】:2019-05-31 06:38:00
【问题描述】:

我有一个节点脚本,它不断地抓取网站列表以获取信息。我想尝试提高脚本的效率;但是,nodejs a 是单线程运行时。但在幕后,nodejs 是多线程的,允许异步代码。有没有办法利用这一点来提高效率?如果没有,替代方案?

现在脚本同步运行。我尝试过混合使用同步和异步代码,但我总是用尽堆栈。示例代码不包括用于抓取数据或检查数据的逻辑,因为它是不相关的。

const request = require('request-promise');
const cheerio = require('cheerio');

const siteList = require('./websites.json');

async function scrapePage(link)
{
    let $, data = {};

    $ = await request({
        uri: link,
        transform: (body) => { return cheerio.load(body) },
        connection : 'keep-alive',
    });

    // Scrape data using cheerio

    return data;
}

async function scrapePages()
{
    for(let site of siteList)
    {
        let data = await scrapePage(site.url);

        // Check data for favored result
    }

    // Tail call to reuse stack space
    return scrapePages();
}

scrapePages();

对于质疑抓取范围的个人,网站列表少于 100 个。

【问题讨论】:

  • 使用Child Process 或实验性Thread
  • @GetOffMyLawn 两者都完全不适合手头的任务。他的问题是他一次只做一件事。
  • 节点一次只能处理一件事,你可以使用async/await 任何你想要的,但它的核心仍然一次只能处理一件事。因此,子进程或线程将处理同步问题。
  • 在您的示例代码中,您实际上并没有对结果做任何事情,是因为它被虚拟化了吗?我们在谈论多少个网址?你只是在监控输出吗?
  • @GetOffMyLawn 这里的问题不是服务器受 CPU 限制......问题是他一次只发出一个请求。如果服务器实际上受 CPU 限制,则考虑线程或多进程。同时,简单地同时发出多个请求可以更好地利用系统。

标签: javascript node.js web-scraping


【解决方案1】:

您现在的代码将等待scrapePage() 完成:

let data = await scrapePage(site.url);

如果您想一次抓取多个页面,请更改 for 循环的工作方式。例如,在数组上使用 .forEach()

为了便于控制同时操作的数量,请考虑使用 await-semaphore 之类的包。

https://www.npmjs.com/package/await-semaphore

然后,你可以做这样的事情......

import {Semaphore} from 'await-semaphore';
const semaphore = new Semaphore(10); // 10 operations at a time

// Then, inside a loop...
semaphore.use(() => {
  // do your work here
});

【讨论】:

  • 为什么不干脆忘记 await,做一个 promise.all?我真的不明白为什么模拟其他多线程语言的包会比本地语言功能更有用
  • @Icepickle 毫无疑问,他想要将 99999999 个东西堆成一个数组并刮掉它们。 Promise.all() 在这种情况下会耗尽系统资源,因为所有尝试都将同时启动。一个人当然可以编写自己的代码,一次从数组中开始说 10 件事情,当它们成功或失败时,开始阵列中的下一件事情。我发现这个特殊的包(await-semaphore)轻巧方便,但绝对不需要任何人使用它。
  • 不过,我想知道这是否真的很重要,他不会同时发送所有这些请求(您一次只能发出这么多请求,具体取决于您的系统设置),所以我真的不相信这很重要。由于 OP 并没有真正指定他的抓取范围,我想很难说会发生什么。我同意你的观点,await 是问题所在,但是根据网站输入,我可能只做return Promise.all( siteList.map( site => scrapePage( site.url ) ) 并担心以后的任何其他事情:)
  • @Icepickle Node.js 默认没有请求限制。 (他们几年前从默认代理中取消了该限制。)我向您保证,他们都会堆积起来并尝试同时运行。此外,如果您在浏览器中尝试此操作,浏览器将开始抱怨大约数千个同时请求的资源不足,即使是同一来源,它们一次仅限于几个。
  • 当然,但它仍在操作系统/浏览器之上运行。我要说的是,我真的不认为它会产生如此大的不同:)
猜你喜欢
  • 1970-01-01
  • 2021-07-06
  • 2011-02-21
  • 2018-02-21
  • 2013-01-15
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
  • 2016-08-25
相关资源
最近更新 更多