setTimeout в Phantom.js

javascript node.js meteor phantomjs

13213 просмотра

2 ответа

Приведенный ниже код требует, чтобы Phantom.js загрузил страницу, нажмите кнопку и подождите 5 секунд, прежде чем вернуть HTML-код страницы.

Проблема: Однако использование setTimeout()для создания 5-секундной задержки заставляет page.evaluateфункцию возвращаться nullк функции обратного вызова вместо HTML.

myUrl = 'http://www.google.com'

var phantom = Meteor.npmRequire('phantom')
phantom.create = Meteor.wrapAsync(phantom.create)
phantom.create( function(ph) {

    ph.createPage = Meteor.wrapAsync(ph.createPage)
    ph.createPage(function(page) {

        page.open = Meteor.wrapAsync(page.open)
        page.open(listingUrl, function(status) {
            console.log('Page loaded')

            page.evaluate = Meteor.wrapAsync(page.evaluate)
            page.evaluate(function() {

                // Find the button
                var element = document.querySelector( '.search-btn' );

                // create a mouse click event
                var event = document.createEvent( 'MouseEvents' );
                event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );

                // send click to element
                element.dispatchEvent( event );

                // Give page time to process Click event
                setTimeout(function() {
                    // Return HTML code
                    return document.documentElement.outerHTML
                }, 5000)

            }, function(html) {

                // html is `null`
                doSomething()

            })
        })
    })
})

Замена setTimeout()на Meteor.setTimeout()вызывает другую ошибку:

phantom stdout: ReferenceError: Can't find variable: Meteor
Автор: Nyxynyx Источник Размещён: 12.11.2019 09:02

Ответы (2)


9 плюса

Решение

page.evaluate()является изолированным контекстом страницы PhantomJS. Он не имеет доступа к переменным, определенным снаружи. Если вам нужен тайм-аут, вам нужно сделать два вызова page.evaluate(), потому что вы не можете ничего вернуть из асинхронной функции ( объяснение ):

page.evaluate(function() {
    ...
    element.dispatchEvent( event );
}, function() {
    setTimeout(function() {
        page.evaluate(function() {    
            return document.documentElement.outerHTML
        }, function(html) {
            doSomething()
        })
    }, 5000)
})

Вместо того, чтобы использовать второй page.evaluate()вызов, вы можете сократить код путем прямого доступа к контенту, как определено здесь :

setTimeout(function() {
    page.get("content", function(content) {
        doSomething()
    })
}, 5000)
Автор: Artjom B. Размещён: 09.03.2015 08:02

0 плюса

Это не очень хорошее решение, но оно работает, если все, что вам нужно, это обрабатывать изменения страницы при нажатии кнопки и отправке формы. Просто объявите переменные функции вне page.open (), а затем назначьте им функции оценки страницы позже внутри. OnLoadFinished будет вызываться после перезагрузки страницы с изменениями, вызванными нажатием кнопки, а затем вы сможете снова оценить ее.

var loadInProgress = false,
jurl = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js',
page = require('webpage').create();

// declare variables outside page.open and assign them later inside
var evalPageFunc;

// assign callbacks which will be called by phantom
page.onLoadStarted = function() {
    loadInProgress = true;
    console.log('load started');
};
page.onLoadFinished = function() {
    loadInProgress = false;
    console.log('load finished');
    if (evalPageFunc) {
      // since the page has loaded we can safely evaluate it
      var mydata = evalPageFunc();
      console.log(mydata);
      if (!mydata.havemore) {
        phantom.exit();
        // or next url
      }
    }
};

page.open(url, function(status) {
  page.includeJs(jurl, function(){

    // define your page evaluating functions
    evalPageFunc = function(){
      return page.evaluate(function() {
        var datafromhtml = {}, havemoretoclick = true;
        // get your data and perform clicks if you want to
        // datafromhtml.somedata = $('stealme').text();
        // $("clickme").click();
        return {
          havemore: havemoretoclick,
          data: datafromhtml
        };
      });
    }
    var k = evalPageFunc();
  });
});

Это не красиво, но это работает.

Автор: user3596375 Размещён: 22.07.2015 11:12
Вопросы из категории :
32x32