2016-03-23 22 views
-1

私は特定のウェブサイトのデータスクレーパーを構築しています。私は10秒ごとに要求を出したいので、私は手動で入力したURLの配列からパラメータとしてurlを受け取るsetTimeoutループとして設定しました。コールバックでは、このurlを要求して応答を解析し、最終的にcsvに変換できるように構造化された新しい配列にデータをプッシュします。私は私の依存関係と一緒に下の完全なコードを貼り付けます。私の非同期コードをsetTimeoutと同期させる。私は約束が必要ですか?

これらの要求の約1/5が未定義として返されるという問題があります。私は、タイムアウト機能がこれを処理し、プログラムが同期して動作すると思っていました。私は明らかに間違っていました。これを調べると、多くの人が非同期リクエストを注文するために約束の依存関係を使用することが分かりました。ここで私の質問:それは必要ですか?または、コールバック/ setTimeoutを調整して、別の依存関係を追加せずに動作させることはできますか?

編集私が、私はこのアプリがやりたい、まさにここにコピーしています明確ではありませんでしたので: 私はプログラムは、要求を取るJSON文字列を返し、データのためのそのJSON文字列を解析したいです、そのデータを配列に追加し、その配列をcsvとしてエクスポートします。私はこの機能をループして長いURLのリストに対して行うことができますが、一度に1つのリクエストを行い、最初のレスポンスから必要なデータが収集されるまで次のリクエストを繰り返すのを待ちます。 10秒ごとにリクエストを送信したいだけです。

は、ここに私のコードです:

var express = require('express'); 
var fs = require('fs'); 
var request = require('request'); 
var cheerio = require('cheerio'); 
var app  = express(); 

var arr = []; 

var url = //A bunch of urls that I'm leaving out to conserve space 


i = 0; 
function timeout() { 
    setTimeout(function() { 
     request(url[i], function(error, response, html){  
      if(error){ 
       console.log(error); 
      } else { 

       var $ = cheerio.load(html); 

       var company, industry, size, website, type; 

       var inArr = []; 
       $('div .image-wrapper img').filter(function(){ 
        var data = $(this); 
        company = data.attr('alt'); 
        inArr.push("\"" + company + "\""); 
       }) 

       $('.industry p').filter(function(){ 
        var data = $(this);    
        industry = data.text(); 
        inArr.push("\"" + industry + "\""); 
       }) 

       $('.company-size p').filter(function(){ 
        var data = $(this);     
        size = data.text(); 
        inArr.push("\"" + size + "\""); 
       }) 

       $('.website p a').filter(function(){ 
        var data = $(this);     
        website = data.text(); 
        inArr.push("\"" + website + "\""); 
       }) 

       $('.type p').filter(function(){ 
        var data = $(this);     
        type = data.text(); 
        inArr.push("\"" + type + "\""); 
       }) 


       arr.push(inArr); 
       console.log("I just sourced data for " + company); 

       if (i === url.length - 1) { 
        clearTimeout(timeout); 
        console.log("All done!") 
        var csvContent; 
        arr.forEach(function(infoArray, index){ 

         dataString = infoArray.join(","); 
         csvContent += index < arr.length ? dataString+ "\n" : dataString; 

        }); 
        fs.writeFile('output.csv', csvContent, function(err){ 
         console.log('File successfully written! - Check your project directory for the output.csv file'); 
        }); 

       } else { 
        i++; 
        timeout();     
       } 
      } 

     }); 
    }, 10000); 

}; 


timeout(); 
+0

_ "これらの要求のうち約5分の1が未定義として返されるという問題があります。" _ clearTimeout(timeout);の期待される結果は何ですか? 'timeout'関数内の' setTimeout'がintially宣言されていないか、後で 'timeout'変数として設定されていますか? 'timeout'は、質問 – guest271314

+0

で' js'の関数としてのみ定義されています。本当の質問は何ですか?あなたは 'request()'操作を何度も実行しようとしていますか?もしそうなら、 'setTimeout()'でどのくらい時間がかかるかを推測するのは悪い設計です。操作を順序付ける実際のコードを記述する必要があります。しかし、最初に、あなたの 'setTimeout()'の問題ではなく、本当の問題がここにあることを明確にしてください。解決策の試みだけでなく、実際の問題について説明すると、問題解決のための最善の解決策を見つけることができます。 – jfriend00

+0

'clearTimeout(timeout);'は何故か何の意味もありません。 'timeout'はあなたのコード内の関数であり、タイマーIDではありません。 'clearTimeout()'は 'setTimeout()'への呼び出しからの戻り値で動作します。 'var timer = setTimeout(f、t);と同じです。 clearTimeout(タイマー); '。さらに、 'setTimeout()'の結果を既に実行しているときに 'clearTimeout()'を使うロジックは意味がありません。タイマーは既に起動しています。 – jfriend00

答えて

1

を参照してください。

var request = require('request'); 

function requestNext(url, callback, delay, nextCallback) { 
    var start = Date.now(); 
    request(url, function(error, response, html) { 
     callback(error, response, html); 
     var elapsed = Date.now() - start; 
     var wait = Math.max(delay - elapsed, 0); 
     // schedule next call to request() 
     setTimeout(nextCallback, wait); 
    }); 
} 
:EREは、あなたが次々リクエストを送信したいのですが、ノー早くも10秒間隔で、その後、あなたはそれが次の呼び出しのための時間だときに伝える少しラッパー関数を作ることによって、このようなことを行うことができるということです

次に、遅延時間を指定するrequestNext()と、次の呼び出しをいつ行うかを示す2番目のコールバックを呼び出すことができます。、そして、

function getURLs(urls, delay, processCallback, doneCallback) { 
    var index = 0; 
    var data = []; 

    function next() { 
     if (index < urls.length) { 
      requestNext(urls[index++], function(err, response, html) { 
       // need to decide what you want do for error handling here 
       // continue? stop further processing? 
       data.push(processCallback(err, response, html)); 
      }, delay, next); 
     } else { 
      doneCallback(null, data); 
     } 
    } 
    next(); 
} 

getURLs(urlArray, 10000, processResult, function(err, dataArray) { 
    if (!err) { 
     // results are in dataArray 
    } 
}); 

次のようになりますprocessResultという名前の関数でURLを処理するために、あなたのロジックを置く:

その後、あなたは特に状況で、あなたはこのようなリピート機能であることを使用することができ

function processResult(err, response, html) { 
    // your code to process a page here 
    // return the final result as a return value and it will be collected for you 
} 
+0

私はあなたの忍耐とあなたの助けに感謝します。ちょっとした手品とパーソナライゼーションの後、この解決策が私のために働いた。私はあなたの答えをupvoteだろうが、この質問を投稿する行為は、人々に私をdownvoteさせた。 –

+0

率直に言って、これは自分自身と私が知っている多くの人がコードオーバーフローを避けるためにコードを学習していることを知っています。私は私の質問を調査し、何が間違っていたのか、実際にそれに費やされた時間を把握しようとしました。あなたが私に明確にするように頼んだとき、私は明確にしました。これは、人々がお互いを助け合う場所であると考えられています。拒否したり排除したりすることはありません。しかし、それは私がクリックするすべての質問で見るものの大部分です。再び、私はあなたの助けに本当に感謝しています。あなたのコードと説明はどちらも完璧でした。しかし、次回に質問がありましたら、おそらく別の場所に行くでしょう。 –

+0

@AaronHill - あなたはその答えの左側にある緑のチェックマークをチェックすることでこの回答を受け入れることができます。私はあなたにdownvoteをしませんでしたが、あなたが完全にはっきりしていない場合、あなたの質問を編集してすぐに質問に答えることができない場合、あなたは質問のdownvotesを得ることができます。私が思い出したように、あなたの質問を明確にするまでにはしばらくかかりました。ここのコミュニティはガイドラインに合致しない質問は許容しません。ちょっとした練習では、最初に明確な質問を書いたり、不明な場合はすぐに反応することができます。 – jfriend00

0

setTimeoutを参照する変数を宣言するjsを調整してみてください。 timeoutは関数であり、timeout()と呼ばれるsetTimeoutへの参照ではありませんが、にはtimeoutがパラメータとして呼び出されます。 tの下のjsには、timeoutの外の変数として宣言されており、setTimeoutの参照に設定され、timeout()コール内に設定されています。

は、本当の問題、H場合WindowTimers.setTimeout()

構文

var timeoutID = window.setTimeout(func, [delay, param1, param2, ...]); 
var timeoutID = window.setTimeout(code, [delay]); 

var arr = []; 
 

 
var url = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 
 

 
var i = 0; 
 

 
var t = null; 
 

 
function timeout() { 
 
    t = setTimeout(function() { 
 
    (function() { 
 
     var inArr = []; 
 
     inArr.push(i) 
 
     arr.push(inArr); 
 
     console.log("I just sourced data for " + i, t); 
 
     if (i === url.length - 1) { 
 
      clearTimeout(t); 
 
      console.log("All done!", i, url.length - 1, arr) 
 
     } else { 
 
      i++; 
 
      timeout(); 
 
     } 
 
    }()); 
 
    }, 1000); // reduced duration to `1000` for stacksnippets 
 
}; 
 

 
timeout();

関連する問題