Ich schreibe einen generischen Web-Scraper mit Selenium 2 (Version 2.33 Python-Bindings, Firefox-Treiber). Es soll eine beliebige URL nehmen, die Seite laden und alle ausgehenden Links melden. Da die URL willkürlich ist, kann ich keinerlei Annahmen über den Inhalt der Seite treffen, so dass der übliche Hinweis (Warten auf ein bestimmtes Element) nicht anwendbar ist.
Ich habe Code, der document.readyState
abfragen soll, bis er "complete" erreicht oder ein 30s-Timeout abgelaufen ist, und fahre dann fort:
Diese Art funktioniert, aber auf etwa einer von fünf Seiten hängt der .until
-Aufruf für immer. Wenn dies passiert, ist der Browser normalerweise nicht in der Lage, die Seite zu laden (der "Throbber" dreht sich immer noch), aber Dutzende von Minuten können verstreichen und das Timeout wird nicht ausgelöst. Aber manchmal scheint die Seite vollständig geladen zu sein und das Skript läuft immer noch nicht.
Was gibt? Wie kann ich die Zeitüberschreitung zuverlässig ausführen? Gibt es eine bessere Möglichkeit, ein Warten auf eine Seite zum Laden anzufordern (wenn man keine Annahmen über den Inhalt machen kann)?
Hinweis: Das obsessive Catching und Ignoring von WebDriverException
hat sich als notwendig erwiesen, um möglichst viele Links von der Seite zu extrahieren, egal ob JavaScript innerhalb der Seite witzige Sachen mit dem DOM macht (zB I verwendet, um "veraltete Element" -Fehler in der Schleife zu erhalten, die die HREF-Attribute extrahiert.)
HINWEIS: Es gibt viele Varianten dieser Frage, sowohl auf dieser Seite als auch anderswo, aber sie haben alle entweder einen subtilen, aber entscheidenden Unterschied, der die Antworten (falls vorhanden) nutzlos macht ich oder ich habe die Vorschläge ausprobiert und sie funktionieren nicht. Bitte beantworten Sie genau die Frage, die ich gestellt habe.
Ich habe eine ähnliche Situation, wie ich das Screenshot-System mit Selenium für einen ziemlich bekannten Website-Service geschrieben habe und die gleiche Zwangslage hatte: Ich konnte nichts über die geladene Seite wissen.
Nachdem wir mit einigen der Selenium-Entwickler gesprochen hatten, war die Antwort, dass verschiedene WebDriver-Implementierungen (Firefox Driver oder IEDriver) unterschiedliche Entscheidungen treffen, wann eine Seite als geladen betrachtet wird oder nicht, damit der WebDriver die Kontrolle zurückgibt.
Wenn Sie sich tief in Selenium-Code vertiefen, können Sie die Punkte finden, die versuchen und die besten Entscheidungen treffen, aber da es eine Reihe von Dingen gibt, die dazu führen können, dass der Zustand fehlschlägt, wie mehrere Frames, wo man nicht Um rechtzeitig fertig zu werden, gibt es Fälle, in denen der Fahrer offensichtlich einfach nicht zurückkehrt.
Mir wurde gesagt, "es ist ein Open-Source-Projekt", und dass es wahrscheinlich nicht für jedes mögliche Szenario korrigiert werden kann / kann, dass ich jedoch Korrekturen vornehmen und Patches gegebenenfalls einreichen kann.
Auf lange Sicht war das ein bisschen viel für mich, so ähnlich wie Sie, ich habe meinen eigenen Timeout-Prozess erstellt. Da ich Java benutze, habe ich einen neuen Thread erstellt, der versucht, bei Erreichen des Timeouts mehrere Dinge zu tun, um WebDriver zurückzugeben, selbst wenn man nur bestimmte Tasten drückt, um den Browser zum Antworten zu bringen. Wenn es nicht zurückkehrt, töte ich den Browser und versuche es erneut.
Das erneute Starten des Treibers hat die meisten Fälle für uns erledigt, als ob das zweite Laden des Browsers es in einen stabileren Zustand versetzt hätte (bedenkt man, dass wir von VMs starten und der Browser ständig nach Updates suchen und laufen will bestimmte Routinen, wenn sie in letzter Zeit nicht gestartet wurde).
Ein weiterer Teil davon ist, dass wir zuerst eine bekannte URL starten und einige Aspekte des Browsers bestätigen und dass wir tatsächlich in der Lage sind, damit zu interagieren, bevor wir fortfahren. Mit diesen Schritten ist die Fehlerrate ziemlich niedrig, etwa 3% mit 1000 Tests in allen Browsern / Versionen / Betriebssystemen (FF, IE, CHROME, Safari, Opera, iOS, Android, etc.)
Zu guter Letzt klingt es für Ihren Fall so, als müssten Sie nur die Links auf der Seite erfassen, nicht die volle Browser-Automatisierung. Es gibt andere Ansätze, die ich in Richtung cURL und Linux-Tools machen könnte.
Die "empfohlene" (aber immer noch hässliche) Lösung könnte sein, explizite Wartezeit :
%Vor%Der naive Versuch wäre etwa so:
%Vor%Ein anderer, besserer wäre (Credits zu @ThomasMarks ):
%Vor%Und das letzte Beispiel beinhaltet das Vergleichen von Seiten-IDs wie unten (was kugelsicher sein könnte):
%Vor%Und jetzt können wir tun:
%Vor%Die obigen Codebeispiele stammen von Harrys Blog .
Soweit ich weiß, macht Ihr readystate_complete
nichts, da driver.get () bereits nach dieser Bedingung sucht. Wie auch immer, ich habe gesehen, dass es in vielen Fällen nicht funktioniert. Eine Sache, die Sie versuchen könnten, ist, Ihren Verkehr durch einen Proxy zu routen und diesen für das Klingeln für irgendeinen Netzwerkverkehr zu verwenden. Dh browsermob hat die Methode wait_for_traffic_to_stop:
Hier ist die Lösung, die von Tommy Beadle (durch Verwendung von Veralterung Ansatz):
%Vor%Ich war mit ähnlichen Problemen konfrontiert und in meinem Setup waren die oben genannten Lösungen nicht ausreichend.
Um ein erfolgreiches Laden der Seite zu erkennen oder um timeout
auf driver.get(URL)
zu erzwingen, verwende ich die folgende Lösung und es funktioniert für mich:
Tags und Links python selenium-webdriver webdriver