2016-10-12 13 views
2

私は、Webサイトのすべてのページを繰り返し処理して情報を抽出するスクレイパーを作成しました。たくさんのページがあります。このプログラムがノンストップで機能していれば、完了するまでに約1週間かかります。しかし、2〜3時間ごとにページから情報を抽出しようとするとハングするだけで、それは決して続かない。私はスクリプトを再起動する必要があるので、これはイライラしています。ここでNodeJSを使用して実行することの骨格は、次のとおりです。JavaScript関数を別のJavaScript関数から定期的に削除して再起動する方法

index = 0; 
finalIndex = 50000; 

function scrape(){ 
    if(index < finalIndex){ 
     //hit the website using nightmare, navigate to page, extract info, store as JSON 
     console.log("finished scraping page number: ", index); 
     index++; 
     scrape(); 
    } 
} 

scrape(); 

私は掻き取り機能を実行される、このファイルまたは別では、機能を持っているしたいのですが、その後、2時間ごとに機能を殺して、それを再起動しますそれが掻き取ろうとした最後のインデックスから。私はsetTimeoutを使って公式を考えようとしましたが、関数スタックを途中で止める方法がわかりません。また、スクレイプ機能がすでに停止している場合、再起動機能が失敗することも望ましくありません。

これを行うには、どのような方法が最適ですか?この問題に対するその他の解決策は歓迎ですが、JavaScriptの知識の観点からも、私はこれを将来行う方法を知りたいと思います。ここで

は、もう少し詳細に私の関数である。

function scrape() { 
console.log("initializing scrape from index: " + index); 
var nightmare = Nightmare(); 
if (index < indexEnd) { 

    nightmare 
    .goto(hidTestURL) //connect to the main site 
    .wait('input[name="propertySearchOptions:advanced"]') 
    .wait(4000) 
    .goto(pageURL) //navigate to the specific entry's info page 
    .wait('a[id="propertyHeading_searchResults"]') 
    .wait(2500) 
    .evaluate(function(){ 
     return document.querySelector('body').innerHTML; 
    }) 
    .then(function(html){ 
     return xP([html, {data: css.data}])() //scrape the data from the page 
    }) 
    .then(cleanDetails) 
    .then(writeResult) 
    .then(_ => { 
       nightmare.end(); 
       nightmare.proc.disconnect(); 
       nightmare.proc.kill(); 
       nightmare.ended = true; 
       nightmare = null; 
     }) 
    .then(function(){ 
      console.log("successful scrape for ", ids[index]); 
      ++index; 
      setTimeout(scrape(), interval); //start scraping the next entry after a specified delay (default 4 seconds) 
     }) 
    .catch(function(e){ 
     if (e.message === 'EmptyProperty'){ 
     console.log('EmptyProperty'); 
      ++index; 
      setTimeout (scrape, interval/2); 
     } 
     else { 
      return appendFileP(logFile, new Date().toString() + " unhandled error at " + street + index + ' ' + e + '\r\n', 'utf8') 
       .then(function(){ 
        if (numOfTries < 2){ 
         console.log("Looks like some other error, I'll retry: %j", e.message); 
         ++numOfTries;      
         setTimeout (scrape, interval * 5); 
         return nightmare.end(); 
        } 
        else { 
         console.log("Tried 3 times, moving on"); 
         ++index; 
         numOfTries = 0; 
         setTimeout (scrape, interval * 5); 
         return nightmare.end(); 
        } 
       }); 
     } 
    }) 

} 

そのコードが、私は含まれていませんが、それらの名前が明らかでなければならない、と私はその機能があるとは思わないヘルパー関数があります。問題の重要な部分。また、Nodeを使用してこれを実行していることを明確にしたいので、ブラウザで実行することはありません。

+0

を。 (私が間違っていると誰かに教えてください) 実行や読み込みに時間がかかりすぎると、ブラウザはプロセスを強制終了させることがあります。 EDITED しかしNodejsはJavascriptではありません。あなたはNode.jsのプロセスをkillすることができます –

+0

あなたのメソッドから離れすぎないようにしようとしないでください。おそらく、ここに記述されているようなものを試すことができます:http://stackoverflow.com/questions/672732/prevent-long-running-javascript- from-locking-up-browser –

+0

コードが何をハングアップさせるのかを見つけ出して修正します。それまでは、OSに付属のタスクスケジューラを使用して、2時間ごとに 'node'プロセスを強制終了して再起動することができます。 – Bergi

答えて

0

私はあなたの機能を簡単に停止できないと思いますが、コードの構造を少し変更することができます。あなたのコードがcall stackNodeに達し、そのために停止する可能性があります。

は、このようなループのためにあなたのコードを変換してみてください。

finalIndex = 50000; 
for (var index = 0; index < finalIndex; index++) { 
    console.log("finished scraping page number: ", index); 
    scrape(); 
} 
+0

これは同時に複数のスクレープコールを含むでしょうか?私は再帰を伴う約束チェーンを使用しました。その理由の1つは、Webサイトが一度に1回しか攻撃できないためです。そうしないと、システム管理者は自動的に自分のIPをブロックします。 (これは大きな問題であり、私が危険にさらしたくないもの) – Phylth

+0

Nodeの 'call stack'使用法をチェックするにはどうしたらいいですか? – Phylth

+0

ああ、あなたのコードがすでにそうしているので、それは問題ではありませんでした。本当に私は精度でチェックする方法がわかりませんが、ここでの問題は再帰関数を使用することです。コールスタックをどれだけ増やしても関数はおそらくそれを超えます。 –

1

JavaScriptがシングルスレッドであるあなたは、単に何も「外」があるとして、「外」から実行されている機能を「殺す」ことはできませんので(別のスレッドのように)。

JSで唯一のマルチタスクオプションは、呼び出されるたびに小さなチャンクを行うように関数を設計するときに、協調マルチタスクです。上記のこの掻き取り機能は、単一のスクラップアクションを行い

var index = 0; 
var finalIndex = 50000; 

var working = true; // if working == false then stop running. 

function scrape(){ 

    if(!working) 
     return; 

    if(index < finalIndex){ 
     // scrap code is here ... 
     console.log("finished scraping page number: ", index); 
     index++; 
     setTimeout(scrape); // schedule scrape for the next chunk (iteration) 
          // and return immediately 
    } 
} 

// reset working variable in 60 seconds 
setTimeout(function() { working = false; }, 60000); 

scrape(); // start iterations 

と次の反復の終了時 スケジュール自体を:ここ

は、チャンク関数の一例です。

working変数をfalseに設定するために、別のタイマーが使用されます。これは擦り傷に "ループ"を壊して停止することを知らせます。

+0

これは賢明な回避策ですが、タイムアウトが終了する前にコードがハングアップしていた場合は、正しく再起動しません。また、私は擦り傷の中で 'working = true'を実行する節を追加する必要があります。そうでなければ、再起動しません。停止するだけです。 – Phylth

3

これまで同様の問題に取り組んでいましたが、私が選んだ解決策は、各ページが一定時間内に終了することを保証することでした。あなたは約束の中で悪夢のコードを包んで、一定の時間内に終了するようにPromise.raceを使用することができます。その後、タイムアウトした場合は、v2.8.0に導入された.halt apiを使用して、メモリリークや放棄されたプロセスを防ぎます。

それはこのようなものになります。私はこれはJavascriptで行うことが可能であるとは思わない

Promise.race([ 
    doNightmareCodeAndReturnPromise(nightmareInstance), 
    new Promise((resolve, reject) => setTimeout(() => reject('timed out'), 5000)) 
]) 
.then(result => /* save result */) 
.catch(error => { 
    if (error === 'timed out') nightmareInstance.halt() 
}) 
関連する問題