网络爬虫的异步请求



我有一个URL数组,我想从每个URL中抓取一个html表,并以与原始数组相同的顺序将其保存在另一个数组中。

由于节点的异步性质,我认为它没有按预期工作,每次结果的顺序都不同。

我用谷歌搜索了很多,并尝试了不同的事情,例如使用自定义的异步函数或请求承诺而不是请求,但没有任何效果。

const request = require('request');
const rp = require('request-promise');
const cheerio = require('cheerio');
const fs = require('fs');
let verbs = [];
let conjugations = [];
fs.readFileSync('verbs.txt', 'utf-8').split(/r?n/).forEach
(function(line){
  verbs.push(line);
});
verbs.forEach((verb) => {
    const URI = encodeURI("https://ru.wiktionary.org/wiki/" + verb);
    var options = {
        uri: URI,
        transform: function (body) {
            return cheerio.load(body);
        }
    };
    rp(options).then(function ($) {
        let table = $('span#Русский.mw-headline').parent().nextAll('table').first();
        conjugations.push(table.text());
        console.log(conjugations[0]);
    })
    .catch(function (err) {
    });
})

        
  
    

如果顺序很重要,请使用 Promise.all。

Promise.all(( 方法返回单个 Promise,当作为可迭代对象传递的所有承诺都已解析或可迭代对象不包含任何承诺时,该方法将解析。它以第一个拒绝的承诺为由拒绝。

保持秩序的示例:

const verbs = ["hello", "world", "example"];
let timeout = 2000;
const promises = verbs.map(verb=>{
  timeout -= 500;
  return new Promise((resolve,reject)=>{
    setTimeout(function(){
      resolve(verb);
    }, timeout);
  });
});
Promise.all(promises).then(dataArray=>console.log(dataArray));

使用您的代码解决问题。

const promises = verbs.map((verb) => {
  const URI = encodeURI("https://ru.wiktionary.org/wiki/" + verb);
  var options = {
    uri: URI,
    transform: function(body) {
      return cheerio.load(body);
    }

  };
  return rp(options);
})
Promise.all(promises).then(dataArray=>{
     dataArray.forEach(function($) {
      let table = $('span#Русский.mw-headline').parent().nextAll('table').first();
      conjugations.push(table.text());
      console.log(conjugations[0]);
    })
}).catch(function(err) {});

缺点是,如果一个请求失败,它们都会失败。

或者,你可以通过使用每个动词的索引来做这样的事情(使用 Promise.all 来确定何时完成所有操作,但可以忽略该步骤......

const verbs = ["hello", "world", "example"];
const conjugations = [];
let timeout = 2000;
const promises = verbs.map((verb, index)=>{
  return new Promise((resolve, reject)=>{
    setTimeout(function(){
      conjugations[index] = verb;
      resolve();
    }, timeout);
    timeout -= 500;
  });
});
Promise.all(promises).then(()=>console.log(conjugations));

代码示例。

const request = require('request');
const rp = require('request-promise');
const cheerio = require('cheerio');
const fs = require('fs');
let verbs = [];
let conjugations = [];
fs.readFileSync('verbs.txt', 'utf-8').split(/r?n/).forEach(function(line) {
  verbs.push(line);
});
verbs.forEach((verb, index) => {
      const URI = encodeURI("https://ru.wiktionary.org/wiki/" + verb);

      var options = {
        uri: URI,
        transform: function(body) {
          return cheerio.load(body);
        }
      };
      rp(options).then(function($) {
          let table = $('span#Русский.mw-headline').parent().nextAll('table').first();
          conjugations[index] = table.text();
          console.log(conjugations[index]);
        })
        .catch(function(err) {});

最新更新