2013-05-29 9 views
24

ユーザーは、このリンクをクリックする方法:遅い関数が実行を終了し、前phantomjsの要素の可視性を待つ

page.evaluate(
    function() { $("#panel").click(); } 
); 
console.log('SUCCESS'); 
phantom.exit(); 

ファントム出る:

<span onclick="slow_function_that_fills_the_panel(); $('#panel').show();"> 

今、私はphantomjsでクリックをシミュレートしていますがDIVが表示されます。待機を実装するにはどうすればよいですか?

+0

愚か溶液はのsetTimeout() – igor

答えて

7

このシナリオの私のアプローチは、「何か」が成立するまで待つことです。 waitfor.jsを試してみることを強くお勧めします。

demo.html

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script> 
    <title>Test</title> 
</head> 
<body id="body"> 

    <div id="thediv">Hello World !</div> 

    <script type="text/javascript"> 
     $('#thediv').hide(); 
     setTimeout(function() { 
      $('#thediv').show(); 
     }, 3000); 

    </script> 
</body> 
</html> 

demoscript.js

var page = require('webpage').create(); 
var system = require('system'); 

function waitFor(testFx, onReady, timeOutMillis) { 
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 5000, //< Default Max Timout is 5s 
     start = new Date().getTime(), 
     condition = false, 
     interval = setInterval(function() { 
      if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) { 
       // If not time-out yet and condition not yet fulfilled 
       condition = (typeof (testFx) === "string" ? eval(testFx) : testFx()); //< defensive code 
      } else { 
       if (!condition) { 
        // If condition still not fulfilled (timeout but condition is 'false') 
        //console.log("'waitFor()' timeout"); 
        typeof (onReady) === "string" ? eval(onReady) : onReady(); 
        clearInterval(interval); 
        //phantom.exit(1); 
       } else { 
        // Condition fulfilled (timeout and/or condition is 'true') 
        console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms."); 
        typeof (onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled 
        clearInterval(interval); //< Stop this interval 
       } 
      } 
     }, 500); //< repeat check every 500ms 
}; 

if (system.args.length != 1) { 
    console.log('invalid call'); 
    phantom.exit(1); 
} else { 
    //adapt the url to your context 
    page.open('http://localhost:40772/demo.html', function (status) { 
     if (status !== 'success') { 
      console.log('Unable to load the address!'); 
      phantom.exit(); 
     } else { 
      waitFor(
       function() { 
        return page.evaluate(function() { 
         return $('#thediv').is(':visible'); 
        }); 
       }, 
       function() { 
        page.render('page.png'); 
        phantom.exit(); 
       }, 5000); 
     } 
    }); 
} 

このスクリプトはDIVが表示されているかどうかをチェックする$('#thediv').is(':visible')(古典的なjQueryのコード)毎に500ミリ秒を評価します。

+0

恐ろしい溶液です。私は 'Promise'パターンのために' phantom'ノードにこれをどのように適用するのかよく分かりません@see https://github.com/amir20/phantomjs-node/issues/431 – loretoparisi

22

相続人Cyber​​maxsの答えのスピン:使用の

function waitFor ($config) { 
    $config._start = $config._start || new Date(); 

    if ($config.timeout && new Date - $config._start > $config.timeout) { 
     if ($config.error) $config.error(); 
     if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); 
     return; 
    } 

    if ($config.check()) { 
     if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); 
     return $config.success(); 
    } 

    setTimeout(waitFor, $config.interval || 0, $config); 
} 

例:

waitFor({ 
    debug: true, // optional 
    interval: 0, // optional 
    timeout: 1000, // optional 
    check: function() { 
     return page.evaluate(function() { 
      return $('#thediv').is(':visible'); 
     }); 
    }, 
    success: function() { 
     // we have what we want 
    }, 
    error: function() {} // optional 
}); 

あなたが設定変数を使用するとき、それは少し簡単です。

+0

THANKYOU!私はフォームが提出されているかどうかを確かめるために2日かけて他の方法を試していました(盲目的に希望の 'setTimeout'ではなく)。これが私のために完璧に機能した唯一のものです。 +1 – indextwo

14

PhantomJS同期方法でそれを使ってあなたを停止することは何もありませんが(あなたの結果は準備ができている前に、スクリプトが終了する)あなたは上記の記述1

のような問題を引き起こして、デフォルトで非同期に実行されます。

whileループでphantom.page.sendEvent('mousemove')をちょうど使用してください。これにより、Webkitエンジンがページをロードしたり、必要なブラウザーイベントを処理したりするまで、イベントポンプをループし続けます。

var page = require('webpage').create(); 

// Step 1: View item 
page.open('http://localhost/item3324.php'); 
do { phantom.page.sendEvent('mousemove'); } while (page.loading); 
page.render('step1-viewitem.png'); 

// Step 2: Add to cart 
page.evaluate(function() {$('#add-to-cart').click(); }); 
do { phantom.page.sendEvent('mousemove'); } while (page.loading); 
page.render('step2-viewcart.png'); 

// Step 3: Confirm contents 
page.evaluate(function() {$('#confirm-cart').click(); }); 
do { phantom.page.sendEvent('mousemove'); } while (page.loading); 
page.render('step3-confirm.png'); 

page.loadingはまた、例えば、他のブール条件であることに注意してください:

do { phantom.page.sendEvent('mousemove'); } 
while (page.evaluate(function() {return $("#panel").is(":visible");})); 

呼び出しをエミュレートしようとしているtriflejs.orgプロジェクト(ファントムのInternet Explorerのバージョン)に取り組んでいる間、私はこのアプローチを発見PhantomJS環境内のtrifle.wait(ms)に転送します。 page.evaluate内部

+0

'phantom.page.sendEvent( 'mousemove')'はモバイルページで動作しますか? –

+0

@FengYu確かに。 'mousemove'は使うべき正しいイベントです。 Phantom(デスクトップブラウザのような)はモバイルページを知らない。知っているのは、Webページを開いてレンダリングすることだけです。 –

+0

whileループで 'page.sendEvent( 'mousemove')'を削除できますか? –

0

()、出来具合をテストするself.loadingプロパティを使用....

var fs = require('fs'); 
path = '/path/to/file.html'; 
address = 'http://google.com';  

page.open(address, function (status) { 
    if (status !== 'success') { 
     console.log('Unable to access page'); 
    } else { 
     var p = page.evaluate(function() { 
      if(!self.loading){ // ah, such beauty 
       return document.documentElement.outerHTML; 
      } 
     }); 
    fs.write(path, p, 'w'); 
    } 
    phantom.exit(); 
});  
関連する問題