如何在继续之前等待在phantomjs中加载click()事件



Phantomjs有两个非常方便的回调onLoadStartedonLoadFinished,它们允许您在加载页面时暂停执行。但我一直在搜索,如果你click()一个提交按钮或超链接,我找不到等效的。类似的页面加载也会发生,但我想onLoadStarted不会被调用,因为没有发生显式的page.open()。我正试图找出一种干净的方法,在加载时暂停执行。

一个解决方案显然是嵌套的setTimeout,但我想避免这种情况,因为它很粗糙,依赖于反复试验,而不是可靠和更健壮的东西,比如针对某个东西进行测试或等待事件。

对于我错过的这种页面加载,是否有特定的回调?或者可能有某种通用代码模式可以处理这种事情?

编辑:

我还没想好如何让它停下来。以下是当我调用click()命令时不调用onLoadStarted()函数的代码:

var loadInProgress = false;
page.onLoadStarted = function() {
  loadInProgress = true;
  console.log("load started");
};
page.onLoadFinished = function() {
  loadInProgress = false;
  console.log("load finished");
};
page.open(loginPage.url, function (status) {
    if (status !== 'success') {
        console.log('Unable to access network');
        fs.write(filePath + errorState, 1, 'w');
        phantom.exit();
    } else {
        page.evaluate(function (loginPage, credentials) {
            console.log('inside loginPage evaluate function...n')
            document.querySelector('input[id=' + loginPage.userId + ']').value = credentials.username;
            document.querySelector('input[id=' + loginPage.passId + ']').value = credentials.password;      
            document.querySelector('input[id=' + loginPage.submitId + ']').click();
            //var aTags = document.getElementsByTagName('a')
            //aTags[1].click();
        }, loginPage, credentials);
        page.render(renderPath + 'postLogin.png');
        console.log('rendered post-login');

我仔细检查了身份证是否正确。page.render()将显示信息已提交,但前提是我将其放入setTimeout()中,否则它会立即呈现,并且我只看到在页面重定向之前输入的凭据。也许我错过了什么?

我认为onLoadStartedonLoadFinished函数就是您所需要的一切。以以下脚本为例:

var page = require('webpage').create();
page.onResourceReceived = function(response) {
    if (response.stage !== "end") return;
    console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + response.url);
};
page.onResourceRequested = function(requestData, networkRequest) {
    console.log('Request (#' + requestData.id + '): ' + requestData.url);
};
page.onUrlChanged = function(targetUrl) {
    console.log('New URL: ' + targetUrl);
};
page.onLoadFinished = function(status) {
    console.log('Load Finished: ' + status);
};
page.onLoadStarted = function() {
    console.log('Load Started');
};
page.onNavigationRequested = function(url, type, willNavigate, main) {
    console.log('Trying to navigate to: ' + url);
};
page.open("http://example.com", function(status){
    page.evaluate(function(){
        // click
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        document.querySelector("a").dispatchEvent(e);
    });
    setTimeout(function(){
        phantom.exit();
    }, 10000);
});

它打印

正在尝试导航到:http://example.com/请求(#1):http://example.com/加载已启动新URL:http://example.com/响应(#1,阶段"结束"):http://example.com/加载完成:成功正在尝试导航到:http://www.iana.org/domains/example请求(#2):http://www.iana.org/domains/example加载已启动正在尝试导航到:http://www.iana.org/domains/reserved请求(#3):http://www.iana.org/domains/reserved响应(#2,阶段"结束"):http://www.iana.org/domains/example新URL:http://www.iana.org/domains/reserved请求(#4):http://www.iana.org/_css/2013.1/screen.css请求(#5):http://www.iana.org/_js/2013.1/jquery.js请求(#6):http://www.iana.org/_js/2013.1/iana.js响应(#3,阶段"结束"):http://www.iana.org/domains/reserved响应(#6,阶段"结束"):http://www.iana.org/_js/2013.1/iana.js响应(#4,阶段"结束"):http://www.iana.org/_css/2013.1/screen.css响应(#5,阶段"结束"):http://www.iana.org/_js/2013.1/jquery.js请求(#7):http://www.iana.org/_img/2013.1/iana-logo-header.svg请求(#8):http://www.iana.org/_img/2013.1/icann-logo.svg响应(#8,阶段"结束"):http://www.iana.org/_img/2013.1/icann-logo.svg响应(#7,阶段"结束"):http://www.iana.org/_img/2013.1/iana-logo-header.svg请求(#9):http://www.iana.org/_css/2013.1/print.css响应(#9,阶段"结束"):http://www.iana.org/_css/2013.1/print.css加载完成:成功

它显示,单击链接会发出一次LoadStarted事件和两次NavigationRequested事件,因为存在重定向。诀窍是在执行操作之前添加事件处理程序:

var page = require('webpage').create();
page.open("http://example.com", function(status){
    page.onLoadFinished = function(status) {
        console.log('Load Finished: ' + status);
        page.render("test37_next_page.png");
        phantom.exit();
    };
    page.onLoadStarted = function() {
        console.log('Load Started');
    };
    page.evaluate(function(){
        var e = document.createEvent('MouseEvents');
        e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        document.querySelector("a").dispatchEvent(e);
    });
});

如果你需要做这些事情,也许是时候尝试其他东西了,比如CasperJS。它运行在PhantomJS之上,但有一个更好的API来导航网页。

使用高级包装器nightmarejs。你可以在那里轻松地click,然后等待。

以下是代码(示例部分):

var Nightmare = require('nightmare');
new Nightmare()
  .goto('http://yahoo.com')
    .type('input[title="Search"]', 'github nightmare')
    .click('.searchsubmit')
    .run(function (err, nightmare) {
      if (err) return console.log(err);
      console.log('Done!');
    });

更多示例和API使用可以在github 上找到

以下是基于其他一些答案的代码。在我的例子中,我不需要专门评估任何其他javascript。我只需要等待页面加载完成。

var system = require('system');
if (system.args.length === 1) {
    console.log('Try to pass some arguments when invoking this script!');
}
else {
    var page = require('webpage').create();
    var address = system.args[1];
    page.open(address, function(status){
        page.onLoadFinished = function(status) {
            console.log(page.content);
            phantom.exit();
        };    
    });     
}

将以上内容保存在一个名为"scrape.js"的文件中,并按以下方式调用:

phantomjs --ssl-protocol=any --ignore-ssl-errors=true scrape.js https://www.example.com

添加SSL相关参数是为了避免我在某些HTTPS站点上遇到的其他问题(与证书加载问题有关)。

希望这能帮助到别人!