Делать различные запросы, используя nightmare.js - PullRequest
0 голосов
/ 17 мая 2018

Я использую nightmarejs для очистки сайта.Во-первых, я делаю запрос на выбор некоторых ссылок, которые ведут на другую страницу с дополнительной информацией, которую я тоже хочу.Я разделил его на две функции:

const { csvFormat } = require('d3-dsv');
const Nightmare = require('nightmare');
const { writeFileSync } = require('fs');

const url = 'https://lojaonline.claro.com.br/celular';

function getUrls (){
    console.log('Extraindo Links...');
    const nightmare = new Nightmare({show: true});
    var p1 = '51030';
    var p2 = '560';
    try{
        nightmare.goto(url).wait('input[id="edit-cep-part1"]')
                           .type('input[id="edit-cep-part1"]', p1)
                           .wait('input[id="edit-cep-part2"]')
                           .type('input[id="edit-cep-part2"]', p2)
                           .click('input[value="Confirmar"]')
                           .wait('#products-container .products-list').evaluate(function(){

            return Array.from(document.querySelectorAll('.offer')).map(element => element.href);            

        }).end()
        .then(function(result){

            var listaUrls = Object.values(result);

            return listaUrls;

        })
        .then(function(listaUrls){
            listaUrls.forEach(function(link){
                console.log('Pegando preços de ' + link);
                getPrecos(link);
            });
        });
    }catch(e){
        console.error(e);
    }
};

function getPrecos(endereco) {
    console.log('Extraindo preços...');
    const nightmare = new Nightmare({gotoTimeout: 999999999});
    var p1 = '51030';
    var p2 = '560';
    try{

         nightmare.goto(endereco).wait('input[id="edit-cep-part1"]')
                                .type('input[id="edit-cep-part1"]', p1)
                                .wait('input[id="edit-cep-part2"]')
                                .type('input[id="edit-cep-part2"]', p2)
                                .click('input[value="Confirmar"]')
                                .wait('#plans-tab').evaluate(function(){

            return Array.from(document.querySelectorAll('tr.body')).map(element => element.innerText);          

        }).end()
        .then(function(result){

            var listaPrecos = Object.values(result);

            console.log(listaPrecos);
        });
    }catch(e){
        console.error(e);
    }
};

getUrls();

По большей части это работает.Некоторые запросы выполнены успешно, и я могу получить информацию, но некоторые запросы истекают по истечении 30 секунд:

 UnhandledPromiseRejectionWarning: Error: .wait() for #plans-tab timed out after 30000msec.

Мне нужно подождать, ввести и щелкнуть, потому что этот конкретный веб-сайт запрашивает почтовый индекс перед отображениемданные.И если я покажу: true внутри функции getPrecos, появится 20 экземпляров электрона.Что я тут не так делаю?

Можно ли сгенерировать запрос только после того, как предыдущий закончен?

1 Ответ

0 голосов
/ 23 мая 2018

Вы используете forEach для циклического перемещения по списку, если вы хотите, чтобы они собирали данные один за другим, вам следует использовать for...of и async await или некоторую библиотеку обещаний с поддержкой параллелизма.

listaUrls.forEach(function(link) {
  console.log("Pegando preços de " + link);
  getPrecos(link);
});

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

// other part of code
.then(async function(listaUrls) { // <-- async function
  for(const link of listaUrls){
      console.log("Pegando preços de " + link);
      await getPrecos(link); // <-- go thru the link one by one
  }
});
...