2012-10-03 13 views
21

Estoy trabajando para integrar el navegador sin cabeza PhantomJS en un proyecto mío (actualmente usando la versión 1.6). En su mayor parte, está haciendo un gran trabajo al lograr lo que necesito lograr. Sin embargo, la naturaleza asíncrona de la forma en que funcionan las llamadas a WebPage.open(), y la necesidad de llamar a phantom.exit() en algún momento, hace que sea difícil manejar los redireccionamientos del lado del cliente cuando no se puede anticipar hacia dónde se dirigen. ir.Cómo finalizar un script PhantomJS solo después de que se han producido redirecciones del lado del cliente

Lo que estoy buscando es una forma de llamar a phantom.exit() solo después de cualquier meta actualización (que conduzca a una página diferente) y se han ejecutado los redireccionamientos de JavaScript ligados a eventos como onload. Puedo ver por qué esto es un problema, porque en teoría una redirección del lado del cliente podría tener lugar segundos después de la carga de una página, y no puedo simplemente pedir la posibilidad de salir solo cuando no hay más redirecciones que van a tener lugar. En este momento, la mejor solución que puedo pensar es a) detectar manualmente la presencia de metarefrigerar los elementos en la página y lidiar con ellos, yb) usar setInterval() para permitir una cierta cantidad de tiempo (por ejemplo, 1- 1.5 segundos) para que transcurra antes de llamar a phantom.exit(). Sería básicamente el siguiente aspecto:

var page = require('webpage').create(); 
var visitComplete = false; 
var url = "http://some.url"; 
var pageOpenedTime; 
setInterval(function() { 
    if (visitcomplete && typeof pageOpenedTime != 'undefined' && 
     new Date() - pageOpenedTime >= 1500) 
    { 
     phantom.exit(); 
    } 
), 1000); 
page.open(url, function() { 
    pageOpenedTime = new Date(); 
    if (!hasMetaRefresh(page)) { 
     visitComplete = true; 
    } 
}); 

function hasMetaRefresh(page) { 
    // Query the DOM here to detect meta refresh elements 
} 

mejor idea?

Editar: Debo mencionar que mi primer pensamiento fue que podría haber un evento PhantomJS que se dispara cuando se ha ejecutado el JavaScript asociado con la carga de la página inicial, pero la devolución de llamada onLoadFinished parece preceder a la ejecución de cualquier JavaScript de la página, incluidos los eventos de carga. También realicé algunas pruebas acerca de cuánto de un intervalo podría necesitar esperar, y mientras que 1000 ms fue suficiente para un redireccionamiento de JavaScript (a través del evento de carga del cuerpo) para ser ejecutado en una página de prueba pequeña, 100 ms no fue lo suficientemente largo.

+0

Usé el mismo enfoque en mi proyecto, es deciragregó una pequeña pausa entre llamadas. Me temo que es la única opción (por ahora). –

Respuesta

0

Tengo la idea de usar temporizadores simulados para este propósito. Supongamos que incluimos "a mocked timer" en la página. De esta forma, puede acelerar el tiempo para evitar el tiempo de inactividad js. Vea los ejemplos en la página de GitHub.

Este es solo un enfoque para hacer que las cosas sucedan más rápido, pero como era de esperar, no es posible asegurarse de que se dispare un evento de redirección en el futuro.

8

Tuve el mismo problema al cargar una página que estaba utilizando Optimizely, y la variación fue una redirección de location.href.

Ahora uso la devolución de llamada onNavigationRequest dentro de una función "renderPage". Esos redireccionamientos optimizados ya no se bloquean y no necesito un tiempo de espera arbitrario.

var webpage = require('webpage'); 
var page = null; 

var renderPage = function (myurl) { 
    page = webpage.create(); 

    page.onNavigationRequested = function(url, type, willNavigate, main) { 
     if (main && url!=myurl && url.replace(/\/$/,"")!=myurl&& (type=="Other" || type=="Undefined")) { 
     // main = navigation in main frame; type = not by click/submit etc 

      log("\tfollowing "+myurl+" redirect to "+url) 
      myurl = url; 
      page.close(); 
      renderPage(url); // rerun this function wit the new URL 
     } 
    }; // on Nav req 

    page.open(myurl, function(status) { 
     if (status==="success") { 
      page.render("screenshot.jpg"); 
     } else { 
      page.close(); 
     } 
    }); // page open 
} // render page 


renderPage("http://some.domain.com"); 

ver documentos: http://phantomjs.org/api/webpage/handler/on-navigation-requested.html

+0

Esto funcionaría para redireccionamientos de encabezados, redireccionamientos js y acciones de usuario ¿no? – CMCDragonkai

+0

@CMCDragonkai: según mi uso, esto funciona en CUALQUIER cambio en la URL, por lo que recibimos un 302 -> el navegador le hace una nueva solicitud -> cambios de navegación Lo mismo si hace una ubicación.href a través de JavaScript; Las utilizaciones (es decir, clics de mouse emulados y formularios, etc. se tratan de forma diferente: el valor de "tipo" con cambio (tipo: los valores posibles incluyen: 'Indefinido', 'Enlace', 'FormSubmitted', 'BackOrForward', 'Reload', 'FormResubmitted' , 'Otro') – ProfessionalHack

0

ya la caja varios de ejemplo para redirigir PhantomJS de manejo: Mala suerte.

Por el momento, no hay una solución universal para ello. Si aplica un parche al script as suggested here, se producirá un error en otro escenario, p. al lado de usar location.href, usando javascript para redirigir. No he probado el cuerpo todavía. Después de algunos parches de dinero aquí y allá, me rindo.

Acabo de utilizar el "pesado" Selenio desencadenado Firefox para resolver mis problemas. Si necesita cargar muchas páginas, en lugar de reiniciar Firefox, simplemente use webdriver.delete_all_cookies() para limpiar algunas capturas. Me da resultados confiables (que necesito hacer captura de pantalla, descargar el html, obtener la url final y muchas más) comparar con phantomjs.

Cuestiones relacionadas