Подтвердить что ты не робот

Как дождаться загрузки страницы при использовании 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();
4b9b3361

Ответ 1

Я использовал обходное решение waitForSelector, упомянутое здесь Аруном: fooobar.com/questions/238830/...

Это лучшее решение, которое я нашел; "недостаток" как бы заключается в том, что вам нужно знать, какой элемент вы хотите загрузить. Я говорю недостаток, лично я не думаю, что столкнулся с ситуацией, когда у меня не было какой-то обратной связи, в которой говорилось, что все, что я жду, произошло

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

Хотя я бы предположил, что вы можете использовать waitForResource() или что-то в этом роде, если у вас не было визуальной обратной связи.

Ответ 2

Что я сделал, чтобы обойти эту проблему, когда нет ничего конкретного для целевой и ждать на перезагруженной странице, нужно использовать следующее:

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 для элементов, которые могли существовать как до, так и после перезагрузки. Ожидание, пока временный класс не будет удален, позволяет мне знать, что все, что существовало до этого, было уничтожено, поэтому не бойтесь выбирать элементы до перезагрузки.

Ответ 4

У меня такой же опыт, что и ты. script таким образом в пользовательской перспективе так и не получилось. он падает в середине нигде и очень ненадежен. Я делал поиск из salesforce, который также требует входа в систему.

Вам нужно как можно меньше сделать свой шаг. script в режиме работы cron. не делайте заполнение формы/нажатие кнопки, если вы не выполняете тестирование пользовательского интерфейса. Я бы посоветовал вам разбить процесс на две части.

// 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)

my script теперь чистые фантомы, casper script просто терпит крах без причины. даже фантомы ненадежны. Я сохраняю результат/статус при каждом успешном поиске/загрузке, всякий раз, когда появляется ошибка, я выхожу из script, если не остальная часть результата непредсказуема (хороший результат в хром оказывается плохим в phantomjs).

Ответ 5

Я нашел этот вопрос при поиске решения проблемы, в которой действие 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 - это элемент, который, как ожидается, будет перезагружен после отправки клика или формы.

Ответ 6

Так как Casperjs написан для разработчиков, он ожидает, что кто-то знает, в каком состоянии должна быть загружена страница, и какие элементы должны быть доступны для определения загруженного страницы.

Один из вариантов - проверить наличие, например, ресурса javascript, который загружается в конце страницы.

При выполнении любого типа теста результаты должны воспроизводиться каждый раз, и поэтому идемпотентность необходима. Чтобы это произошло, тестер должен иметь возможность контролировать окружающую среду настолько, чтобы это произошло.

Ответ 7

Просто оцените document.readyState как complete или interactive. Затем он загружается.

Это реализация с while, но, возможно, это может быть сделано с интервалом...

this.then(function () {
 while(this.evaluate(function () { return document.readyState != 'complete' && document.readyState != 'interactive'; })) {}
});