prebuilt phantom node instalar globally example node.js web-scraping phantomjs jsdom

node.js - node - phantomjs prebuilt 2.1 16



Cómo administrar un ''grupo'' de instancias de PhantomJS (6)

Como alternativa a la excelente respuesta de @JasonS puedes probar PhearJS , que construí. PhearJS es un supervisor escrito en NodeJS para instancias de PhantomJS y proporciona una API a través de HTTP. Está disponible fuente abierta de Github .

Estoy planificando un servicio web para mi propio uso interno que toma un argumento, una URL y devuelve html que representa el DOM resuelto de esa URL. Resuelto, quiero decir que el servicio web primero obtendrá la página en esa URL, luego usará PhantomJS para ''renderizar'' la página, y luego devolverá la fuente resultante después de que se ejecuten todas las llamadas DHTML, AJAX, etc. Sin embargo, lanzar un fantasma por solicitud (lo que estoy haciendo ahora) es demasiado lento. Preferiría tener un conjunto de instancias PhantomJS con una siempre disponible para atender la última llamada a mi servicio web.

¿Se ha hecho algún trabajo en este tipo de cosas antes? Prefiero basar este servicio web en el trabajo de los demás que escribir un administrador de grupo / servidor proxy http desde cero.

Más contexto : he enumerado los 2 proyectos similares que he visto hasta ahora y por qué he evitado cada uno, lo que da como resultado esta pregunta sobre la administración de un grupo de instancias de PhantomJS.

jsdom: por lo que he visto, tiene una gran funcionalidad para ejecutar scripts en una página, pero no intenta replicar el comportamiento del navegador, por lo que si yo lo usara como un "resolvedor de DOM" de propósito general, terminaría siendo una gran cantidad de codificación adicional para manejar todo tipo de casos de bordes, llamadas a eventos, etc. El primer ejemplo que vi fue tener que llamar manualmente a la función onload () de la etiqueta del cuerpo para una aplicación de prueba que configuré usando el nodo. Parecía el comienzo de un profundo agujero de conejo.

Selenio: simplemente tiene muchas más partes móviles, por lo que configurar un grupo para gestionar instancias de navegador de larga duración será más complicado que utilizar PhantomJS. No necesito ninguno de sus beneficios de macro grabación / scripting. Solo quiero un servicio web que sea tan eficiente en obtener una página web y resolver su DOM como si estuviera navegando a esa URL con un navegador (o incluso más rápido si puedo hacer que ignore las imágenes, etc.)


Configuré un servicio en la nube PhantomJs, y hace más o menos lo que me pides. Me tomó alrededor de 5 semanas de implementación del trabajo.

El mayor problema con el que se encontrará es el conocido problema de pérdida de memoria en PhantomJs . La forma en que trabajé en esto es hacer un ciclo de mis instancias cada 50 llamadas.

El segundo problema más grande con el que se encontrará es que el procesamiento por página consume mucha memoria y CPU, por lo que solo podrá ejecutar 4 instancias por CPU.

El tercer problema más grande que se encontrará es que PhantomJs es bastante loco con eventos y redirecciones de página acabada. Se le informará que su página ha finalizado la renderización antes de que realmente sea. Hay varias maneras de lidiar con esto , pero desafortunadamente no hay nada ''estándar''.

El cuarto problema más importante con el que tendrás que lidiar es la interoperabilidad entre nodejs y phantomjs. Afortunadamente, hay muchos paquetes de npm que se ocupan de este tema para elegir.

Así que sé que soy parcial (ya que escribí la solución que voy a sugerir), pero sugiero que consulte PhantomJsCloud.com, que es gratuito para uso ligero.

Actualización de enero de 2015: Otro (¿el 5to?) Gran problema que encontré es cómo enviar la solicitud / respuesta del administrador / equilibrador de carga. Originalmente estaba usando el servidor HTTP incorporado de PhantomJS, pero seguí corriendo en sus limitaciones, especialmente con respecto al tamaño máximo de respuesta. Terminé escribiendo la solicitud / respuesta al sistema de archivos local como líneas de comunicación. * El tiempo total invertido en la implementación del servicio representa quizás 20 problemas de semanas hombre es quizás 1000 horas de trabajo. * y FYI estoy haciendo una reescritura completa para la próxima versión ... (en curso)


Para mi tesis de maestría, desarrollé la biblioteca phantomjs-pool que hace exactamente esto. Permite proporcionar trabajos que luego se asignan a los trabajadores de PhantomJS. La biblioteca maneja la distribución del trabajo, la comunicación, el manejo de errores, el inicio de sesión, el reinicio y algunas cosas más. La biblioteca se utilizó con éxito para rastrear más de un millón de páginas.

Ejemplo:

El siguiente código ejecuta una búsqueda en Google para los números del 0 al 9 y guarda una captura de pantalla de la página como googleX.png . Cuatro sitios web se rastrean en paralelo (debido a la creación de cuatro trabajadores). La secuencia de comandos se inicia a través del node master.js .

master.js (se ejecuta en el entorno Node.js)

var Pool = require(''phantomjs-pool'').Pool; var pool = new Pool({ // create a pool numWorkers : 4, // with 4 workers jobCallback : jobCallback, workerFile : __dirname + ''/worker.js'', // location of the worker file phantomjsBinary : __dirname + ''/path/to/phantomjs_binary'' // either provide the location of the binary or install phantomjs or phantomjs2 (via npm) }); pool.start(); function jobCallback(job, worker, index) { // called to create a single job if (index < 10) { // index is count up for each job automatically job(index, function(err) { // create the job with index as data console.log(''DONE: '' + index); // log that the job was done }); } else { job(null); // no more jobs } }

worker.js (se ejecuta en el entorno PhantomJS)

var webpage = require(''webpage''); module.exports = function(data, done, worker) { // data provided by the master var page = webpage.create(); // search for the given data (which contains the index number) and save a screenshot page.open(''https://www.google.com/search?q='' + data, function() { page.render(''google'' + data + ''.png''); done(); // signal that the job was executed }); };


Si está utilizando nodejs, puede usar https://github.com/sgentle/phantomjs-node , que le permitirá conectar un número arbitrario de procesos phantomjs a su proceso principal NodeJS, por lo tanto, la capacidad de utilizar async.js y muchos extras de nodo.


si está usando nodejs, ¿por qué no usar selenium-webdriver?

  1. ejecuta alguna instancia de phantomjs como webdriver phantomjs --webdriver=port_number
  2. para cada instancia phantomjs crea PhantomInstance

    function PhantomInstance(port) { this.port = port; } PhantomInstance.prototype.getDriver = function() { var self = this; var driver = new webdriver.Builder() .forBrowser(''phantomjs'') .usingServer(''http://localhost:''+self.port) .build(); return driver; }

    y póngalos a todos en una matriz [phantomInstance1, phantomInstance2]

  3. crear dispather.js que obtenga la instancia fantasma libre de la matriz y

    var driver = phantomInstance.getDriver();


La biblioteca de JavaScript asíncrona funciona en Nodo y tiene una función de queue que es bastante útil para este tipo de cosas:

queue(worker, concurrency)

Crea un objeto de cola con la concurrencia especificada. Las tareas agregadas a la cola se procesarán en paralelo (hasta el límite de concurrencia). Si todos los trabajadores están en progreso, la tarea se pone en cola hasta que uno esté disponible. Una vez que un trabajador ha completado una tarea, se llama a la devolución de llamada de la tarea.

Algunos pseudocódigo:

function getSourceViaPhantomJs(url, callback) { var resultingHtml = someMagicPhantomJsStuff(url); callback(null, resultingHtml); } var q = async.queue(function (task, callback) { // delegate to a function that should call callback when it''s done // with (err, resultingHtml) as parameters getSourceViaPhantomJs(task.url, callback); }, 5); // up to 5 PhantomJS calls at a time app.get(''/some/url'', function(req, res) { q.push({url: params[''url_to_scrape'']}, function (err, results) { res.end(results); }); });

Consulte toda la documentación para la queue en el archivo Léame del proyecto .