2016-11-23 3 views
0

Это мой первый вопрос, задающий вопрос, поэтому, пожалуйста, несите меня. Я пытаюсь написать скребок для содержимого в node.js. Моя программа перейдет на целевую страницу сайта, получит ссылку на следующую страницу и получит ссылку на следующую партию страниц. Моя проблема в том, когда мне приходится перебирать массив ссылок, переходить на эту страницу и получать там информацию об утилизации. Я пытаюсь выполнить async.forEhe iteration, но заканчивается после последнего then() в моих цепных обещаниях. Многие из концепций здесь новы для меня, поэтому я уверен, что этот код является отвратительным. Любая помощь будет оценена по достоинству.Bluebird обещает и async.forEach итерации

var sX = require('scrapper-x'); 
 
var request = require('request'); 
 
var async = require('async'); 
 
var Promise = require('bluebird'); 
 
var request = (require('request')); 
 
var colors = require('colors'); 
 

 
var baseURL = 'http://shirts4mike.com'; 
 
var arrShirts = [ 
 
    { 
 
     link: 'shirt.php?id=101', 
 
     img: 'some img' 
 
    }, 
 
    { 
 
     link: 'shirt.php?id=102', 
 
     img: 'some img' 
 
    }, 
 
    { 
 
     link: 'shirt.php?id=103', 
 
     img: 'some img' 
 
    } 
 
]; 
 

 
var page = ''; 
 

 
var configMain = { 
 
    repeatItemGroup: '.nav > li', 
 
    dataFormat: { 
 
     link: { 
 
      selector: 'li > a', 
 
      type: 'attr:href' 
 
     } 
 
    } 
 
}; 
 

 
var configShirts = { 
 
    repeatItemGroup: '.products > li', 
 
    dataFormat: { 
 
     link: { 
 
      selector: 'li > a', 
 
      type: 'attr:href' 
 
     }, 
 
     img: { 
 
      selector: 'li > a > img', 
 
      type: 'attr:src' 
 
     } 
 
    } 
 
}; 
 

 
var configDetails = { 
 
    repeatItemGroup: '.shirt-details', 
 
    dataFormat: { 
 
     price: { 
 
      selector: '.price', 
 
      type: 'text' 
 
     }, 
 
     title: { 
 
      selector: '.shirt-details > h1', 
 
      type: 'text' 
 
     } 
 
    } 
 
}; 
 

 

 
function getPage(url, config) { 
 
    return new Promise(function(resolve, reject) { 
 
     request(url, function(error, response, body, shirt) { 
 
       if (error) { 
 
        console.log('error'); 
 
        reject(); 
 
       } 
 
       if (!error && response.statusCode == 200) { 
 
        detail = sX.scrape(body, config); 
 
        resolve(detail); 
 
       } 
 
      }); 
 

 
    }); 
 
} 
 

 
function getDetailPage(arr, config) { 
 
    return new Promise(function(resolve, reject) { 
 
     async.forEach(arr, function(item, callback) { 
 
      request('http://www.shirts4mike.com' + '/' + item.link, function(error, response, body, item) { 
 
       if (!error && response.statusCode == 200) { 
 
        detail = sX.scrape(body, configDetails); 
 
        console.log('Item: ', detail); 
 
       } 
 
      }); 
 
      callback(); 
 
     }); 
 
     resolve(detail); 
 
    }); 
 
} 
 

 
    getPage(baseURL, configMain).then(function(data) { 
 
     for (var i = 0; i < data.length; i++) { 
 
      //console.log('getMainPage: ', scrappedResult[i].link); 
 
      if (data[i].link.search('shirt') !== -1) { 
 
       page = '/' + data[i].link; 
 
       console.log(page.yellow); 
 
       baseURL += page; 
 
       return baseURL; 
 
      } 
 
     } 
 
    }).then(function(baseURL) { 
 
     return getPage(baseURL, configShirts); 
 
    }).then(function(data) { 
 
     for (var i = 0; i < data.length; i++) { 
 
      //console.log(data[i].link); 
 
      if (data[i].link.search('shirt') !== -1) { 
 
       arrShirts.push(data[i]); 
 
       console.log("arrShirts[" + i + "]: " + arrShirts[i].link); 
 
      } 
 
     } 
 
     return arrShirts; 
 
    }).then(function(arr) { 
 
     return getDetailPage(arrShirts, configDetails); 
 
    }).then(function (data) { 
 
     console.log("end: ", data); 
 
    }).catch(function(err) { 
 
     console.log(err); 
 
    });

+0

использовать глобальный (необъявленный) уаг 'detail' в двух различных функциях - это преднамеренный? –

+1

Вам будет намного лучше, если вы не будете смешивать асинхронную библиотеку с обещаниями. Выберите один или другой для управления вашими асинхронными операциями (предпочтительно обещаниями). – jfriend00

+1

Async не имеет 'forEach' (возможно, был один в прошлом) - и если он такой же, как' async.each', вы используете его неправильно, но, да, что сказал @jfriend, смешивание двух чревато с разочарованиями и слезами: p –

ответ

1

Я хотел бы предложить кучу изменений.

  1. Прекратить использование глобальных переменных или переменных с более высокой степенью охвата или необъявленных переменных. Объявите локальные переменные, где они используются/необходимы и не используют переменные с другими функциями.

  2. Не смешивайте асинхронную библиотеку с обещаниями. Поскольку вы уже обещаете свои асинхронные функции, используйте функции обещаний для управления несколькими асинхронными операциями. Вы можете просто удалить асинхронную библиотеку из этого проекта.

  3. Продвигайтесь на самом низком уровне, который является практичным, поэтому все более высокие уровни использования могут просто использовать обещания напрямую. Итак, вместо того, чтобы обещать getPage(), вы должны обещать request(), а затем использовать его в getPage().

  4. Поскольку у вас есть библиотека обещаний Bluebird, вы можете использовать ее итерационные функции более высокого уровня, такие как Promise.map(), чтобы перебирать вашу коллекцию, собирать все результаты и возвращать единственное обещание, которое сообщает вам, когда все будет сделано.

Используя эти понятия, вы можете использовать такой код:

// promisified request() 
function getRequest(url) { 
    return new Promise(function(resolve, reject) { 
     request(url, function(err, response, body) { 
      if (err) { 
       reject(err); 
      } else { 
       resolve(body); 
      } 
     }); 

    }); 
} 

// resolves to scraped contents for one page 
function getPage(url, config) { 
    return getRequest(url).then(function(body) { 
     returm sX.scrape(body, config); 
    }); 
} 

// resolves to an array of scraped contents for an array of objects 
// that each have a link in them 
function getDetailPage(arr, config) { 
    return Promise.map(arr, function(item) { 
     return getPage('http://www.shirts4mike.com' + '/' + item.link); 
    }); 
} 
+0

Спасибо, что нашли время ответить. Я так ценю это. Я сделаю исправления, как вы предлагаете, и посмотрите, где он меня принимает. Сначала я попробовал асинк и не смог пройти итеративный проход. Затем отбросил это и попробовал Bluebird, но также повесил трубку в той же точке. Сочетание двух было отчаянием :)). Еще раз спасибо! – Bleeks