2016-09-22 6 views
1

일부 데이터를 스크랩하기위한 작은 스크립트를 작성하려고합니다. 나는 자바 스크립트에서 몇 가지 기본 지식을 가지고 있지만 모든 비동기 콜백 또는 약속 물건들로 잃어 버렸습니다. 여기에 내가 지금 가지고있는 것입니다 :Node.js URL 배열에 루프가있는 웹 스크래핑

url = "http://Blablablabla.com"; 

var shares = function(req, res) { 
    request(url, function (error, response, body) { 
    if (!error) { 
    var $ = cheerio.load(body), 
     share = $(".theitemIwant").html(); 

    return res.send(url + ":" + share); 
    } else { 
    console.log("We've encountered an error: " + error); 
    } 
}) 

} 

그래서이 코드 조각으로 모든 것이 잘됩니다. 내가 뭘하고 싶은 것입니다 :

  1. 내가 이런 식으로 뭔가를 사용할 필요가 알고있는이 data = [{url: url1, shares: share},{url: url2, shares: share},etc...]

처럼, 다른 배열로 내 폐기 데이터를 저장 뭔가를 URL var urls = [url1,url2,url3,etc...]

  • 의 배열을 사용하여 data.push({ urls: url, shares: share})})

    그리고 두 번째 데이터 배열로 데이터를 푸시하기 위해 첫 번째 URL 배열을 반복해야한다는 것을 알고 있습니다.

    그러나 나는 request 메서드로 잃어 버렸고 내 상황에서 비동기 문제를 처리해야합니다.

    감사합니다.

    편집 # 1 :

    내가 약속을 사용하는이 시도 :

    var url = "www.blablabla.com" 
    var geturl = request(url, function (error, response, body) { 
        if (!error) { return $ = cheerio.load(body) } else 
        { console.log("We've encountered an error: " + error); } 
    }); 
    
    var shares = geturl.then(function() { 
        return $(".nb-shares").html(); 
    }) 
    

    만 가지고 다음과 같은 오류 geturl.then is not a function

  • +0

    ... – Nix

    +0

    시작 간단하고'request' 호출을 promisify : 여기 – Bergi

    +0

    @Bergi 내 게시물을 업데이트합니다. –

    답변

    2

    나는 그것을 찔러했다. 당신은 Q 라이브러리를 설치해야하고

    var Q = require('q'); 
    
    //... where ever your function is 
    //start with an array of string urls 
    var urls = [ "http://Blablablabla.com", '...', '...']; 
    
    //store results in this array in the form: 
    // { 
    //  url: url, 
    //  promise: <will be resolved when its done>, 
    //  share:'code that you wanted' 
    // } 
    var results = []; 
    
    //loop over each url and perform the request 
    urls.forEach(processUrl); 
    
    function processUrl(url) { 
        //we use deferred object so we can know when the request is done 
        var deferred = Q.defer(); 
    
        //create a new result object and add it to results 
        var result = { 
        url: url, 
        promise: deferred.promise 
        }; 
        results.push(result); 
    
    
        //perform the request 
        request(url, function (error, response, body) { 
         if (!error) { 
         var $ = cheerio.load(body), 
          share = $(".theitemIwant").html(); 
         //resolve the promise so we know this request is done. 
         // no one is using the resolve, but if they were they would get the result of share 
         deferred.resolve(share); 
         //set the value we extracted to the results object 
         result.share = share; 
         } else { 
    
         //request failed, reject the promise to abort the chain and fall into the "catch" block 
         deferred.reject(error) 
         console.log("We've encountered an error: " + error); 
         } 
        }); 
    } 
    
    //results.map, converts the "array" to just promises 
    //Q.all takes in an array of promises 
    //when they are all done it rull call your then/catch block. 
    Q.all(results.map(function(i){i.promise})) 
        .then(sendResponse) //when all promises are done it calls this 
        .catch(sendError); //if any promise fails it calls this 
    
    function sendError(error){ 
        res.status(500).json({failed: error}); 
    } 
    function sendResponse(data){ //data = response from every resolve call 
        //process results and convert to your response 
        return res.send(results); 
    } 
    
    +0

    감사합니다. 괜찮습니다. 잘 작동합니다. Q를 특별히 사용하는 이유는 무엇입니까? –

    +0

    나는 본래 약속에 익숙하지 않아서, 일반적으로'goto '를 나의 고토로 사용한다. 약속을 만들 수는 있지만 약속의 "배열"이 완료되었는지 쉽게 확인할 수 있습니다. – Nix

    +0

    코드의 각 부분에 주석을 달아달라고 요청하는 것은 너무 어렵습니까? 나는 약속에 대한 모든 생각을 가졌지 만, 나는 이것이 어떻게 작동 하는지를 정말로 이해할 수있는 힘든 시간을 보냈습니다. –

    2

    에 필요 난 당신이 async를 사용한다고 생각 :

    var async = require('async'); 
    
    var urls = ["http://example.com", "http://example.com", "http://example.com"]; 
    var data = []; 
    var calls = urls.map((url) => (cb) => { 
        request(url, (error, response, body) => { 
         if (error) { 
          console.error("We've encountered an error:", error); 
          return cb(); 
         } 
         var $ = cheerio.load(body), 
          share = $(".theitemIwant").html(); 
         data.push({ url, share }) 
        }) 
    }) 
    
    async.parallel(calls,() => { /* YOUR CODE HERE */ }) 
    

    당신은 약속과 동일한 기능을 수행 할 수 있지만, 그 이유가 표시되지 않습니다. 난 당신이 응답으로 반환하는 것을 이해 해달라고

    const requestPromise = require('request-promise'); 
    const Promise = require('bluebird'); 
    const cheerio = require('cheerio'); 
    
    const urls = ['http://google.be', 'http://biiinge.konbini.com/series/au-dela-des-murs-serie-herve-hadmar-marc-herpoux-critique/?src=konbini_home'] 
    
    Promise.map(urls, requestPromise) 
        .map((htmlOnePage, index) => { 
        const $ = cheerio.load(htmlOnePage); 
        const share = $('.nb-shares').html(); 
        let shareTuple = {}; 
        shareTuple[urls[index]] = share; 
        return shareTuple; 
        }) 
        .then(console.log) 
        .catch((e) => console.log('We encountered an error' + e)); 
    
    0

    내가 많이 좋아 또 다른 솔루션입니다.