2012-09-23 14 views
11

Estoy arrastrando una página de Facebook con el módulo de nodo PhantomJS (https://github.com/sgentle/phantomjs-node), pero cuando intento evaluar la página, no evalúa la función que le paso. Ejecutarlo en una secuencia de comandos independiente y ejecutarlo con el intérprete de nodo funciona ... El mismo código en una aplicación Express.js no funciona.Phantomjs no ejecuta la función en la función page.valuate

Este es mi código

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); 
      }); 
     }); 
    }); 
}; 

La salida me sale:

{"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"} 

Así que, como ves, se llama a la función fantasma de devolución de llamada (segundo parámetro en la función de evaluar) con un nulo argumento, pero no ejecuta el primer parámetro (mi función evaluadora, que imprime el paso iterativo X).

¿Alguien sabe cuál es el problema?

Respuesta

23

No estoy seguro de qué versión de PhantomJS está utilizando, pero en cuanto a la documentación de las versiones 1.6+ el inicio de sesión en el script evaluado registrará el resultado en la página contenida. No se registrará en su consola. Para conseguir que el que tendría que unir el registro en el caso de páginas onConsoleMessage:

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

En cuanto al resultado que no están disponibles: La función page.evaluate toma argumentos como tal - primera es una función a ejecutar y el el resto se pasa como entrada a esa función. El resultado se devuelve directamente:

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

evaluate se ejecuta en el modo de recinto de seguridad, lo que significa que ninguna de las variables definidas en el entorno que contiene están disponibles, incluyendo cb o incluso el objeto phantom o cualquier función que pueda haber definido .

Puede canalizar explícitamente información en el sandbox como argumentos adicionales al evaluate.

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

PhantomJS' es la puerta al contexto DOM (contexto de la página). Solo es posible acceder al DOM a través de esta función. Dado que la función es sandbox, no puede usar variables definidas fuera de ella y deben pasar explícitamente. Existen limitaciones lo que pueden pasar dentro y fuera, aunque (docs):

Nota: Los argumentos y el valor de retorno de la función evaluate debe ser un objeto primitivo simple. La regla general: si se puede serializar a través de JSON, entonces está bien.

Cierres, funciones, nodos DOM, etc. no ¡trabajo!

phantomjs-node es un puente entre PhantomJS y el nodo.js y como tal tiene una API ligeramente diferente que PhantomJS. Las funciones que son síncronas en PhantomJS no devuelven nada en phantomjs-node, sino que toman una devolución de llamada donde se pasa el resultado. La devolución de llamada se ejecuta en el contexto externo y no es un espacio aislado.

Los argumentos se puede pasar de esta manera:

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"); 
+1

La versión más reciente del puente PhantomJS-nodo debe devolver una promesa en vez de confiar en una función de devolución de llamada. –

+0

Esto realmente me ayudó, gracias –

+0

Bueno, pierdo unas 6 horas probando algunas cosas dentro de la función 'evaluar' ... Si hay otra función dentro de ella, o algo de tipo no primitivo, ni siquiera comenzará la ejecución de la función ... Una cosa importante. ** No olvides leer la documentación ** –

2

Los siguientes trabajó para mí evaluar una página:

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