click - run - phantomjs()
¿Cómo esperar a que un evento click() se cargue en phantomjs antes de continuar? (3)
Phantomjs tiene estas dos devoluciones de llamada muy útiles onLoadStarted
y onLoadFinished
que le permiten esencialmente detener la ejecución mientras se carga la página. Pero he estado buscando y no puedo encontrar un equivalente si haces click()
un botón de envío o un hipervínculo. Sucede una carga de página similar pero no se llama a onLoadStarted
para este evento, supongo que porque no hay un page.open()
explícito que sucede. Estoy tratando de encontrar una manera limpia de suspender la ejecución mientras se lleva a cabo esta carga.
Una solución es obviamente setTimeout''s anidada, pero me gustaría evitar este escenario porque es intrépido y se basa en la prueba y el error en lugar de algo confiable y más robusto, como probar algo o esperar un evento.
¿Hay una devolución de llamada específica para este tipo de carga de página que perdí? ¿O tal vez hay algún tipo de patrón de código genérico que puede hacer frente a este tipo de cosas?
EDITAR:
Todavía no he descubierto cómo hacer que se detenga. Aquí está el código que no llama a la función onLoadStarted()
cuando llamo el comando click()
:
var loadInProgress = false;
page.onLoadStarted = function() {
loadInProgress = true;
console.log("load started");
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log("load finished");
};
page.open(loginPage.url, function (status) {
if (status !== ''success'') {
console.log(''Unable to access network'');
fs.write(filePath + errorState, 1, ''w'');
phantom.exit();
} else {
page.evaluate(function (loginPage, credentials) {
console.log(''inside loginPage evaluate function.../n'')
document.querySelector(''input[id='' + loginPage.userId + '']'').value = credentials.username;
document.querySelector(''input[id='' + loginPage.passId + '']'').value = credentials.password;
document.querySelector(''input[id='' + loginPage.submitId + '']'').click();
//var aTags = document.getElementsByTagName(''a'')
//aTags[1].click();
}, loginPage, credentials);
page.render(renderPath + ''postLogin.png'');
console.log(''rendered post-login'');
Comprobé que la identificación es correcta. El page.render()
mostrará que la información se envía, pero solo si la puse en un setTimeout (), de lo contrario, la muestra inmediatamente y solo veo las credenciales ingresadas, antes de que la página redirija. Tal vez me estoy perdiendo algo más?
Aquí está mi código basado en algunas otras respuestas. En mi caso, no necesité evaluar específicamente ningún otro javascript. Solo necesitaba esperar a que la página terminara de cargarse.
var system = require(''system'');
if (system.args.length === 1) {
console.log(''Try to pass some arguments when invoking this script!'');
}
else {
var page = require(''webpage'').create();
var address = system.args[1];
page.open(address, function(status){
page.onLoadFinished = function(status) {
console.log(page.content);
phantom.exit();
};
});
}
Guarde lo anterior en un archivo llamado "scrape.js" y llámelo de esta manera:
phantomjs --ssl-protocol=any --ignore-ssl-errors=true scrape.js https://www.example.com
Los parámetros relacionados con SSL se agregan para evitar otros problemas que estaba teniendo con ciertos sitios HTTPS (relacionados con problemas de carga de certificados).
¡Espero que esto ayude a alguien!
Creo que las funciones onLoadStarted
y onLoadFinished
son todo lo que necesita. Tomemos por ejemplo el siguiente script:
var page = require(''webpage'').create();
page.onResourceReceived = function(response) {
if (response.stage !== "end") return;
console.log(''Response (#'' + response.id + '', stage "'' + response.stage + ''"): '' + response.url);
};
page.onResourceRequested = function(requestData, networkRequest) {
console.log(''Request (#'' + requestData.id + ''): '' + requestData.url);
};
page.onUrlChanged = function(targetUrl) {
console.log(''New URL: '' + targetUrl);
};
page.onLoadFinished = function(status) {
console.log(''Load Finished: '' + status);
};
page.onLoadStarted = function() {
console.log(''Load Started'');
};
page.onNavigationRequested = function(url, type, willNavigate, main) {
console.log(''Trying to navigate to: '' + url);
};
page.open("http://example.com", function(status){
page.evaluate(function(){
// click
var e = document.createEvent(''MouseEvents'');
e.initMouseEvent(''click'', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
document.querySelector("a").dispatchEvent(e);
});
setTimeout(function(){
phantom.exit();
}, 10000);
});
Se imprime
Trying to navigate to: http://example.com/ Request (#1): http://example.com/ Load Started New URL: http://example.com/ Response (#1, stage "end"): http://example.com/ Load Finished: success Trying to navigate to: http://www.iana.org/domains/example Request (#2): http://www.iana.org/domains/example Load Started Trying to navigate to: http://www.iana.org/domains/reserved Request (#3): http://www.iana.org/domains/reserved Response (#2, stage "end"): http://www.iana.org/domains/example New URL: http://www.iana.org/domains/reserved Request (#4): http://www.iana.org/_css/2013.1/screen.css Request (#5): http://www.iana.org/_js/2013.1/jquery.js Request (#6): http://www.iana.org/_js/2013.1/iana.js Response (#3, stage "end"): http://www.iana.org/domains/reserved Response (#6, stage "end"): http://www.iana.org/_js/2013.1/iana.js Response (#4, stage "end"): http://www.iana.org/_css/2013.1/screen.css Response (#5, stage "end"): http://www.iana.org/_js/2013.1/jquery.js Request (#7): http://www.iana.org/_img/2013.1/iana-logo-header.svg Request (#8): http://www.iana.org/_img/2013.1/icann-logo.svg Response (#8, stage "end"): http://www.iana.org/_img/2013.1/icann-logo.svg Response (#7, stage "end"): http://www.iana.org/_img/2013.1/iana-logo-header.svg Request (#9): http://www.iana.org/_css/2013.1/print.css Response (#9, stage "end"): http://www.iana.org/_css/2013.1/print.css Load Finished: success
Muestra que hacer clic en un enlace emite el evento LoadStarted una vez y el evento NavigationRequested dos veces, porque hay una redirección. El truco es agregar los controladores de eventos antes de realizar la acción:
var page = require(''webpage'').create();
page.open("http://example.com", function(status){
page.onLoadFinished = function(status) {
console.log(''Load Finished: '' + status);
page.render("test37_next_page.png");
phantom.exit();
};
page.onLoadStarted = function() {
console.log(''Load Started'');
};
page.evaluate(function(){
var e = document.createEvent(''MouseEvents'');
e.initMouseEvent(''click'', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
document.querySelector("a").dispatchEvent(e);
});
});
Si necesita hacer esas cosas, tal vez es hora de probar algo como CasperJS . Se ejecuta sobre PhantomJS, pero tiene una API mucho mejor para navegar por las páginas web.
Utilice la envoltura de alto nivel, nightmarejs . Puede hacer click
allí fácilmente y esperar después.
Aquí está el código (sección de ejemplos):
var Nightmare = require(''nightmare'');
new Nightmare()
.goto(''http://yahoo.com'')
.type(''input[title="Search"]'', ''github nightmare'')
.click(''.searchsubmit'')
.run(function (err, nightmare) {
if (err) return console.log(err);
console.log(''Done!'');
});
Más ejemplos y uso de API se pueden encontrar en github