Python Selenium auf Input klicken?
Hallo,
folgender Code:
<div class="block-receipt">
<div class="div-block-8">
<input type="file" size="20" name="receipt-3" id="receipt" class="input-file w-input" accept="image/*, application/pdf" required="" style="overflow: hidden;">
<a href="#" class="receipt-button w-button"> hochladen</a>
<div style="margin-top: 0px;margin-bottom: 0px;text-align: center;" class="text-block-3">
<strong>(Maximal </strong>
</div>
</div>
</div>
Nun würde ich gerne mit Selenium automatisch auf das Element klicken lassen, damit sich das das "Dateiauswählfenster" öffnet. Ohne alles hinzuschreiben:
driver.find_elements_by_xpath("//*[contains(text(), 'Kassenbon hochladen')]").click()
Dies und viele weitere Versuche führen zur Fehlermeldung:
AttributeError: 'list' object has no attribute 'click'
und viele weitere.
Wie lautet denn ein funktionierender Code, um das Element klicken zu lassen?
Danke
P.S.: Anstatt "Kassenbon hochladen", müsste es " hochladen" heißen.
Funktioniert bei jemandem das ganze auch nicht, wenn man nur: <input id = "test "type="file"> hat und dann mit driver.get_element_by_id("test").click() zu clicken versucht?
2 Antworten
Zunächst hierzu:
AttributeError: 'list' object has no attribute 'click'
Dieser Fehler ist logisch. Wenn du find_elements_by_xpath verwendest, darfst du auch erwarten, dass eine Ergebnisliste zurückgeliefert wird. Egal, ob diese nun einen Eintrag enthält oder mehrere. Um nun einen Klick auf eines der gefundenen Elemente auszuführen, müsstest du dieses erst aus der Liste holen. Stelle zuvor stets sicher, dass das Element überhaupt existiert. Wolltest du bspw. das zweite Element erhalten, wäre es ratsam, erst zu prüfen, ob es denn zwei Elemente in der Liste gibt:
elements = driver.find_elements_by_xpath("...")
if len(elements) > 1:
second_element = elements[1]
# do something ...
Wenn dich prinzipiell nur das erste Vorkommen interessiert, nutze find_element_by_xpath.
Funktioniert bei jemandem das ganze auch nicht, (...)
Ich habe es an deinem speziellen Anwendungsfall einmal getestet (mit ChromeDriver Version 92, um genau zu sein). Die Notwendigkeit für einen XPath-Selektor habe ich nicht gesehen, da das Element schon eindeutig mit einer ID gekennzeichnet ist, die zudem nur einmal auf der Seite vorkommt (wie ich dir ja schon bei deiner anderen Frage schrieb, ist das bei dieser Seite nicht unbedingt selbstverständlich).
Dem Element muss nur der Pfad via send_keys übermittelt werden.
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://gruenkraft-zufriedenheit.de/")
element = driver.find_element_by_id("receipt")
element.send_keys(r"C:\path\to\some\file.txt")
Nach Ausführung färbt sich der Button auf der Seite grün und gibt über sein Label bekannt, dass ein Upload stattgefunden hat.
Eine Klickaktion auf ein File-Input hingegen funktioniert nicht, da der Browser in diesem Zuge auch die Auswahl eines Dateipfads erwartet. Dieser Prozess (der Dateiauswahldialog) wird allerdings von deinem Betriebssystem gesteuert, nicht vom Webbrowser. Somit besteht auch für Selenium keine Möglichkeit, diesen Dialog händisch zu bedienen, so wie du es als normaler Nutzer tun würdest. Stattdessen wird eine Fehlermeldung erscheinen, die sich über ein invalides / fehlendes Argument (den erwarteten Dateipfad) beschweren wird. Die click-Methode kann dieses nicht liefern. Sinnigerweise gibt es dafür keine Überladung.
Mach's doch einfach per Klassen-Name, oder per ID.
driver.find_element_by_class_name('receipt-button').click()
Versuchs mal mit dem Code aus meiner Antwort. Vlt. hattest du dich einfach verschrieben.
Ist die Fehlermeldung vlt. etwas länger/genauer als 'Invalid Argument'?
Und sicher dass es sich auf genau die Zeile mit meinem Code bezieht?
An meinem Code ist nämlich eigentlich nichts falsch..
in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidArgumentException: Message: invalid argument
Das sollte zwar kommen wenn man mehrere Klassen eingibt, also z.B.
find_element_by_class_name("receipt-button w-button")
aber bei einer einzigen Klasse ("receipt-button") eigentlich nicht... Weird.
Hab ich auch schon ausprobiert, geht aber irgendwie nicht. Mir geht es eigentl. ja nur darum, dass das Dateiauswähl Menü sich selbstständig öffnet...
Die Website: GrünKraft Zufriedenheit (gruenkraft-zufriedenheit.de) Der Button: Kassenbon hochladen
Also bei dem Code-Ausschnitt, den du geschickt hast, macht der Anker (<a>) garnichts, und man müsste auf das input-Element klicken.
Ok, jo, dann hatte ich recht.
Du musst den INPUT anklicken, nicht den Anchor-Tag.
driver.find_element_by_id('receipt').click()
Hab es mit deinem Code ausprobiert ==> invalid argument
Hab jetzt selbst einen kurzen Code mit input typ = file geschrieben und auch da kommt diese Fehlermeldung. Kommt bei dir auch so was, wenn du nur ein inputfeld für files hast plus id und dann die von dir geschr. Codezeile anwendest?
Hab leider kein Selenium und bin auch grad zu Faul das extra zu downloaden etc xD
Kanns mir bei dir mal über Discord anschauen wenn du willst xD
Für WebScraping hab ich immer BeautifulSoup und Requests benutzt
Hab gerade leider kein Discord mehr drauf und meine Internetverbindung spackt auch wieder rum.
Was mich nur wundert ist, dass die click() Methode für so ziemlich jedes Input Feld funktioniert. Sobald ich aber den Typ zu typ="file" umändere, war´s das dann. Komisch.
Dann kann Selenium vermutlich einfach keinen File-Dialog öffnen.
Dann musst du die Datei so hochladen:
driver.find_element_by_id("receipt").send_keys(os.getcwd()+"/deineDatei.png")
Bei anderen(Stackoverflow) scheint es aber zu funktionieren:How to upload file with Python + Selenium - Stack Overflow
Nö, da wird die selbe Lösung vorgeschlagen die ich dir grad gezeigt hab xD
You can try to locate the hidden input and type into it. (-> send_keys)
und
driver.find_element_by_id("IdOfInputTypeFile").send_keys(os.getcwd()+"/image.png")
Ok, dann dir noch einen schönen Abend und danke für die Hilfe!
War das die Lösung?
Klappt's jetzt? :D
Weil dann besser ich meine Antwort aus, für jeden der zukünftig das Problem hat xD
Nope, aber "hoffe" mal, dass Selenium diesen Input Typ einfach noch nicht implementiert bekommen hat...
Hab ich schon, aber dann passiert nichts und es kommt die Meldung: "invalid argument".