PhantomJS; haga clic en un elemento

81

¿Cómo hago clic en un elemento en PhantomJS?

page.evaluate(function() {
    document.getElementById('idButtonSpan').click();  
});

Esto me da un error "indefinido no es una función ..."

Si yo en cambio

 return document.getElementById('idButtonSpan');

y luego imprimirlo,

luego imprime [objeto objeto], por lo que el elemento existe.

El elemento actúa como un botón, pero en realidad es solo un elemento de intervalo, no una entrada de envío.

Pude hacer que este botón funcionara con Casper, pero Casper tenía otras limitaciones, así que volví a PhantomJS.

usuario984003
fuente
28
Es hora de aceptar una respuesta.
Hay 3 respuestas que usan la función "dispatchEvent", 2 que usan "sendEvent", una que es prácticamente inútil y otra que debería ser un comentario.
redbeam_
No olvides el signo # ...
GracefulCode
¿Por qué nadie ha señalado todavía que click()no existe en DOM API en absoluto, probablemente lo vio en jQuery o alguna lib como esa?
YemSalat
4 años después: ¡Respuesta aceptada! Me alejé de PhantomJS, por lo que no pude verificar la respuesta. Pero aceptaré que 58 votos a favor son correctos :) @torazaburo
user984003

Respuestas:

68

.click()no es estándar. Necesita crear un evento y enviarlo:

function click(el){
    var ev = document.createEvent("MouseEvent");
    ev.initMouseEvent(
        "click",
        true /* bubble */, true /* cancelable */,
        window, null,
        0, 0, 0, 0, /* coordinates */
        false, false, false, false, /* modifier keys */
        0 /*left*/, null
    );
    el.dispatchEvent(ev);
}

fuente
9
Envolver elcon jQuery le da esta definición de clic. Funcionará en su navegador y en Phantom. $(el).click()
Bluu
3
¡Dios mío, lágrimas de alegría, después de casi 12 horas de lucha continua con esto! ¡sniff sniff!
user1323136
1
También funcionó bien para mí, pero uno debe recordar no salir de PhantomJS demasiado pronto, antes de que finalice el procesamiento. Necesitaba un breve script para hacer clic en un botón y salir. Esto no funcionaría para mí hasta que llame a phantom.exit () desde dentro de page.onLoadFinished = function () {...};
Gregko
document.querySelector (element) .click () funciona bien para mí.
GracefulCode
Para trabajar con controles personalizados, tuve que hacer una solución más complicada con 3 eventos: función triggerMouseEvent (elm, eventType) {var ev = document.createEvent ("MouseEvent"); ev.initMouseEvent (eventType, verdadero / * burbuja /, verdadero / cancelable /, ventana, nulo, 0, 0, 0, 0, / coordenadas / falso, falso, falso, falso, / teclas modificadoras * / 0 / * izquierda * /, nulo ); elm.dispatchEvent (ev); } función clic (olmo) {triggerMouseEvent (olmo, 'mousedown'); triggerMouseEvent (olmo, 'mouseup'); triggerMouseEvent (olmo, 'clic'); }
a-bobkov
34

Alternativamente a la respuesta de @ torazaburo, puede stub HTMLElement.prototype.clickcuando se ejecuta en PhantomJS. Por ejemplo, usamos PhantomJS + QUnit para ejecutar nuestras pruebas y en nuestro qunit-config.jstenemos algo como esto:

if (window._phantom) {
  // Patch since PhantomJS does not implement click() on HTMLElement. In some 
  // cases we need to execute the native click on an element. However, jQuery's 
  // $.fn.click() does not dispatch to the native function on <a> elements, so we
  // can't use it in our implementations: $el[0].click() to correctly dispatch.
  if (!HTMLElement.prototype.click) {
    HTMLElement.prototype.click = function() {
      var ev = document.createEvent('MouseEvent');
      ev.initMouseEvent(
          'click',
          /*bubble*/true, /*cancelable*/true,
          window, null,
          0, 0, 0, 0, /*coordinates*/
          false, false, false, false, /*modifier keys*/
          0/*button=left*/, null
      );
      this.dispatchEvent(ev);
    };
  }
}
TheCloudlessSky
fuente
1
Un aviso de que estoy ejecutando Karma 0.12.17 con PhantomJs 1.9.7-14. No hay ningún window._phantomobjeto, así que eliminé esa condición y funcionó como se esperaba.
BradGreens
Me pregunto si la función debería aceptar parámetros para establecer diferentes coordenadas para MouseEvent
ffflabs
16

No es bonito, pero he estado usando esto para permitirme usar jQuery para la selección:

var rect = page.evaluate(function() {
    return $('a.whatever')[0].getBoundingClientRect();
});
page.sendEvent('click', rect.left + rect.width / 2, rect.top + rect.height / 2);

pero siempre puede reemplazar $(s)[0]con document.querySelector(s)si no usa jQuery.

(Depende de que el elemento esté en vista, es decir, su viewportSize.height es lo suficientemente grande).

Stovroz
fuente
2
Probé todos los enfoques posibles y esta es la única opción que funcionó para mí al intentar hacer clic tr.
Kai
Trabajó en phantomjs 1.9.0 y con un elemento <a>
redbeam_
1
la mejor solución en mi opinión,+1
Flash Thunder
10

Espero que el siguiente método sea útil. Me funcionó en la versión 1.9

page.evaluate(function(){
    var a = document.getElementById("spr-sign-in-btn-standard");
    var e = document.createEvent('MouseEvents');
    e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    a.dispatchEvent(e);
    waitforload = true;
});

Esto funcionó para mí. Espero que esto también sea útil para otros

Jobins John
fuente
@Jobins john ¿qué es waitforload = true?
Qadir Hussain
1
@QadirHussain En realidad, está esperando que la página se cargue por completo. Es casi como configurar una hora determinada para cargar la página.
Jobins John
6

Con 1.9.2esto funcionó para mí, se activaron los controladores de clic:

var a = page.evaluate(function() {
    return document.querySelector('a.open');
});

page.sendEvent('click', a.offsetLeft, a.offsetTop);
sshaw
fuente
No está en todos los elementos. Por ejemplo, <a> no lo tiene. En los botones está ahí.
Deshacer
6

use JavaScript simple con evaluatealgo como esto:

page.evaluate(function() {
    document.getElementById('yourId').click();
});
HappyCoder888
fuente
1
En realidad, ahora ES la solución correcta ahora con PhantomJS 2.x
BlaM
3

Nunca pude hacer clic directamente en el elemento. En cambio, miré el html para encontrar qué función se llamó con onclick, y luego llamé a esa función.

usuario984003
fuente
¿Cómo podría encontrar la función y cómo llamarla si se ha adjuntado a través de addEventListener?
Suo6613
2

Document.querySelector (elemento) .click () funciona cuando se usa Phantomjs 2.0

click: function (selector, options, callback) {
    var self = this;
    var deferred = Q.defer();
    options = options || {timeout:1000}; 
    setTimeout(function () { 
        self.page.evaluate(function(targetSelector) {
            $(document).ready(function() {
                document.querySelector(targetSelector).click();
            }) ;
        }, function () {
                deferred.resolve();
        }, selector);
    }, options.timeout);
    return deferred.promise.nodeify(callback);
},
GracefulCode
fuente
2

También es posible hacer doble clic con PhantomJS.

Recomendado

Esto está adaptado de la respuesta de stovroz y desencadena un nativo que dblclickincluye los eventos mousedown, mouseupy click(dos de cada uno).

var rect = page.evaluate(function(selector){
    return document.querySelector(selector).getBoundingClientRect();
}, selector);
page.sendEvent('doubleclick', rect.left + rect.width / 2, rect.top + rect.height / 2);

Otras maneras

Las siguientes dos formas solo desencadenan el dblclickevento, pero no los otros eventos que deberían precederlo.

Adaptado de esta respuesta de torazaburo :

page.evaluate(function(selector){
    var el = document.querySelector(sel);
    var ev = document.createEvent("MouseEvent");
    ev.initMouseEvent(
        'dblclick',
        true /* bubble */, true /* cancelable */,
        window, null,
        0, 0, 0, 0, /* coordinates */
        false, false, false, false, /* modifier keys */
        0 /*left*/, null
    );
    el.dispatchEvent(ev);
}, selector);

Adaptado de esta respuesta de Jobins John :

page.evaluate(function(selector){
    var el = document.querySelector(sel);
    var e = document.createEvent('MouseEvents');
    e.initMouseEvent('dblclick', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    el.dispatchEvent(e);
}, selector);

Guión de prueba completo

Artjom B.
fuente
2

La forma más sencilla es usar jQuery.

page.evaluate(function() {
  page.includeJs("your_jquery_file.js", function() {
    page.evaluate(function() {
      $('button[data-control-name="see_more"]').click();
    });
  });
});
Jiayuan Zhang
fuente
0

Para aquellos que usan JQuery, la interfaz de usuario de JQuery creó una utilidad para simularlos: jquery-simulate . Yo uso esto en PhantomJS y Chrome

$ele..simulate( "click" );
wbdarby
fuente