2016-12-20 3 views
0

Я строю простой скребок с использованием Request.js и Cheerio.js в Express. Прямо сейчас я ищу только название сайта. Вместо того, чтобы соскабливать сайт один за другим, я помещаю список в массив. Я разбираю их, а затем использую Cheerio.js, чтобы найти название веб-сайта. Когда я консоль регистрирую заголовки, они выдаются отлично, но я хочу, в конечном счете, показать их на html-странице. Обратите внимание: я очень новичок в программировании, поэтому, если бы вы могли предоставить подробную обратную связь, это было бы невероятно полезно (ниже код, над которым я работал). Заранее спасибо!Использование Request.js и Cheerio.js в Node/Express возвращает пустой массив

function parseSites(urls) { 
var parsedSites = []; 
urls.forEach(function(site) { 
     request(site, function(err, res, body) { 
      if(err) { 
       console.log(err); 
      } else { 
       var $ = cheerio.load(body); 
       parsedSites.push($('title').text()); 
       } 
      }  
     });    
    }); 
    return parsedSites; 
} 

ответ

0

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

function testFor() { 
    for(let i=0;i<5;++i){ 
     console.log(i); 
    } 
} 

-

console.log('start:'); 
testFor(); 
console.log('end:'); 

// Here you get the expected output because this code is synchronous. 
//output: 
    start: 
    0 
    1 
    2 
    3 
    4 
    end: 

-

console.log('start:'); 
setTimeout(testFor,1000); 
console.log('end:'); 

// Here you don't get your expected output because setTimeout is asynchronous . 
//output: 
    start: 
    end: 
    0 
    1 
    2 
    3 
    4 
  1. Сначала console.log ('старт:'); называется.
  2. Затем setTimeout (testFor, 1000); (но это асинхронно, и вызов будет выполняться через 1 секунду).
  3. Сразу после console.log ('end:'); называется.
  4. Наконец 1 второе после этого, testFor() выполняется, и он печатает 0 1 2 3 4

Следующая точка в том, что есть ошибка в коде!

function parseSites(urls) { 
    var parsedSites = []; 
    urls.forEach(function(site) { 
     request(site, function(err, res, body) { 
      if(err) { 
       console.log(err); 
      } else { 
       var $ = cheerio.load(body); 
       parsedSites.push($('title').text()); 
      } 
     //} ! THIS bracket should be removed 
     }); 
    }); 
    return parsedSites; 
} 

Итак, ваша проблема в том, что «запрос» в цикле ForEach является функцией асинхронной, которая будет вызывать обратный вызов «функции (эээ, Рез, тело)» раз есть ответ от веба-страницы.

Мои решения для этого:

'use strict' 

const cheerio = require('cheerio'); 
const request = require('request'); 
const async = require('async'); 

const urls = ['http://stackoverflow.com/','http://hackaday.com/','https://www.raspberrypi.org/','https://cheerio.js.org/']; 

//SOLUTION 1: do what you need to do when all calls are done using recursion 
let i=0; 
let parsedSites = []; 
parseSites(urls[i],parsedSites); 
function finalCall(sites) { 
    console.log(sites); 
} 
function parseSites(site,parsedSites) { 
    ++i; 
    request(site, function(err, res, body) { 
     if(err) { 
      console.log(err); 
     } else { 
      let $ = cheerio.load(body); 
      let title = $('title').text(); 
      console.log(title); 
      parsedSites.push(title); 
     } 
     if(i<urls.length){ 
      parseSites(urls[i],parsedSites);// recursive call; 
     } 
     else{ 
      finalCall(parsedSites);// when all sites are done. 
     } 
    }); 
    //return parsedSites;// cant return! we are in async calls! 
} 


//SOLUTION 2: do what you need to do when all calls are done using 'async' 
parseSites(urls); 
function finalCall(sites) { 
    console.log(sites); 
} 
function parseSites(urls) { 
    let parsedSites = []; 
    async.each(urls,function parseSite(site, callback) { 
     request(site, function (err, res, body) { 
      if (err) { 
       callback(err); 
      } else { 
       let $ = cheerio.load(body); 
       parsedSites.push($('title').text()); 
       callback(); 
      } 
     }) 
    },function (err) { 
     if(err) console.log(err); 
     else finalCall(parsedSites); 
    }); 
} 

Async github page

Async example

+0

Спасибо так много для детальной обратной связи. Обсуждался с async.js и все еще пытался освоить асинхронный код. Это супер супер полезно! – teamjustin

0

Пожалуйста, обратитесь к ниже код для рабочей реализации

var request = require('request-promise') 
    var cheerio = require("cheerio") 

    function parseSites(urls, callback) { 
     var parsedSites = []; 
     var promiseList = urls.map(getPage) 

     Promise.all(promiseList).then(function (data) { 
      callback(data.map(parse)) 
     }) 

     return parsedSites; 
    } 

    function getPage(url) { 

     return request.get(url) 
    } 

    function parse(body) { 
     console.log("parsing body") 
     var $ = cheerio.load(body); 
     return $('title').text() 
    } 

    parseSites(['https://www.google.com','https://www.facebook.com'],function(data) { 
     console.log(data) 
    }) 
+0

Большое спасибо за отзыв. в настоящее время изучает обещания помочь с асинхронным кодом! – teamjustin

Смежные вопросы