2014-11-26 4 views
1

Node.js에 웹 페이지를 긁어서 일부 링크를 얻기 위해 작은 스크립트를 작성했습니다. 스크래핑 부분은 Cheerio와 함께 이루어집니다. 내 코드 (공간 간체) 여기에 있습니다 : 여기 JSON 문서가 신비하게 "비었습니다"

var request = require('request'); 
var cheerio = require('cheerio'); 

var base_url = 'http://www.naftemporiki.gr/finance/'; 

var mutuals = {}; 
mutuals.date = new Date(); 
mutuals.companies = []; 

var company = {}; 

request(base_url + 'mtfCompanies', function (error, response, html) { 
    if (!error && response.statusCode == 200) { 
     var $ = cheerio.load(html); 

     $('.blueRow.texttd.name a').each(function (i, element) { 
      var a = $(this); 

      company = {}; 
      company.name = a.text(); 
      company.link = a.attr('href'); 

      mutuals.companies.push(company); 
     }); 
    } 
    //console.log(mutuals);   // 1st place 
}); 
console.log(mutuals);    // 2nd place 

은 재미 부분을 제공 : I 출력에 "1 위"에서 JSON 문서를하려고하면 '요청'블록 내부에, 그것은 좋은 나오는 참된. 예는 여기에 있습니다 :

{ date: Wed Nov 26 2014 10:35:09 GMT+0200 (EET), 
    companies: 
    [ { name: ' J.P. MORGAN ASSET MANAGEMENT', 
     link: 'mtfCompany?id=J.P.+MORGAN+ASSET+MANAGEMENT' }, 
    { name: ' BNP PARIBAS INVESTMENT PARTNERS', 
     link: 'mtfCompany?id=BNP+PARIBAS+INVESTMENT+PARTNERS' }, 
    { name: ' PICTET', link: 'mtfCompany?id=PICTET' }, 
    { name: ' ALLIANZ ΑΕΔΑΚ', 
     link: 'mtfCompany?id=ALLIANZ+%ce%91%ce%95%ce%94%ce%91%ce%9a' }, 
    { name: ' ALLIANZ ΑΕΔΑΚ (ΑΝΤΙΠΡ.)', 
     link: 'mtfCompany?id=ALLIANZ+%ce%91%ce%95%ce%94%ce%91%ce%9a+(%ce%91%ce%9d%ce%a4%ce%99%ce%a0%ce%a1.)' }, 
    { name: ' ALLIANZ ΕΛΛΑΣ Α.Ε.', 
     link: 'mtfCompany?id=ALLIANZ+%ce%95%ce%9b%ce%9b%ce%91%ce%a3+%ce%91.%ce%95.' }]} 

I 출력에 "2 위"에서 JSON 문서를 시도, 어떤 블록의 외부 및 실행의 끝에서, 이것은 내가 무엇을 얻을 수 있습니다 :

{ date: Wed Nov 26 2014 10:35:09 GMT+0200 (EET), companies: [] } 

JSON 문서의 '회사'배열이 비게됩니다. 나는 'mutuals.companies = [];'라는 의혹을 가지고 있습니다. 라인은 어떤 이유로 다시 실행됩니다.

아무도 도와 드릴 수 있습니까?

UPDATE 1 : 사용 제안

내 코드를 변경 'async.series을 ...'. 다음은 업데이트 된 버전입니다.

var request = require('request'), 
    async = require('async'), 
    cheerio = require('cheerio'); 

var base_url = 'http://www.naftemporiki.gr/finance/'; 

var mutuals = {}; 
mutuals.date = new Date(); 
mutuals.companies = []; 

var company = {}; 

async.series([ 
    function(callback) { 
     request(base_url + 'mtfCompanies', function (error, response, html) { 
      if (!error && response.statusCode == 200) { 
       var $ = cheerio.load(html); 

       $('.blueRow.texttd.name a').each(function (i, element) { 
        var a = $(this); 

        company = {}; 
        company.name = a.text(); 
        company.link = a.attr('href'); 

        mutuals.companies.push(company); 
       }); 
      } 
     }); 
     callback(null, 'one'); 
    }, 
    function (callback) { 
     console.log(mutuals); 
     callback(null, 'two'); 
    } 
]); 

여전히 작동하지 않습니다. 여전히 출력 된 JSON은 다음과 같습니다.

{ date: Wed Nov 26 2014 10:35:09 GMT+0200 (EET), companies: [] } 

답변

3

"2 위"는 요청이 완료되기 전에 변수를 인쇄합니다.

"1 위"는 요청의 콜백 내에 있기 때문에 작동합니다. 요청이 이루어지고 데이터가 꺼내지면 콜백이 호출되어 성공적으로 인쇄됩니다.

비동기 코드가 작동하는 방식입니다. 아무것도 차단하지 않습니다. 따라서 요청을하면 노드는 콜백 함수를 저장하여 요청 결과와 함께 코드를 실행할 수있게합니다.

업데이트 1 :

하여 업데이트의 문제는 대부분 동일합니다. 이 시리즈의 첫 번째 기능에서는 요청이 완료되기 전에 callback이 호출됩니다. 콜백을 요청에 전달 된 함수로 이동하면 요청이 완료된 후에 콜백이 호출됩니다. 콜백와 Node.js를에 개발

function(callback) { 
    request(base_url + 'mtfCompanies', function (error, response, html) { 
     if (!error && response.statusCode == 200) { 
      var $ = cheerio.load(html); 

      $('.blueRow.texttd.name a').each(function (i, element) { 
       var a = $(this); 

       company = {}; 
       company.name = a.text(); 
       company.link = a.attr('href'); 

       mutuals.companies.push(company); 
      }); 
      callback(null, 'one'); 
     } 
    }); 
}, 

제안 1

깊은 중첩 구조로 당신을 떠날 수 있습니다. if 문이 중첩되도록하지 마십시오. 더 깊은 둥지 대신 조기 반품을 사용하십시오. 예 : 그것은라는 이름의 함수를 사용하여 일을 단순화 할 수 있습니다 2

async를 사용

function(callback) { 
    request(base_url + 'mtfCompanies', function (error, response, html) { 
     if(error) return callback(error); 
     if(response.statusCode !== 200) return callback('status code not 200'); 
     var $ = cheerio.load(html); 

     $('.blueRow.texttd.name a').each(function (i, element) { 
      var a = $(this); 

      company = {}; 
      company.name = a.text(); 
      company.link = a.attr('href'); 

      mutuals.companies.push(company); 
     }); 
     callback(null, 'one'); 
    }); 
}, 

제안.예 :

var request = require('request'), 
    async = require('async'), 
    cheerio = require('cheerio'); 

var base_url = 'http://www.naftemporiki.gr/finance/'; 

var mutuals = {}; 
mutuals.date = new Date(); 
mutuals.companies = []; 

var company = {}; 

function getPage(callback) { 
    request(base_url + 'mtfCompanies', function (error, response, html) { 
     if(error) return callback(error); 
     if(response.statusCode !== 200) return callback('status code not 200'); 
     var $ = cheerio.load(html); 

     $('.blueRow.texttd.name a').each(function (i, element) { 
      var a = $(this); 

      company = {}; 
      company.name = a.text(); 
      company.link = a.attr('href'); 

      mutuals.companies.push(company); 
     }); 
     callback(null, 'one'); 
    }); 
} 

function printMutuals(callback) { 
    console.log(mutuals); 
    callback(null, 'two'); 
} 

async.series([ 
    getPage, 
    printMutuals 
]); 
+0

이는 node.js의 비동기 특성 때문입니까? 그렇다면 어떻게 해결할 수 있습니까? 프로그래밍 방식으로 "정확하다"고 느껴지기 때문에 루프 밖에서 출력 할 수 있기를 원합니다. – dsljanus

+1

비동기 코드의 흐름을 관리하는 가장 좋은 방법은 현재 'async' 모듈입니다. 그것은 동기식 코드보다 확실히 복잡하지만, 그에 대한 추가적인 힘이 있습니다. 예를 들어 node.js를 사용하면 여러 자원을 병렬로 요청하고 마지막 자원이 완료되면 응답으로 결합 할 수 있습니다. 동기 코드에서는 각 자원 요청을 직렬로 작성해야합니다. node.js의 다음 버전에는 비동기 코드가 훨씬 더 동기식으로 보이게하는 생성기라는 기능이 있지만, 여전히 두포에서 일어나는 일을 이해해야합니다. – Daniel

+0

제 목적으로 'async.series'를 사용하라고 제안합니까? – dsljanus

관련 문제