PhantomJs : cliquer quelques part avant un screenshot

WRInaute impliqué
Bonjour,

Je souhaite faire quelques chose de normalement assez simple avec PhantomJS. Avant de prendre la capture d'écran je souhaite que PhantomJS clique sur une coordonnée (pas un élement, mais une coordonnée du genre X = 100 et Y = 200).

La capture doit donc avoir lieu sur le site B.

Voici mon explication :

119917Sanstitre.jpg


Voici mon code actuel qui ne fonctionne pas car la capture se fait toujours sur le site A :

Code:
page.open(address, settings, function () {
	
 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);
    });
	
	
	page.render(output);
	phantom.exit();
	
});

Je vous remercie de l'aide
 
WRInaute impliqué
J'ai également essayer en intégrant Jquery et en supposant que le lien contient une class "test' mais cela ne fonctionne pas non plus

Code:
page.open(address, settings, function () {
	
  page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
	  
    page.evaluate(function() {
       jQuery(".test").click();
    });
    	page.render(output);
	phantom.exit();
  });
});

Voici les log console :

Code:
2017-02-17T19:02:38 [DEBUG] WebPage - evaluateJavaScript "(function() { return (function () {\n       jQuery(\".test\").click();\n    })(); })()"
2017-02-17T19:02:38 [DEBUG] WebPage - evaluateJavaScript result QVariant(Invalid)
 
WRInaute discret
Question bête : L'élément existe au moment où tu appelle click() ?
Utilise peut-être $(document).ready()
Tu as une page de test ?
 
WRInaute impliqué
Je me retrouve donc avec ceci :

Code:
page.open(address, settings, function(status) {
    // Check for page load success
    if (status !== "success") {
        console.log("Unable to access network");
    } else {
        // Wait for 'signin-dropdown' to be visible
        waitFor(function() {
            // Check in the page if a specific element is now visible
            return page.evaluate(function() {
                document.getElementById("test").click(); // en imaginant un id test sur le href
            });
        }, function() {
           console.log("The sign-in dialog should be visible now.");
		   page.render(output);
           phantom.exit();
        });
    }
});

Les 2 pages sont bien ouverte par Phantomjs, mais la capture est toujours sur le site A et non le B
 
WRInaute impliqué
Hormis le fait que je n'arrive pas à faire une capture sur le deuxième site (ce qui n'est pas le plus important), je n'arrive egalement pas à générer un clic sur la page avec des coordonnée. Est ce que quelqu'un pourrait m'aider ?

J'ai essayé ceci en utilisant SendEvent (http://phantomjs.org/api/webpage/method/send-event.html)

mais ca ne fait aucun effet.

Code:
page.open(address, settings, function(status) {
    // Check for page load success
    if (status !== "success") {
        console.log("Unable to access network");
    } else {

        waitFor(function() {
       
            return page.evaluate(function() {
			
		
    // find element to send click to
    var element = document.querySelector( 'body' );
 
 
    // send click to element
	 element.sendEvent('click', 0, 0, button='left');

				
            });
        }, function() {

         page.render(output);
           phantom.exit();
        });
    }
});

Voici les logs d'erreur :

Code:
 undefined:9
  :12
2017-02-17T23:56:28 [DEBUG] WebPage - evaluateJavaScript result QVariant(Invalid)
2017-02-17T23:56:28 [DEBUG] WebPage - evaluateJavaScript "(function() { return (function () {\n\t\t\t\n\t\t\n    // find element to send click to\n    var element = document.querySelector( 'body' );\n \n \n    // send click to element\n\t element.sendEvent('click', 0, 0, button='left');\n\n\t\t\t\t\n            })(); })()"
TypeError: undefined is not a function (evaluating 'element.sendEvent('click', 0, 0, button='left')')


Merci d'avance
 
WRInaute discret
Tu peux obtenir un l'élément aux coordonnées X Y avec elementFromPoint et simuler un clic dessus.
Si tu es sûr de tes coordonnées tu peux faire une fonction qui sera appelée toutes les xxx ms jusqu'à ce que l'élément soit disponible dan le DOM.
Code:
var zeTimer = window.setInterval(clickCheck, 500);
function clickCheck(){
    var e = document.elementFromPoint(100, 100);
    if(e){
        clearInterval(zeTimer);
        var evt = document.createEvent('Events');
        evt.initEvent('click', true, false);
        e.dispatchEvent(evt);
    }
}
 
WRInaute impliqué
Malheuresement les logs m'affiche une erreur :


2017-02-18T19:40:31 [DEBUG] WebPage - evaluateJavaScript result QVariant(Invalid)

Logs de la partie problématique :

2017-02-18T19:40:31 [DEBUG] WebPage - evaluateJavaScript "(function() { return (function () {\n\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\nfunction clickCheck(){\n var e = document.elementFromPoint(50, 50);\n if(e){\n clearInterval(zeTimer);\n var evt = document.createEvent('Events');\n evt.initEvent('click', true, false);\n e.dispatchEvent(evt);\n }\n}\n\t\t\n\n\t\tvar zeTimer = window.setInterval(clickCheck, 500);\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t})(); })()"
2017-02-18T19:40:31 [DEBUG] WebPage - evaluateJavaScript result QVariant(Invalid)


Mon code :

Code:
page.open(address, settings, function(status) {
	
	// Check for page load success
	page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
		
		if (status !== "success") {
			console.log("==================Unable to access network==================");
		} else {
			// Wait for element to be visible
			waitFor(function() {
				// Check in the page if a specific element is now visible
				
				return page.evaluate(function() {

					return $("body").is(":visible");
					
				});
				
			}, function() {
				console.log("==================The element should be visible now.==================");
				
				
				page.evaluate(function() {
			
					
function clickCheck(){
    var e = document.elementFromPoint(50, 50);
    if(e){
        clearInterval(zeTimer);
        var evt = document.createEvent('Events');
        evt.initEvent('click', true, false);
        e.dispatchEvent(evt);
    }
}
		var zeTimer = window.setInterval(clickCheck, 500);				
					
				});				
				
				page.render(output);
				phantom.exit();
			});
		}
	})
});

Le problème se situe à partir de function clickCheck(){
 
WRInaute impliqué
J'ai enfin réussi à lui faire cliquer une position avec ce code :

Code:
page.open(address, settings, function(status) {
	
	// Check for page load success
	page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
		
		if (status !== "success") {
			console.log("==================Unable to access network==================");
		} else {
			// Wait for element to be visible
			waitFor(function() {
				// Check in the page if a specific element is now visible
				
				return page.evaluate(function() {

					return $("body").is(":visible");
					
				});
				
			}, function() {
				console.log("==================The element should be visible now.==================");
				
				page.sendEvent('click', 50, 50, button='left');
				
				page.render(output);
				phantom.exit();
			});
		}
	})
});

Mais il ne veut pas ouvrir l'url cible, je ne comprends pas !

Voici les logs :

2017-02-18T21:45:23 [DEBUG] Mouse Event: "mousedown" ( QEvent::Type(MouseButtonPress) ) QPoint(50,50) ) 1 1
2017-02-18T21:45:23 [DEBUG] Mouse Event: "mouseup" ( QEvent::Type(MouseButtonRelease) ) QPoint(50,50) ) 1 1
2017-02-18T21:45:23 [DEBUG] WebPage - updateLoadingProgress: 10
2017-02-18T21:45:23 [DEBUG] WebPage - setupFrame ""
2017-02-18T21:45:23 [DEBUG] Network - Resource request error: QNetworkReply::NetworkError(OperationCanceledError) ( "Operation canceled" ) URL: "http://lapagecible.fr"
 
WRInaute impliqué
Bon finalement, j'ai enfin résolu le problème par moi même. Il suffisait de rajouter un timeout à la fin, sinon il n'a pas le temps d"ouvrir la nouvelle page. J'ai mi 10 secondes par précaution. En espérant que ça servent à certains car sur de nombreux forums, il y a ce bug qui est répertorié.

Code:
page.open(address, settings, function(status) {
	
	// Check for page load success
	page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
		
		if (status !== "success") {
			console.log("==================Unable to access network==================");
		} else {
			// Wait for element to be visible
			waitFor(function() {
				// Check in the page if a specific element is now visible
				
				return page.evaluate(function() {

					return $("body").is(":visible");
					
				});
				
			}, function() {
				console.log("==================The element should be visible now.==================");
				console.log("==================Wait 10 seconds.==================");
				
				page.sendEvent('click', 50, 50, button='left');
				

				setTimeout(function(){ 

                                      console.log("==================Capture==================");

					page.render(output);
					phantom.exit();

				}, 10000);				
			});
		}
	})
});

La page complete :

Code:
"use strict";

//function wait display element
function waitFor(testFx, onReady, timeOutMillis) {
	var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
	start = new Date().getTime(),
	condition = false,
	interval = setInterval(function() {
		if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
			// If not time-out yet and condition not yet fulfilled
			condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
		} else {
			if(!condition) {
				// If condition still not fulfilled (timeout but condition is 'false')
				console.log("'waitFor()' timeout");
				phantom.exit(1);
			} else {
				// Condition fulfilled (timeout and/or condition is 'true')
				console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
				typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
				clearInterval(interval); //< Stop this interval
			}
		}
	}, 250); //< repeat check every 250ms
};


var page = require('webpage').create(),
system = require('system'),
address, output, ref;

page.settings.userAgent = 'Opera/9.80 (Android 2.2.2; Linux; Opera Tablet/ADR-1111101157; U; en) Presto/2.9.201 Version/11.50';

address = system.args[1];
output = system.args[2];
ref = system.args[3]; //Option

var settings = {
headers: {
		"Referer": "http://yahoo.com"
	}
};	


page.open(address, settings, function(status) {
	
	// Check for page load success
	page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
		
		if (status !== "success") {
			console.log("==================Unable to access network==================");
		} else {
			// Wait for element to be visible
			waitFor(function() {
				// Check in the page if a specific element is now visible
				
				return page.evaluate(function() {

					return $("body").is(":visible");
					
				});
				
			}, function() {
				console.log("==================The element 'BODY' should be visible now.==================");
				console.log("==================Wait 10 seconds.==================");			
				
				page.sendEvent('click', 50, 50, button='left');

				setTimeout(function(){ 
					
					console.log("==================Capture.==================");

					page.render(output);
					phantom.exit();

				}, 10000);
			});
		}
	})
});
 
WRInaute impliqué
Voila la solution : page.onLoadFinished va vérifier si la nouvelle page a fini de charger

Code:
page.open(address, settings, function(status) {
	
	// Check for page load success
	page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
		
		if (status !== "success") {
			
			console.log("======================== > Unable to access network");
			
		} else {

			// Wait for element to be visible			
			waitFor(function() {
				
				// Check in the page if a specific element is now visible
				return page.evaluate(function() {

					return $("body").is(":visible");
					
				});
				
			}, function() {
				console.log("======================== > The element 'BODY' should be visible now");		
				console.log("======================== > Click");	
				
				page.sendEvent('click', 50, 50, button='left');
				
				page.onLoadFinished = function(status) {
					
					console.log('======================== > Load Finished: ' + status);
					console.log("======================== > Capture");
					
					page.render(output);
					phantom.exit();

				};			
			});
		}
	})
});
 
Discussions similaires
Haut