2017-11-24 24 views
1

私はすべての教授のためにhttp://www.ratemyprofessors.com/を掻き回そうとしています。私のコードは次のエラーを取得するようだ:Cheerio web掻き取りエラー

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 
1: node::Abort() [node] 
2: 0x10d3f9c [node] 
3: v8::Utils::ReportApiFailure(char const*, char const*) [node] 
4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node] 
5: v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [node] 
6: v8::internal::Runtime_AllocateInTargetSpace(int, v8::internal::Object**, v8::internal::Isolate*) [node] 
7: 0x292aec062bf 
Aborted 

私はこのエラーを引き起こすことが何をしたか知らないが、それが原因で私のループのだろうか?私は1000万ページ以上をループする必要がありますが、なぜ10ループでこのエラーが出るのか分かりません。コードは次のとおりです。

var express = require('express'); 
var path = require('path'); 
var request = require('request'); 
var cheerio = require('cheerio'); 
var fs = require('fs'); 
var app = express(); 
var count = 1; 
var url; 

while(count != 10){ 
    url = "http://www.ratemyprofessors.com/ShowRatings.jsp?tid=" + count; 
    request(url, function(err, resp, body){ 
     var $ = cheerio.load(body); 
     if($('.error').text().substring(0, 14) == "Page Not Found"){ 
      console.log("hello"); 
      count++; 
      return; 
     }else{ 
     console.log($('.error').text().substring(0, 14)); 
     var pfname = $('.pfname'); 
     var plname = $('.plname'); 
     var professorName = pfname.text().replace(/\s/g, '') + " " +plname.text().replace(/\s/g, ''); 
     console.log(professorName); 
     console.log(url); 
     count++; 
     } 
     return; 
    }) 
} 

app.listen(3000, function(){ 
    console.log("server is now listening"); 
}) 
+0

「whacko」に切り替えてみてください。cheerioよりもメモリが優れています。 – pguardiario

答えて

0

おそらく10ループ以上の方法を実行しています。要求のコールバックでは、要求が増えただけです(要求が送信されてから数百ミリ秒後に発生する可能性があります)。その時、あなたのwhileループは可能な限り速く要求を送信しています。

これはおそらく、whileループの代わりに通常のfor-loopを使用した方が良いでしょう。

+0

どうやってそれをやりますか? forループは動作しますが、依然としてループが完了した後にリクエスト機能が実行されます。各反復ごとにリクエストを実行させるにはどうすればよいですか? –

0

URLの配列を作成し、その配列をCheerioで反復処理する必要があります。このコードでは、多くの改良を施すことができますが、開始する必要があります。最後のタイムアウトは、URLがポピュレートすることができるようにするためです。

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

var url; 
var urls = []; 

for (i = 1; i < 10; i++) { 
    url = 'http://www.ratemyprofessors.com/ShowRatings.jsp?tid=' + i; 
    urls.push(url); 
} 

function done() { 
    var arrayLength = urls.length; 
    var promiseArray = []; 
    for (var i = 0; i < arrayLength; i++) { 
     request(urls[i], function(err, resp, body) { 
      var $ = cheerio.load(body); 
      if (
       $('.error') 
        .text() 
        .substring(0, 14) == 'Page Not Found' 
      ) { 
       console.log('hello'); 
       return; 
      } else { 
       console.log(
        $('.error') 
         .text() 
         .substring(0, 14) 
       ); 
       var pfname = $('.pfname'); 
       var plname = $('.plname'); 
       var professorName = 
        pfname.text().replace(/\s/g, '') + 
        ' ' + 
        plname.text().replace(/\s/g, ''); 
       console.log(professorName); 
       console.log(url); 
      } 
      return; 
     }); 
    } 
} 

setTimeout(function() { 
    done(); 
}, 3000); 
console.log(urls); 
0

私はカウントが要求のためのコールバックまでインクリメントされていないためラファエルは、その中にあなたが道10個の以上のループをやっているが正しいと思います。あなたは、whileループの内側にシリアル非同期コードを実行することができますasync.whilstのようなものを、使用することによって、この問題を解決することができます。

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

let count = 1 

const test =() => count < 10 

const iteratee = callback => { 
    const url = 'http://www.ratemyprofessors.com/ShowRatings.jsp?tid=' + count 

    request(url, (error, response, body) => { 
    if (error) return callback(error) 
    // do other stuff here 
    count++ 
    callback() 
    }) 
} 

const done = error => { 
    // all done 
} 

async.whilst(test, iteratee, done) 

あなたが同時要求に作っ防止しているので、これは、とにかくおそらく、より安全で責任あります彼らのサーバー(同じ場所への1000万のHTTP要求を同時に放ったのであれば、それはいいとは思いません)。同時リクエストを作成する場合は、async.mapまたはasync.eachのような「パラレル」メソッドをbottleneckのレートリミッタと組み合わせて使用​​することを検討してください。