Phantomjs не выполняет функцию в функции page.evaluate

Я очищаю страницу Facebook с помощью модуля PhantomJS node (https://github.com/sgentle/phantomjs-node), но когда я пытаюсь оценить страницу, он не оценивает функцию, которую я передаю ей. Выполнение его в автономном режиме script и запуск его с помощью интерпретатора node.. Тот же код в приложении Express.js не работает.

Это мой код

facebookScraper.prototype.scrapeFeed = function (url, cb) {
    f = ':scrapeFeed:';

    var evaluator = function (s) {
        var posts = [];

        for (var i = 0; i < FEED_ITEMS; i++) {
            log.info(__filename+f+' iterating step ' + i);
            log.info(__filename+f+util.inspect(document, false, null));
        }

        return {
            news: posts
        };
    }

    phantom.create(function (ph) {
        ph.createPage(function (page) {
            log.fine(__filename+f+' opening url ' + url);
            page.open(url, function (status) {
                log.fine(__filename+f+' opened site? ' + status);
                setTimeout(function() {
                    page.evaluate(evaluator, function (result) {
                        log.info(__filename+f+'Scraped feed: ' + util.inspect(result, false, null));
                        cb(result, ph);
                    });
                }, 5000);
            });
        });
    });
};

Выход, который я получаю:

{"level":"fine","message":"PATH/fb_regular.js:scrapeFeed: opening url <URL> ","timestamp":"2012-09-23T18:35:10.151Z"}
{"level":"fine","message":"PATH/fb_regular.js:scrapeFeed: opened site? success","timestamp":"2012-09-23T18:35:12.682Z"}
{"level":"info","message":"PATH/fb_regular.js:scrapeFeed: Scraped feed: null","timestamp":"2012-09-23T18:35:12.687Z"}

Таким образом, как вы видите, он вызывает функцию обратного вызова phantom (второй параметр в функции оценки) с нулевым аргументом, но он не выполняет первый параметр (моя функция оценщика, которая печатает итерирующий шаг X).

Кто-нибудь знает, в чем проблема?

Ответ 1

Я не уверен в том, какую версию PhantomJS вы используете, но что касается документации по версиям 1.6+, зарегистрированная в оцененном script, будет записывать результат на содержащуюся страницу. Он не войдет в вашу консоль. Чтобы получить это, вам придется привязать ведение журнала к страницам в событииConsoleMessage:

  page.onConsoleMessage = function (msg) { console.log(msg); };

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

 var title = page.evaluate(function (s) {
    return document.querySelector(s).innerText;
 }, 'title');
 console.log(title);

Ответ 2

evaluate запускается в режиме песочницы, что означает, что ни одна из переменных, определенных в содержащей среде, не доступна, включая cb или даже объект phantom или любые функции, которые вы, возможно, определили.

Вы можете явно туннелировать информацию в песочнице в качестве дополнительных аргументов evaluate.

page.evaluate(function(cb){...},  cb); 

Ответ 3

Функция PhantomJS 'page.evaluate() - это дверь в контекст DOM (контекст страницы). Доступ к DOM возможен только через эту функцию. Поскольку функция изолирована песочницей, вы не можете использовать переменные, определенные за ее пределами, и они должны быть переданы явно. Существуют ограничения, которые могут быть переданы и удалены (docs):

Примечание. Аргументы и возвращаемое значение функции evaluate должны быть простым примитивным объектом. Эмпирическое правило: если оно может быть сериализовано через JSON, тогда это нормально.

Закрытия, функции, узлы DOM и т.д. не будут работать!

phantomjs-node является мостом между PhantomJS и node.js и, как таковой, имеет несколько иной API, чем сам PhantomJS. Функции, которые синхронны в PhantomJS, не возвращают ничего в phantomjs- node, но выполняют обратный вызов, в который передается результат. Обратный вызов выполняется во внешнем контексте и не изолирован.

Аргументы могут быть переданы следующим образом:

page.evaluate(function(arg1, arg2){
    // use arg1 and arg2 in the page
    // return `result`
}, function(result){
    // use `result` in the node context
}, "some arg1", "another arg");

Ответ 4

Следующее работало для меня, чтобы оценить страницу:

page.evaluate(function(s) {
  return document.querySelector(s)
}, 'body').then(res => {
  console.log(res)
})