Phantomjs a ces deux callbacks vraiment utiles onLoadStarted
et onLoadFinished
qui vous permettent de suspendre l'exécution pendant le chargement de la page. Mais j'ai cherché et je ne trouve pas d'équivalent si vous click()
un bouton ou un lien hypertexte. Un chargement de page similaire se produit mais onLoadStarted
n'est pas appelé pour cet événement, car il n'y a pas de page.open()
explicite. J'essaie de trouver un moyen propre de suspendre l'exécution pendant le chargement.
L'une des solutions est évidemment celle de setTimeout imbriquée, mais j'aimerais éviter ce scénario car il est hacky et repose sur des essais et des erreurs au lieu de quelque chose de plus fiable et robuste, comme tester contre quelque chose ou attendre un événement.
Existe-t-il un rappel spécifique pour ce type de chargement de page que j'ai manquée? Ou peut-être y a-t-il une sorte de modèle de code générique pouvant traiter ce genre de chose?
MODIFIER:
Je n'ai toujours pas compris comment le mettre en pause. Voici le code qui n'appelle pas la fonction onLoadStarted()
lorsque j'appelle la commande 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');
J'ai vérifié deux fois que l'identifiant est correct. La page.render()
indiquera que les informations sont soumises, mais uniquement si je les mets dans un setTimeout (), sinon, elles sont rendues immédiatement et je ne vois que les informations d'identification entrées avant la redirection de page. Peut-être que je manque quelque chose d'autre?
Je pense que les fonctions onLoadStarted
et onLoadFinished
sont tout ce dont vous avez besoin. Prenons par exemple le script suivant:
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);
});
Il imprime
Tentative de navigation vers: http://example.com/ Request (# 1): http://example.com/ Load Started New URL: http: // example. com / Réponse (# 1, étape "fin"): http://example.com/ Load Terminé: success Tentative de navigation vers: http://www.iana.org/domains /example Request (# 2): http://www.iana.org/domains/example Load Started Tentative de navigation vers: http://www.iana.org/domains/reserved Requête (n ° 3): http://www.iana.org/domains/reserved Response (n ° 2, étape "fin"): http://www.iana.org/domains/exemple Nouvelle 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, étape "fin"): http://www.iana.org/domains/reserved Response (# 6, étape "fin"): http://www.iana.org/_js/2013.1 /iana.js Response (# 4, étape "fin"): http://www.iana.org/_css/2013.1/screen.css Response (# 5, étape "fin"): http : // www .iana.org/_js/2013.1/jquery.js Requête (n ° 7): http://www.iana.org/_img/2013.1/iana-logo-header.svg Demande (n ° 8) : http://www.iana.org/_img/2013.1/icann-logo.svg Response (# 8, étape "fin"): http://www.iana.org/_img/2013.1/icann- logo.svg Réponse (n ° 7, étape "fin"): http://www.iana.org/_img/2013.1/iana-logo-header.svg Request (n ° 9): http://www.iana.org/_css/2013.1/print.css Response (# 9, étape "fin"): http://www.iana.org/_css/2013.1/print.css Charge terminée : Succès
Cela montre que cliquer sur un lien émet deux fois l'événement LoadStarted et deux fois l'événement NavigationRequested, car il existe une redirection. L'astuce consiste à ajouter les gestionnaires d'événements avant d'effectuer l'action:
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 vous devez faire ces choses, il est peut-être temps d'essayer quelque chose d'autre comme CasperJS . Il fonctionne sur PhantomJS, mais possède une API bien meilleure pour naviguer dans les pages Web.
Utilisez le wrapper de haut niveau, nightmarejs . Vous pouvez facilement click
et attendre par la suite.
Voici le code (section Exemples):
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!');
});
Vous trouverez plus d’exemples et d’utilisation des API à l’adresse github
Voici mon code basé sur d'autres réponses. Dans mon cas, je n'ai pas eu besoin d'évaluer spécifiquement un autre javascript. Je devais juste attendre que la page se termine.
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();
};
});
}
Enregistrez ce qui précède dans un fichier appelé "scrape.js" et appelez-le ainsi:
phantomjs --ssl-protocol=any --ignore-ssl-errors=true scrape.js https://www.example.com
Les paramètres liés à SSL sont ajoutés pour éviter d'autres problèmes que j'avais avec certains sites HTTPS (liés à des problèmes de chargement de certificat).
J'espère que cela aide quelqu'un!