PhantomJS; kliknij element

81

Jak kliknąć element w PhantomJS?

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

To daje mi błąd „undefined is not a function ...”

Jeśli zamiast tego

 return document.getElementById('idButtonSpan');

a następnie wydrukuj,

następnie wypisuje [obiekt obiektu], więc element istnieje.

Element działa jak przycisk, ale w rzeczywistości jest to tylko element span, a nie dane wejściowe przesyłania.

Udało mi się uzyskać ten przycisk, aby pracować z Casperem, ale Casper miał inne ograniczenia, więc wróciłem do PhantomJS.

user984003
źródło
28
Czas przyjąć odpowiedź.
Istnieją 3 odpowiedzi korzystające z funkcji „dispatchEvent”, 2 używające „sendEvent”, jedna praktycznie bezużyteczna i jedna, która powinna być komentarzem.
redbeam_
Nie zapomnij o znaku # ...
GracefulCode
Dlaczego nikt jeszcze nie zauważył, że click()w DOM API w ogóle nie istnieje, prawdopodobnie widzieliście to w jQuery lub innej bibliotece tego typu?
YemSalat
4 lata później: odpowiedź przyjęta! Uciekłem od PhantomJS, więc nie mogłem zweryfikować odpowiedzi. Ale zaakceptuję, że 58 głosów za jest poprawnych :) @torazaburo
user984003

Odpowiedzi:

68

.click()nie jest standardem. Musisz utworzyć wydarzenie i wysłać je:

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

źródło
9
Zawijanie za elpomocą jQuery daje tę definicję kliknięcia. Będzie działać w Twojej przeglądarce i Phantom. $(el).click()
Bluu
3
omg łzy radości, po prawie 12 godzinach ciągłej walki z tym! niuch niuch!
user1323136
1
Dla mnie też zadziałało dobrze, ale należy pamiętać, aby nie wychodzić z PhantomJS zbyt wcześnie, zanim przetwarzanie zostanie zakończone. Potrzebowałem krótkiego skryptu, aby kliknąć jeden przycisk i wyjść. To nie zadziałałoby, dopóki nie wywołałem phantom.exit () z poziomu page.onLoadFinished = function () {...};
gregko
document.querySelector (element) .click () działa dla mnie dobrze.
GracefulCode
Aby pracować z niestandardowymi kontrolkami, musiałem stworzyć bardziej skomplikowane rozwiązanie z 3 zdarzeniami: funkcja triggerMouseEvent (elm, eventType) {var ev = document.createEvent ("MouseEvent"); ev.initMouseEvent (eventType, true / * bubble /, true / cancellable /, window, null, 0, 0, 0, 0, / współrzędne / false, false, false, false, / klawisze modyfikujące * / 0 / * left * /, zero ); elm.dispatchEvent (ev); } function click (elm) {triggerMouseEvent (elm, 'mousedown'); triggerMouseEvent (elm, 'mouseup'); triggerMouseEvent (elm, 'kliknięcie'); }
a-bobkov
34

Alternatywnie do odpowiedzi @ torazaburo, możesz HTMLElement.prototype.clickzgubić podczas uruchamiania w PhantomJS. Na przykład używamy PhantomJS + QUnit do uruchamiania naszych testów, aw naszym qunit-config.jsmamy coś takiego:

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
źródło
1
Uwaga, że ​​korzystam z Karmy 0.12.17 z PhantomJs 1.9.7-14. Nie ma window._phantomobiektu, więc właśnie usunąłem ten stan i działało zgodnie z oczekiwaniami.
BradGreens,
Zastanawiam się, czy funkcja powinna akceptować parametry w celu ustawienia różnych współrzędnych dla MouseEvent
ffflabs
16

To nie jest ładne, ale używam tego, aby umożliwić mi użycie jQuery do wyboru:

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

ale zawsze możesz zastąpić $(s)[0]je, document.querySelector(s)jeśli nie używasz jQuery.

(Zależy to od elementu, który jest w widoku, tj. Twój viewportSize.height jest wystarczająco duży).

stovroz
źródło
2
Wypróbowałem wszystkie możliwe podejścia i jest to jedyna opcja, która zadziałała, gdy próbowałem kliknąć tr.
Kai
Pracowałem na phantomjs 1.9.0 i z elementem <a>
redbeam_
1
najlepsze rozwiązanie imo,+1
Flash Thunder
10

Mam nadzieję, że poniższa metoda będzie przydatna. U mnie zadziałało w wersji 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;
});

To zadziałało dla mnie. Mam nadzieję, że przyda się to również innym

Jobins John
źródło
@Jobins john whats waitforload = true?
Qadir Hussain
1
@QadirHussain W rzeczywistości czeka na całkowite załadowanie strony. To prawie jak ustawienie konkretnego czasu na załadowanie strony.
Jobins John
6

Gdy 1.9.2to zadziałało, zostały uruchomione moduły obsługi kliknięć:

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

page.sendEvent('click', a.offsetLeft, a.offsetTop);
sshaw
źródło
Nie dotyczy wszystkich elementów. Na przykład <a> go nie ma. Na guzikach jest tam.
unludo
6

użyj prostego JavaScript z evaluateczymś takim:

page.evaluate(function() {
    document.getElementById('yourId').click();
});
HappyCoder888
źródło
1
Właściwie to jest teraz poprawne rozwiązanie teraz z PhantomJS 2.x
BlaM
3

Nigdy nie udało mi się bezpośrednio kliknąć elementu. Zamiast tego spojrzałem na kod HTML, aby znaleźć funkcję, która została wywołana za pomocą onclick, a następnie wywołałem tę funkcję.

user984003
źródło
jak możesz znaleźć tę funkcję i jak ją nazwać, jeśli została dołączona przez addEventListener?
Suo6613,
2

Document.querySelector (element) .click () działa podczas korzystania z 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
źródło
2

W PhantomJS możliwe są również podwójne kliknięcia.

Zalecana

To jest adaptacją odpowiedź z stovroz i wyzwala rodem dblclickw tym mousedown, mouseupa clickwydarzenia (dwa od siebie).

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

Inaczej

Poniższe dwa sposoby uruchamiają tylko dblclickzdarzenie, ale nie inne zdarzenia, które powinny je poprzedzać.

Zaczerpnięte z tej odpowiedzi z 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);

Zaczerpnięte z tej odpowiedzi z Jobins Jana :

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

Pełny skrypt testowy

Artjom B.
źródło
2

Najłatwiej jest użyć jQuery.

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

Dla tych, którzy używają JQuery, interfejs użytkownika JQuery stworzył narzędzie do ich symulacji: jquery-simulate . Używam tego w PhantomJS i Chrome

$ele..simulate( "click" );
wbdarby
źródło