2014-09-19 44 views
0

我打算使用JQuery通過PhantomJS填寫Form如何觸發Ajax請求填寫表單並等待DOM更改?

我已經爲這樣做,下面的腳本:

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

page.open('http://demo.opencart.com/index.php?route=account/register', function() { 
    fillTheForm(); 
    phantom.exit(); 
}); 

function fillTheForm() { 

    page.evaluate(function() { 

     var selectTags = new Array(); 
     selectTags = document.getElementsByTagName('select'); 
     $(selectTags[0]).val("38"); 
     $(selectTags[0]).trigger('change'); 

     $(selectTags[1]).val('610'); 
    });   
    page.render('form.png'); 
}; 

運行此腳本後,我得到了以下控制檯內部消息!

警報,JavaScript錯誤

而且,畫面我有,試圖填寫表格出來後,告訴我,第二個選擇框中現有值尚未然後PhantomJS改變無法將值分配給第二個字段。

有人可以幫我解決這個問題嗎?我如何使用JQuery和PhantomJS填寫這兩個字段?

+0

我訪問的URL,我改變了第一選擇,以「加拿大」的值作爲你的價值「38」對應。大約需要3或4秒才能加載狀態選擇框。我認爲你的錯誤發生是因爲你的jQuery代碼試圖在加載完成之前設置字段值的方式。 – jwatts1980 2014-09-19 02:27:11

+0

如何在更改第一個值後等待?我要填寫所有現有的字段,然後點擊提交按鈕。然後,我不能在'window.setTimeout'中放置($(selectTags [1])。val('610'))命令。你有什麼建議嗎? – user3321210 2014-09-19 02:34:34

+0

另外,我剛剛在這裏測試了'window.setTimeout',我得到了同樣的錯誤! – user3321210 2014-09-19 02:37:27

回答

0

這是鏈接選擇問題。第二個依賴於第一個,並通過AJAX進行填充。這意味着它是異步的。您必須等待,然後才能設置第二個值。在PhantomJS中,這也是有問題的,因爲您有兩個上下文(頁面上下文和幻像上下文),它們已經被「同步」。

例如,你可以使用

function fillTheForm() { 
    page.evaluate(function() { 
     var selectTags = document.getElementsByTagName('select'); 
     $(selectTags[0]).val("38"); 
     $(selectTags[0]).trigger('change'); 
    }); 
    setTimeout(function(){ 
     page.evaluate(function() { 
      var selectTags = document.getElementsByTagName('select'); 
      $(selectTags[1]).val('610'); 
     }); 
     page.render('form.png'); 
     phantom.exit(); // this has to be inside, because everything is asynchronous now 
    }, 3000); // assuming 3 seconds are enough time for the request 
}; 

更好,更可靠的方法是使用waitFor from the examples,因爲它只要數據可用完成。在這裏我有一些指標的第二個選擇是重新加載時:

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

page.open('http://demo.opencart.com/index.php?route=account/register', function() { 
    fillTheForm(function(){ 
     page.render('form.png'); 
     phantom.exit(); 
    }); 
}); 

function fillTheForm(done) { 
    page.evaluate(function() { 
     var selectTags = document.getElementsByTagName('select'); 

     // custom indicators, perhaps something more elaborate is needed for general selects 
     // in this case it is ok 
     window._chainedSelectChildrenLength = selectTags[1].children.length; 
     window._chainedSelectFirstChildText = selectTags[1].children[0].innerText; 

     $(selectTags[0]).val("38"); 
     $(selectTags[0]).trigger('change'); 
    }); 
    waitFor(function testFx(){ 
     return page.evaluate(function() { 
      var selectTags = document.getElementsByTagName('select'); 
      // use indicators 
      return window._chainedSelectChildrenLength !== selectTags[1].children.length || 
       window._chainedSelectFirstChildText !== selectTags[1].children[0].innerText; 
     }); 
    }, function onReady(){ 
     page.evaluate(function(){ 
      // continue 
      var selectTags = document.getElementsByTagName('select'); 
      $(selectTags[1]).val('610'); 
     }); 
     done(); 
    }, 5000); // 3 seconds is the default 
}; 

function waitFor(testFx, onReady, timeOutMillis) { 
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s 
     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"); 
        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 
       } 
      } 
     }, 250); //< repeat check every 250ms 
}; 
+0

只是一個問題!如果存在一系列選擇,那麼這兩條第一線如何起作用?我沒有那部分!有沒有什麼辦法可以檢查現有的'Select'標籤是否會觸發Ajax調用?我的意思是在給每個人分配價值之前? – user3321210 2014-09-19 14:10:38

+0

在編寫腳本之前,您需要在瀏覽器中打開開發人員工具並轉到網絡選項卡。然後,您執行一些操作並觀察網絡選項卡。在這種情況下,我甚至沒有這樣做,因爲它更有可能異步加載區域,而不是在頁面加載開始時爲所有國家加載所有區域。對已知行爲進行編程要比試圖捕捉未知行爲要容易得多。爲了使它更健壯,你可以使用[page.onResourceReceived](http://phantomjs.org/api/webpage/handler/on-resource-received.html) – 2014-09-19 14:26:32

+0

感謝您的幫助@Artjom B.我終於用你的建議解決了我的問題。 – user3321210 2014-09-21 23:05:42