使用casperjs时如何等待页面加载?

时间:2014-03-04 05:22:49

标签: javascript phantomjs casperjs

我正在尝试抓取一个网页,其中包含许多下拉列表,并且表单中的值是相互依赖的。在许多方面,我需要代码等待页面刷新完成。例如,从列表中选择一个选项后,代码应该等到根据此选择填充下一个列表。如果有人可以指点,那将是非常有帮助的,因为奇怪的是我的代码只有在我提供了如此多的不必要的日志记录语句之后才能工作,这反过来又造成了一些延迟。任何改进代码的建议都会非常有用。

var casper = require('casper').create({
     verbose: true,
     logLevel: 'debug',
     userAgent: 'Mozilla/5.0  poi poi poi (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22',
     pageSettings: {}
 });

 casper.start('http://www.abc.com', function () {
     console.log("casper started");
     this.fill('form[action="http://www.abc.com/forum/member.php"]', {
         quick_username: "qwe",
         quick_password: "qwe"
     }, true);
     this.capture('screen.png');
 });
 casper.thenOpen("http://www.abc.com/search/index.php").then(function () {
     this.click('input[type="checkbox"][name="firstparam"]');
     this.click('a#poi');

     casper.evaluate(function () {
         document.getElementsByName("status")[0].value = 1;
         document.getElementsByName("state")[0].value = 1078;
         changeState(); //This function is associated with the dropdown ie state 
and the page reloads at this point. Only after complete refresh the code shoud execute! How can this be achieved?
         return true;
     });
     this.echo('Inside the first thenOpen' + this.evaluate(function () {
         return document.search.action;
     }));
 });
 casper.then(function () {
     this.capture("poi.png");
     console.log('just before injecting jquery');
     casper.page.injectJs('./jquery.js');
     this.click('input[type="checkbox"][name="or"]');
     this.evaluate(function () {
         $('.boxline .filelist input:checkbox[value=18127]').attr("checked", true);
     });
     this.echo('Just before pressing the add college button' + this.evaluate(function () {
         return document.search.action;
     }));
     this.capture('collegeticked.png');
     if (this.exists('input[type="button"][name="niv"]')) {
         this.echo('button is there');
     } else {
         this.echo('button is not there');
     }
     this.echo("Going to print return value");
     this.click('input[type="button"][name="poi"]'); // This click again causes a page refresh. Code should wait at this point for completion.
     this.echo('Immediately after pressing the add college btn getPresentState()' + this.evaluate(function () {
         return getPresentState();
     }));
     this.echo('Immediately after pressing add colleg button' + this.evaluate(function () {
         return document.search.action;
     }));
     this.capture('iu.png');
 });

 casper.then(function () {
     console.log('just before form submit');
     this.click('form[name="search"] input[type="submit"]'); //Again page refresh. Wait.
     this.echo('Immediately after search btn getPresentState()' + this.evaluate(function () {
         return getPresentState();
     }));
     this.echo('Immediately after search button-action' + this.evaluate(function () {
         return document.search.action;
     }));
     this.capture("mnf.png");
 });

 casper.then(function () {
     casper.page.injectJs('./jquery.js');
     this.capture("resultspage.png");

     this.echo('Page title is: ' + this.evaluate(function () {
         return document.title;
     }), 'INFO');
     var a = casper.evaluate(function () {
           return $('tbody tr td.tdbottom:contains("tye") ').siblings().filter($('td>a').parent());
     });
     console.log("ARBABU before" + a.length);
 });

 casper.run();

7 个答案:

答案 0 :(得分:11)

我一直在使用waitForSelector'解决方法' Arun在这里提到: https://stackoverflow.com/a/22217657/1842033

这是我发现的最佳解决方案;缺点'因为它是你需要知道你期望加载的元素。我说缺点,我个人认为我没有遇到过这样的情况:我没有一些的反馈说我无论等待的是什么发生

this.waitForSelector("{myElement}",
    function pass () {
        test.pass("Found {myElement}");
    },
    function fail () {
        test.fail("Did not load element {myElement}");
    },
    20000 // timeout limit in milliseconds
);

虽然我猜你可以使用waitForResource()或类似的东西,如果你没有视觉反馈。

答案 1 :(得分:7)

我在解决此问题时采取的措施是,如果没有特定的目标并在重新加载的页面中等待,则使用以下内容:

var classname = 'reload-' + (new Date().getTime()),
    callback = function(){},
    timeout = function(){};

/// It happens when they change something...
casper.evaluate(function(classname){
  document.body.className += ' ' + classname;
}, classname);

casper.thenClick('#submit'); /// <-- will trigger a reload of the page
casper.waitWhileSelector('body.' + classname, callback, timeout);

这样我就不必依赖下一页中的特定预期元素,我基本上完成了相反的操作。我已经创建了一个特定的选择器来注意,一旦选择器无法匹配,执行就会继续。

根据我的意图和目的,知道页面已经开始重新加载就足够了,我没有必要等到下一页完全重新加载。这样我就可以对重新加载之前和之后可能存在的元素触发某些waitForSelector调用。等到临时课程被删除后让我知道之前存在的任何东西都已被销毁,所以不必担心在重新加载之前选择元素。

答案 2 :(得分:2)

似乎没有真正的解决方案。 http://docs.casperjs.org/en/latest/modules/casper.html#waitforselector是一种可用的解决方法,可能无法始终有效。

答案 3 :(得分:1)

我和你一样经历同样的事情。脚本以这种方式在用户视角下从未顺利过。它在不知名的地方崩溃,非常不可靠。我正在从salesforce进行搜索,也需要登录。

您需要尽可能减少步伐。以cron工作方式编写脚本。除非您正在进行UI测试,否则不要进行表单填写/按钮单击。我建议你把这个过程分成两部分

// this part do search and find out the exact url of your screen capture.
// save it in a db/csv file
1 - start by POST to http://www.abc.com/forum/member.php with username password in body.
2 - POST/GET to http://www.abc.com/search/index.php with your search criteria, you look at what the website require. if they do POST, then POST.

// second part read your input
1 - login same as first part.
2 - casper forEach your input save your capture. (save the capture result in db/csv)

我的脚本现在是纯粹的phantomjs,casper脚本无缘无故地继续崩溃。甚至幻影都不可靠。我保存每次成功搜索/下载的结果/状态,只要有错误我退出脚本,如果不是其他结果是不可预测的(好的结果导致chrome在phantomjs中变坏)。

答案 4 :(得分:1)

我在搜索问题的解决方案时发现了这个问题,其中click()或fill()操作在子iframe中重新加载完全相同的数据。以下是我对Pebbl答案的改进:

casper.clickAndUnload = function (click_selector, unload_selector, callback, timeout) {
    var classname = 'reload-' + (new Date().getTime());
    this.evaluate(function (unload_selector, classname) {
        $(unload_selector).addClass(classname);
    }, unload_selector, classname);

    this.thenClick(click_selector);
    this.waitWhileSelector(unload_selector + '.' + classname, callback, timeout);
};

casper.fillAndUnload = function (form_selector, data, unload_selector, callback, timeout) {
    var classname = 'reload-' + (new Date().getTime());
    this.evaluate(function (unload_selector, classname) {
        $(unload_selector).addClass(classname);
    }, unload_selector, classname);
    this.fill(form_selector, data, true);
    this.waitWhileSelector(unload_selector + '.' + classname, callback, timeout);
};

此解决方案假定该页面使用jQuery。对于没有的页面,修改它应该不难。 unload_selector是在点击或表单提交后预计会重新加载的元素。

答案 5 :(得分:0)

由于Casperjs是为开发人员编写的,因此预计会知道页面加载应该处于什么状态,以及应该有哪些元素可用于定义页面加载状态。

一种选择是检查是否存在例如在页面末尾加载的javascript资源。

在运行任何类型的测试时,结果必须每次都可重现,因此幂等性是必不可少的。为此,测试人员必须能够控制环境,以实现这一目标。

答案 6 :(得分:0)

只需评估document.readyStateWHEREcomplete。然后它就被加载了。

这是一个interactive的实现,但也许可以使用interval ...

while