node.js request.js / cheerio.js返回空的json

时间:2014-08-26 06:03:05

标签: node.js callback cheerio

我正在开发一款可以抓取网站并将数据公开为其他API的应用。我使用Node,Express,request,cheerio。我好像在数组中得到正确的值..但是在返回之前......数组仍然是空的(在请求函数范围之外)

我无法锻炼我所缺少的东西。你能看看我的代码并告诉我吗?

app.js中的

我指定了路线

    app.use('/timetable', timetable.timetable(url));

in timetable.js

var classes = require('../lib/classes');
var schedule = require('../lib/schedule');
exports.timetable = function(timeTableURL) {

return function(req, res) {

    request( timeTableURL, function srapeWebsite(error, response, html ) {
        var webHtml = '';
        var moreInfo = []; 
        if( !error && response.statusCode === 200 ) {
            webHtml = cheerio.load(html);
        }
        // schedule.getInfo returns an array of json objects where
        // json = {
        //    day,
        //    number,
        //    url
        // }
        var info = schedule.getInfo(webHtml);

        for (var index = 0; index < info.length; index++) {     
            var json = info[index];
            classes.getMoreInfo(json, function (moreInfoJson) {
                //console.log shows correct information here
                moreInfo.push(moreInfoJson);
            };
        }
        // however moreInfo is empty here..hence not getting anything
        res.json(moreInfo);
    } );
  };
};

想法是,对于数组中的每个json对象,从指定的url获取更多信息。

所以最终的结果是,

    finalJson = {
       day : ''
       json : []
    }

在classes.js

exports.getMoreInfo =  function (info, callback) {

var infoDay = info.day;
var infoNumber = parseInt(info.number);
var moreInfoURL = info.moreInfoUrl;
var stuff = [];

var moreInfo = {};
moreInfo.day = infoDay;
moreInfo.json = [];

if (infoNumber > 0 ) {
    request(moreInfoURL, function(error, response,html) {
        var moreInfoHtml = '';
        if( !error && response.statusCode === 200 ) {
            moreInfoHtml = cheerio.load(html) ;

        }
        var $ = moreInfoHtml;

        $('table tbody tr').each ( function getWhatisNeeded () {
            var json = getJson ( $(this) );
            stuff.push(json);

        });

        moreInfo.json = stuff;
        return callback(moreInfo);
    });
  }
}

2 个答案:

答案 0 :(得分:3)

您对classes.getMoreInfo的调用是异步的。

你不会等待调用返回,并使用空数组调用res.json。

编辑: 如何解决这个问题?一种方法是使用promisses(参见例如https://github.com/malko/D.js)。

getMoreInfo应该返回一个延迟对象:

exports.getMoreInfo =  function (info) {
    var deferred = D();
    ...
    request(..., function(){
        deferred.resolve(moreInfo);
    });
    ...
    return deferred.promise;
}

和timetable.js应该或多或少看起来像这样:

var promises = [];
for (var index = 0; index < info.length; index++) {     
    var json = info[index];
    promises.push(classes.getMoreInfo(json));
}
D.all(promises).this(function(array_of_results){
    res.json(array_of_results);
}

我没有测试代码,所以我可能在这里有一个错误,但这是如何解决node.js中的异步问题的一个很好的指导方针。 让自己熟悉承诺,解决这样的问题要容易得多。

答案 1 :(得分:0)

感谢提示'jonjon'..我使用Async.map来修复它(抱歉打算昨天发布它..但是你打败了它)..我也会尝试Promises ..我不妨学习这两种技术..

这就是我为解决它而做的事情。

在app.js

app.get('/timetable', timetable.timetable);

在timetable.js

var url = '...';
exports.timetable = function ( request, response ) {

    //scrape html to get info
    scrape.getHtml( url, function ( error, html ) {
    // schedule.getInfo returns an array of json objects where
    // json = {
    //    day,
    //    number,
    //    url
    // }
    var info = schedule.getInfo(cheerio.load(html));

    //getmoreinfo
    async.map(info, classes.getMoreInfo, function( error,moreInfo ) {
        if(!error) {
            response.json(moreInfo);
        }else {
            response.send("error encountered");
        }
    });
  });
}

在classes.js

   exports.getMoreInfo =  function (info, callback) {

   var infoDay = info.day;
   var infoNumber = parseInt(info.number);
   var moreInfoURL = info.moreInfoUrl;
   var stuff = [];

   var moreInfo = {};
   moreInfo.day = infoDay;
   moreInfo.json = [];

   if (infoNumber > 0 ) {
   request(moreInfoURL, function(error, response,html) {
    var moreInfoHtml = '';
    if( !error && response.statusCode === 200 ) {
        moreInfoHtml = cheerio.load(html) ;

    }
    var $ = moreInfoHtml;

    $('table tbody tr').each ( function getWhatisNeeded () {
        var json = getJson ( $(this) );
        stuff.push(json);

    });

    moreInfo.json = stuff;
    return callback(null, moreInfo);
  });
 }
}

我正在接受我现在所追求的东西......无论如何它似乎需要5秒......无论如何都需要测试更多......