Nodejs:带有URL

时间:2017-11-15 04:03:22

标签: node.js request web-crawler

我正在使用抓取工具。我有一个需要请求的URL列表。如果我没有将它设置为异步,则同时有几百个请求。我担心它会破坏我的带宽或产生对目标网站的大量网络访问。我该怎么办?

这是我正在做的事情:

urlList.forEach((url, index) => {

    console.log('Fetching ' + url);
    request(url, function(error, response, body) {
        //do sth for body

    });
});

我希望在一个请求完成后调用一个请求。

4 个答案:

答案 0 :(得分:0)

您需要注意的事项是:

  1. 目标网站是否有速率限制,如果您尝试请求太快,可能会被阻止访问?

  2. 目标网站可以处理多少个并发请求而不会降低其性能?

  3. 服务器的最终带宽是多少?

  4. 您自己的服务器可以在飞行和处理过程中同时发出多少请求,而不会导致过多的内存使用或挂钩的CPU。

  5. 通常,管理所有这些的方案是创建一种方法来调整您启动的请求数量。有多种不同的方法可以通过同时请求的数量,每秒的请求数量,使用的数据量等来控制它...

    最简单的启动方式是控制您同时发出的请求数。这可以这样做:

    function runRequests(arrayOfData, maxInFlight, fn) {
        return new Promise((resolve, reject) => {
            let index = 0;
            let inFlight = 0;
    
            function next() {
                while (inFlight < maxInFlight && index < arrayOfData.length) {
                    ++inFlight;
                    fn(arrayOfData[index++]).then(result => {
                        --inFlight;
                        next();
                    }).catch(err => {
                        --inFlight;
                        console.log(err);
                        // purposely eat the error and let the rest of the processing continue
                        // if you want to stop further processing, you can call reject() here
                        next();
                    });
                }
                if (inFlight === 0) {
                    // all done
                    resolve();
                }
            }
            next();
        });
    }
    

    然后,你会像这样使用它:

    const rp = require('request-promise');
    
    // run the whole urlList, no more than 10 at a time
    runRequests(urlList, 10, function(url) {
        return rp(url).then(function(data) {
            // process fetched data here for one url
        }).catch(function(err) {
            console.log(url, err);
        });
    }).then(function() {
        // all requests done here
    });
    

    通过向其添加时间元素(每秒不超过N个请求)或甚至是带宽元素,可以将其设置为您想要的复杂。

      

    我希望在一个请求完成后调用一个请求。

    这是一种非常缓慢的做事方式。如果你真的想要那个,那么你可以将1 maxInFlight参数传递给上面的函数,但通常,事情会更快地运行并且不会因为允许介于5到50之间而导致问题同时请求。只有测试才能告诉您特定目标站点和特定服务器基础架构的最佳位置以及您需要对结果进行的处理量。

答案 1 :(得分:0)

但是,这在三.2之前的设备上可能无法很好地绘制,因为它们不理解sw600dp作为长度限定符,因此您仍然必须使用大限定符。因此,您应该有一个名为 res/format-big/most important.Xml 的记录,它与 res/layout-sw600dp/essential.Xml 相同。在下一节中,您将看到一种允许您避免以这种方式复制布局文件的方法。

答案 2 :(得分:0)

您可以使用 Promise 库之类的东西,例如片段

const Promise = require("bluebird");
const axios = require("axios");

//Axios wrapper for error handling
const axios_wrapper = (options) => {
    return axios(...options)
        .then((r) => {
            return Promise.resolve({
                data: r.data,
                error: null,
            });
        })
        .catch((e) => {
            return Promise.resolve({
                data: null,
                error: e.response ? e.response.data : e,
            });
        });
};

Promise.map(
    urls,
    (k) => {
        return axios_wrapper({
            method: "GET",
            url: k,
        });
    },
    { concurrency: 1 } // Here 1 represents how many requests you want to run in parallel
)
    .then((r) => {
        console.log(r);
        //Here r will be an array of objects like {data: [{}], error: null}, where if the request was successfull it will have data value present otherwise error value will be non-null
    })
    .catch((e) => {
        console.error(e);
    });

答案 3 :(得分:-1)

您可以使用set timeout函数来处理循环内的所有请求。为此,您必须知道处理请求的最长时间。