2015-11-19 78 views
-2

我创建使用cheerio,并要求客户一个简单的刮刀,但它不工作我想要的方式。for循环的Node.js +请求:运行两次

首先,我看到所有的“空回来,什么都不做”终端上的消息,然后看到的名称,所以我觉得它首先会检查所有返回null,则非空的URL。

我想它如果你不使用承诺按照正确的顺序运行,从1到100

app.get('/back', function (req, res) { 
    for (var y = 1; y < 100; y++) { 
    (function() { 
     var url = "example.com/person/" + y +; 
     var options2 = { 
     url: url, 
     headers: { 
      'User-Agent': req.headers['user-agent'], 
      'Content-Type': 'application/json; charset=utf-8' 
     } 
     }; 
     request(options2, function (err, resp, body) { 
     if (err) { 
      console.log(err); 
     } else { 
      if ($ = cheerio.load(body)) { 
      var links = $('#container'); 
      var name = links.find('span[itemprop="name"]').html(); // name 
      if (name == null) { 
       console.log("null returned, do nothing"); 
      } else { 
       name = entities.decodeHTML(name); 
       console.log(name); 
      } 
      } 
      else { 
      console.log("can't open"); 
      } 
     } 
     }); 
    }()); 
    } 
}); 
+0

什么是 “正确的秩序”? – Houseman

+0

@Houseman从1到100 – salep

+0

你的循环不会等待第一个请求到第二个触发之前返回。 Javascript是异步的。有很多技术可以让你等待。 [例如](https://zackehh.com/handling-synchronous-asynchronous-loops-javascriptnode-js/)。或者你可以使用像[Q]这样的库(https://github.com/kriskowal/q)。 [此外,这种(http://stackoverflow.com/questions/15162049/javascript-synchronizing-foreach-loop-with-callbacks-inside) – Houseman

回答

3

,并要连续运行的要求,那么这是一条共同的设计模式连续异步循环:

app.get('/back', function (req, res) { 
    var cntr = 1; 

    function next() { 
     if (cntr < 100) { 
      var url = "example.com/person/" + cntr++; 
      var options2 = { 
       url: url, 
       headers: { 
        'User-Agent': req.headers['user-agent'], 
        'Content-Type': 'application/json; charset=utf-8' 
       } 
      }; 
      request(options2, function (err, resp, body) { 
       if (err) { 
        console.log(err); 
       } else { 
        if ($ = cheerio.load(body)) { 
         var links = $('#container'); 
         var name = links.find('span[itemprop="name"]').html(); // name 
         if (name == null) { 
          console.log("null returned, do nothing"); 
         } else { 
          name = entities.decodeHTML(name); 
          console.log(name); 
         } 
        } else { 
         console.log("can't open"); 
        } 
        // do the next iteration 
        next(); 
       } 
      }); 
     } 
    } 
    // start the first iteration 
    next(); 
}); 

如果你想在并行(多个请求同时在飞行中)所有的请求,这将是一个更快的最终结果,然后在年底积累的所有结果,以便,你可以这样做:

// create promisified version of request() 
function requestPromise(options) { 
    return new Promise(function(resolve, reject) { 
     request(options2, function (err, resp, body) { 
      if (err) return reject(err); 
      resolve(body); 
     }); 
    }); 
} 

app.get('/back', function (req, res) { 
    var promises = []; 
    var headers = { 
     'User-Agent': req.headers['user-agent'], 
     'Content-Type': 'application/json; charset=utf-8' 
    }; 
    for (var i = 1; i < 100; i++) { 
     promises.push(requestPromise({url: "example.com/person/" + i, headers: headers})); 
    } 
    Promise.all(promises).then(function(data) { 
     // iterate through all the data here 
     for (var i = 0; i < data.length; i++) { 
      if ($ = cheerio.load(data[i])) { 
       var links = $('#container'); 
       var name = links.find('span[itemprop="name"]').html(); // name 
       if (name == null) { 
        console.log("null returned, do nothing"); 
       } else { 
        name = entities.decodeHTML(name); 
        console.log(name); 
       } 
      } else { 
       console.log("can't open"); 
      } 
     } 
    }, function(err) { 
     // error occurred here 
    }); 

}); 
+0

@salep - 我使用promise添加了一个并行版本。 – jfriend00

+0

可能是值得使用节点取的,因为这已经成为标准,并且已经答应基于... – Tracker1

+0

@ Tracker1 - 是的,那工作了。我不知道你的意思是“成为标准”。它不是构建在node.js中,也不是Node.js中的任何标准轨道,除非您在浏览器中讨论获取API。节点提取是许多可用于提取数据的库之一。 [request-promise](https://github.com/request/request-promise)也可作为请求的promisified版本。 – jfriend00