PhantomJS; Klicken Sie auf ein Element


81

Wie klicke ich auf ein Element in PhantomJS?

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

Dies gibt mir einen Fehler "undefiniert ist keine Funktion ..."

Wenn ich stattdessen

 return document.getElementById('idButtonSpan');

und dann drucken,

dann druckt es [Objekt Objekt], so dass das Element existiert.

Das Element fungiert als Schaltfläche, ist jedoch nur ein span-Element und keine Übermittlungseingabe.

Ich konnte diesen Button klicken, um mit Casper zu arbeiten, aber Casper hatte andere Einschränkungen, so dass ich zurück zu PhantomJS bin.


28
Zeit, eine Antwort anzunehmen.

Es gibt 3 Antworten, die die Funktion "dispatchEvent" verwenden, 2, die "sendEvent" verwenden, eine, die praktisch nutzlos ist und eine, die ein Kommentar sein sollte.
redbeam_

Vergessen Sie nicht das # Zeichen ...
GracefulCode

Warum hat noch niemand darauf hingewiesen, dass click()es in der DOM-API überhaupt nicht existiert, Sie haben es wahrscheinlich in jQuery oder einer solchen Bibliothek gesehen?
YemSalat

4 Jahre später: Antwort angenommen! Ich bin von PhantomJS weggekommen und konnte die Antwort nicht überprüfen. Aber ich werde akzeptieren, dass 58 Upvotes korrekt sind :) @torazaburo
user984003

Antworten:


68

.click()ist nicht Standard. Sie müssen ein Ereignis erstellen und versenden:

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);
}

9
Umwickeln elmit jQuery gibt Ihnen diese defn von Klick. Es wird in Ihrem Browser und in Phantom funktionieren. $(el).click()
Bluu

3
omg Freudentränen, nach fast 12 Stunden ununterbrochenem Kampf damit! schnüffeln schnüffeln!
user1323136

1
Hat auch für mich gut funktioniert, aber man muss daran denken, PhantomJS nicht zu früh zu beenden, bevor die Verarbeitung abgeschlossen ist. Ich brauchte ein kurzes Skript, um nur auf eine Schaltfläche zu klicken und zu beenden. Dies würde für mich nicht funktionieren, bis ich phantom.exit () innerhalb von page.onLoadFinished = function () {...} aufgerufen habe.
Gregko

document.querySelector (element) .click () funktioniert für mich einwandfrei.
GracefulCode

Um mit benutzerdefinierten Steuerelementen arbeiten zu können, musste ich eine kompliziertere Lösung mit drei Ereignissen erstellen: function triggerMouseEvent (elm, eventType) {var ev = document.createEvent ("MouseEvent"); ev.initMouseEvent (eventType, true / * buble /, true / cancelable /, Fenster, null, 0, 0, 0, 0, / Koordinaten / false, false, false, false, / Modifikatortasten * / 0 / * left * /, Null ); elm.dispatchEvent (ev); } function click (elm) {triggerMouseEvent (elm, 'mousedown'); triggerMouseEvent (Ulme, 'mouseup'); triggerMouseEvent (Ulme, 'Klick'); }
a-bobkov

34

Alternativ zur Antwort von @ torazaburo können Sie HTMLElement.prototype.clickbeim Ausführen in PhantomJS einen Stub ausführen. Zum Beispiel verwenden wir PhantomJS + QUnit, um unsere Tests durchzuführen, und in unserem qunit-config.jshaben wir ungefähr Folgendes :

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);
    };
  }
}

1
Ein Hinweis, dass ich Karma 0.12.17 mit PhantomJs 1.9.7-14 verwende. Da es kein window._phantomObjekt gibt, habe ich diesen Zustand einfach entfernt und es hat wie erwartet funktioniert.
BradGreens

Ich frage mich, ob die Funktion Parameter akzeptieren sollte, um unterschiedliche Koordinaten für das MouseEvent
ffflabs

16

Es ist nicht schön, aber ich habe dies verwendet, um jQuery für die Auswahl zu verwenden:

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

aber man kann immer ersetzen $(s)[0]mit , document.querySelector(s)wenn nicht jQuery verwenden.

(Es hängt davon ab, ob das Element im Blickfeld ist, dh Ihr Ansichtsfenster. Die Höhe ist groß genug.)


2
Versuchte alle möglichen Ansätze und dies ist die einzige Option, die für mich beim Klicken funktioniert hat tr.
Kai

Arbeitete an Phantomjs 1.9.0 und mit einem <a> -Element
redbeam_

1
die beste Lösung imo,+1
Flash Thunder

10

Hoffe, die folgende Methode wird nützlich sein. In Version 1.9 hat es bei mir funktioniert

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;
});

Das hat bei mir funktioniert. Hoffe, dass dies auch für andere nützlich sein wird


@Jobins John Was ist Waitforload = wahr?
Qadir Hussain

1
@QadirHussain Es wartet tatsächlich darauf, dass die Seite vollständig geladen wird. Es ist fast so, als würde man eine bestimmte Zeit zum Laden der Seite einrichten.
Jobins John

6

Damit 1.9.2funktionierten für mich Klick-Handler:

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

page.sendEvent('click', a.offsetLeft, a.offsetTop);

Es ist nicht auf allen Elementen. Zum Beispiel hat <a> es nicht. Auf Knöpfen ist es da.
Unludo

6

Verwenden Sie einfaches JavaScript mit evaluate:

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

1
Eigentlich ist es jetzt die richtige Lösung mit PhantomJS 2.x
BlaM

3

Ich konnte das Element nie direkt anklicken. Stattdessen habe ich mir den HTML-Code angesehen, um herauszufinden, welche Funktion mit onclick aufgerufen wurde, und dann diese Funktion aufgerufen.


Wie können Sie die Funktion finden und wie rufen Sie sie auf, wenn sie über addEventListener angehängt wurde?
Suo6613

2

Document.querySelector (Element) .click () funktioniert bei Verwendung von 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);
},

2

Doppelklicks sind auch mit PhantomJS möglich.

Empfohlen

Dies ist aus angepasst der Antwort von stovroz und löst einen nativen dblclickeinschließlich der mousedown, mouseupund clickEreignisse (je zwei).

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);

Andere Möglichkeiten

Die folgenden zwei Möglichkeiten lösen nur das dblclickEreignis aus, nicht jedoch die anderen Ereignisse, die davor stehen sollten.

Angepasst an diese Antwort von 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);

Angepasst an diese Antwort von 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);

Vollständiges Testskript


2

Am einfachsten ist die Verwendung von jQuery.

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

0

Für Benutzer von JQuery hat die JQuery-Benutzeroberfläche ein Dienstprogramm erstellt, um diese zu simulieren: jquery-simulate . Ich benutze dies in PhantomJS und Chrome

$ele..simulate( "click" );
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.