![]() |
auf EdgeBrowser.ExecuteScript warten
Hallo Gemeinde,
kennt jemand einen Weg wie man auf
Delphi-Quellcode:
warten kann?
EdgeBrowser1.ExecuteScript(
'document.documentElement.outerHTML'); Ich benötige das Ergebnis aus ExecuteScript, aber leider kenne ich keine Möglichkeit auf das Ergebnis zu warten bevor ich mit der Weiterverarbeitung starte. Wäre toll wenn mir auch hier jemand helfen könnte. :) Danke. |
AW: auf EdgeBrowser.ExecuteScript warten
Ja, das ist asynchron, aber Du wirst doch benachrichtigt, wenn das Ergebnis da ist und kannst dort weitermachen mit der Verarbeitung.
Also in etwa so:
Code:
Oder warum willst Du aktiv warten?
procedure Step1
Executescript(...) // ruft EdgeBrowserExecuteScript auf, wenn fertig procedure EdgeBrowserExecuteScript Step2; // ruft den nächsten Schritt auf procedure Step2 Weitere Verarbeitung |
AW: auf EdgeBrowser.ExecuteScript warten
Du hast recht, ich hatte gerade Tomaten auf den Augen.
Mein Problem liegt glaub doch etwas anders. Wenn ich in meinem normalen Programmdurchlauf folgende Procedure aufrufe.
Delphi-Quellcode:
Dann bekomme ich in meine kleinen Kontrolle (das Showmessage) ein anderes Ergebnis als wenn ich es manuell über einen Button einen kurzen Moment später nochmal anstoße.
procedure TForm2.EdgeBrowser1ExecuteScript(Sender: TCustomEdgeBrowser;
AResult: HRESULT; const AResultObjectAsJson: string); var json: TJSONValue; begin json := TJSONObject.ParseJSONValue(AResultObjectAsJson); WebsiteContent_SL.Text:=json.AsType<string>; Showmessage(IntToStr(Length(WebsiteContent_SL.Text))); json.Free; DatenAbgreifen; end; ExecuteScript wird bei mir im "EdgeBrowser1NavigationCompleted" ausgeführt. Nun muss ich ja davon ausgehen, dass EdgeBrowser1NavigationCompleted für mich nicht das richtige Ereignis ist. Denn scheinbar ist die Seite ja doch noch nicht vollständig geladen. Ich hoffe ich konnte mich jetzt verständlich ausdrücken.:wink: |
AW: auf EdgeBrowser.ExecuteScript warten
Inwiefern weicht das Ergebnis denn ab?
Es kann natürlich sein, dass das HTML im Browser noch durch Javascript abgeändert wird. Du fragst ja mit document.documentElement.outerHTML nicht den eigentlichen HTML-Quellcode an, der geladen wurde, sondern den aktuellen Stand zum Zeitpunkt der Ausführung. Wenn jetzt Javascript selbst auf das "onload" wartet und Daten nachlädt, sieht das Ergebnis einige Zeit später anders aus. Du kannst allerdings in Javascript selbst auf ein anderes Event warten, z.B. so:
Delphi-Quellcode:
Das Ergebnis bekommst Du dann über
EdgeBrowser1.executescript('document.addEventListener("DOMContentLoaded", (event) => { chrome.webview.postMessage(document.documentElement.outerHTML);});');
Delphi-Quellcode:
Man kann sich über "DOMContentLoaded" auch direkt in Delphi informieren lassen ohne den Umweg über PostMessage, aber so wie im Beispiel bist Du flexibel, verschiedene Zeitpunkte in Javascript auszuprobieren.
procedure TForm2.EdgeBrowser1WebMessageReceived(Sender: TCustomEdgeBrowser;
Args: TWebMessageReceivedEventArgs); var WebMessage: PWidechar; begin args.ArgsInterface.TryGetWebMessageAsString(PWidechar(WebMessage)); showmessage(Webmessage); end; Letztlich könntest Du Dir so auch sparen, den HTML-Code im Nachhinein nochmal mit Python zu parsen. Du kannst die gesuchten Werte direkt per Javascript im Browser auslesen und an Delphi wie oben gezeigt übermitteln, auch im JSON-Format (über args.ArgsInterface.Get_webMessageAsJson). |
AW: auf EdgeBrowser.ExecuteScript warten
gubbe ich bin dir sehr dankbar für deine Hilfe.
Zitat:
Allerdings funktioniert es noch nicht wie es soll. Ich will mir ja auch nicht alles vorkauen lassen, aber ich habe wirklich keinen Plan von JavaScript. Deswegen kann ich es auch nicht wirklich nachvollziehen. Der Grundgedanke ist mir aber klar. So bin ich jetzt vorgegangen: Ich habe jetzt im Objectinspektor im EdgeBrowser1 "ONWebMessageReceived" mit deiner Procedure versehen. Im "TForm2.EdgeBrowser1NavigationCompleted" habe ich folgende Zeile eingefügt.
Delphi-Quellcode:
EdgeBrowser1.ExecuteScript('document.addEventListener("DOMContentLoaded", (event) => { chrome.webview.postMessage(document.documentElement.outerHTML);});');
Eigentlich sollte ja jetzt nach dem die Webmessage kommt das Showmessage aktiv werden. Aber leider tut sich da nix. Jetzt ist die Frage, ob die Message gesendet wird oder ich sie nicht empfange. |
AW: auf EdgeBrowser.ExecuteScript warten
Ich bin da jetzt nicht so fit, aber wer garantiert, dass der Zug in
Delphi-Quellcode:
nicht schon abgefahren ist, also auf Browser-Seite das
TEdgeBrowser.OnNavigationCompleted
Delphi-Quellcode:
schon bereits lange ausgelöst wurde?
DOMContentLoaded
|
AW: auf EdgeBrowser.ExecuteScript warten
Zitat:
So verwende ich das auch nicht und es war erst mal eine Idee, um den richtigen Zeitpunkt zum Auslesen zu finden. Woran es liegt, kann man ja testen.
Delphi-Quellcode:
EdgeBrowser1.ExecuteScript('chrome.webview.postMessage(document.documentElement.outerHTML)');
Dann wird das Postmessage direkt aufgerufen. Kommt die Nachricht an? Wenn ja, ist es tatsächlich so, dass DOMContentLoaded schon aufgerufen wurde, bevor der Eventhandler in OnNavigationCompleted gesetzt werden konnte. Dann müsste man dem zuvorkommen oder das Event in Delphi abfangen. Würde ich dann genauer beschreiben. |
AW: auf EdgeBrowser.ExecuteScript warten
Ich habe es jetzt nochmal in einem frischen Projekt getestet um mögliche Einflüsse auszuschließen.
Dabei bin ich auf
Delphi-Quellcode:
gekommen, was ich bei mir im eigentlichen Projekt drinnen hatte.
EdgeBrowser1.WebMessageEnabled:=true;
Dieses habe ich nun ausgeblendet und dann funktioniert das hier.
Delphi-Quellcode:
Jetzt stellt sich mir aber gerade die Frage, aktiviere ich nicht damit eigentlich Webmessages??? Naja, das scheint auf jeden Fall erstmal ein Grund gewesen zu sein!
EdgeBrowser1.ExecuteScript('window.chrome.webview.postMessage(document.documentElement.outerHTML)');
Jetzt wo ja die Webmassage definitiv empfangen wird, wollte ich nun das hier testen:
Delphi-Quellcode:
und das funktioniert weiterhin nicht.
EdgeBrowser1.ExecuteScript('document.addEventListener("DOMContentLoaded", (event) => { chrome.webview.postMessage(document.documentElement.outerHTML);});');
Also wird jetzt "Der schöne Günther" den Finger schon drauf haben. Wenn nun das
Code:
zu spät ist, wann ist es dann sinnvoll das "ExecuteScript" zu starten.
TEdgeBrowser.OnNavigationCompleted
|
AW: auf EdgeBrowser.ExecuteScript warten
Das
Delphi-Quellcode:
funktioniert bei mir auch nicht. Da gibt es wohl einen Bug beim Setzen der Eigenschaft, vielleicht beim Konvertieren des Delphi-Boolean in den Integer-Wert, den das Interface erwartet. Werde ich mir mal genauer anschauen, denn vielleicht sind noch andere Eigenschaften betroffen.
EdgeBrowser1.WebMessageEnabled:=true;
Aber der Default-Wert ist bereits True, daher müssen wir es hier nicht setzen. Das DOMContentLoaded bringt Dir wohl nichts, wenn es schon ausgelöst wurde, bevor in Delphi TEdgeBrowser.OnNavigationCompleted aufgerufen wird. Das Prinzip, auf etwas zu warten und dann per Javascript das Ergebnis per Postmessage zurückzugeben, funktioniert aber. Man müsste jetzt die Seite genauer kennen und schauen, was sie noch nach dem Laden macht und wann sie tatsächlich fertig ist. Zum Beispiel in Chrome laden und den Entwicklertools genauer reinschauen. Nur zum Test kannst Du aber auch mal eine Verzögerung einbauen, z.B. mit einem Timer in Delphi oder per Javascript:
Delphi-Quellcode:
Ist der Quelltext dann komplett?
EdgeBrowser1.executescript('setTimeout(() => {chrome.webview.postMessage(document.documentElement.outerHTML);}, "2000");');
|
AW: auf EdgeBrowser.ExecuteScript warten
Ich habe jetzt noch ein wenig getestet und versucht. Es sei noch gesagt, dass es nicht nur eine Seite die ich auslesen will. Es sind verschiedene.
Wie "Der schöne Günther" ja schon vermutet hatte, ist der Zug im
Code:
schon abgefahren. Also muss ein Zeitpunkt gefunden werden, wo ich noch auf den Zug aufspringen kann.
EdgeBrowser1NavigationCompleted
Das habe ich jetzt so realisiert:
Delphi-Quellcode:
als nächstes:
procedure TForm2.EdgeBrowser1NavigationStarting(Sender: TCustomEdgeBrowser;
Args: TNavigationStartingEventArgs); begin EdgeBrowser1.ExecuteScript('document.addEventListener("DOMContentLoaded", (event) => { chrome.webview.postMessage(document.documentElement.outerHTML);});'); //EdgeBrowser1.executescript('setTimeout(() => {chrome.webview.postMessage(document.documentElement.outerHTML);}, "2000");'); end;
Delphi-Quellcode:
hierbei lasse ich ja jetzt aber das hier vollkommen aus:
procedure TForm2.EdgeBrowser1WebMessageReceived(Sender: TCustomEdgeBrowser;
Args: TWebMessageReceivedEventArgs); var WebMessage: PWidechar; begin args.ArgsInterface.TryGetWebMessageAsString(PWidechar(WebMessage)); //showmessage(Webmessage); WebsiteContent_SL.Text:=WebMessage; //TFile.writeAllText('Quelltext.txt', WebsiteContent_SL.Text, TEncoding.UTF8); DatenAbgreifen; end;
Delphi-Quellcode:
Kann ich denn auch bei dem
procedure TForm2.EdgeBrowser1ExecuteScript(Sender: TCustomEdgeBrowser;
AResult: HRESULT; const AResultObjectAsJson: string); var json: TJSONValue; //neu begin json := TJSONObject.ParseJSONValue(AResultObjectAsJson); WebsiteContent_SL.Text:=json.AsType<string>; Showmessage(IntToStr(Length(WebsiteContent_SL.Text))); //TFile.writeAllText('Quelltext.txt', WebsiteContent_SL.Text, TEncoding.UTF8); json.Free; //DatenAbgreifen; end;
Code:
schon an das JsonObject kommen?
EdgeBrowser1WebMessageReceived
|
AW: auf EdgeBrowser.ExecuteScript warten
Ist "NavigationStarting" nicht viel zu früh?
Hier ist eine schöne Grafik, die den Ablauf zeigt: ![]() An der Stelle ist ja noch gar nichts geladen und man kann die Navigation sogar noch verhindern. Es würde mich wundern, wenn man hier per Javascript schon Event-Handler setzen könnte. Theoretisch müsste das Script noch im Kontext der vorherigen Seiten ausgeführt werden. Wenn Du aber erfolgreich eine Rückmeldung kriegst, hast Du vielleicht Glück und die Scriptausführung wird verzögert bis zum Laden der Seite. Muss ich auch mal ausprobieren. In der Grafik sieht man aber auch, dass NavigationCompleted nach DomContentloaded aufgerufen wird. Mein Beispiel mit DomContentloaded war hier also nicht sehr hilfreich, auch wenn es bei meinem Test funktionierte. Also eigentlich wäre NavigationCompleted in Delphi das passende Ereignis, um den Quelltext auszulesen, da hier auch schon Bilder, Scripte etc. geladen sind. Wobei man nur für das Auslesen des Quelltextes evtl. gar nicht möchte, dass Bilder geladen werden, aber das ist ein anderes Thema. Man könnte auch direkt über einen HTTP-Aufruf den Quelltext lesen. Den Browser nutzt man, wenn man man einen Benutzer simulieren muss oder damit Javascript ausgeführt wird. Nur ist in NavigationCompleted zwar alles geladen, aber die Scripte starten teilweise auch erst dann, wenn sie z.B. auf "OnLoad" im Browser warten oder asynchron geladen werden. Aber um die letzte Frage zu beantworten: Das JSON-Objekt brauchst Du hier ja nicht, weil nur ein String übermittelt wird. Es wäre aber möglich, auch JSON-Daten zu senden und in WebmassageReceived mit args.ArgsInterface.Get_webMessageAsJson auszulesen. Die PN mit den Beispielwebseiten habe ich erhalten und schaue sie mir später an. |
AW: auf EdgeBrowser.ExecuteScript warten
Du hattest natürlich recht, "NavigationStarting" ist zu früh. Das hatte auch nur bei den meisten Webseiten geklappt. Aber meiner "Problemwebseite" auch nicht.
OK, ich habe es jetzt nach deinem letzten Post nochmal umgestellt. Jetzt sieht es so aus:
Delphi-Quellcode:
procedure TForm2.EdgeBrowser1NavigationCompleted(Sender: TCustomEdgeBrowser;
IsSuccess: Boolean; WebErrorStatus: TOleEnum); begin if IsSuccess then begin StatusBar1.Panels[0].Text := BoolToStr(IsSuccess); EdgeBrowser1.executescript('setTimeout(() => {chrome.webview.postMessage(document.documentElement.outerHTML);}, "2000");'); end else begin Showmessage('Navigation nicht beendet'); end; end;
Delphi-Quellcode:
Diese Procedure habe ich entfernt!
procedure TForm2.EdgeBrowser1ExecuteScript(Sender: TCustomEdgeBrowser;
AResult: HRESULT; const AResultObjectAsJson: string); var json: TJSONValue; //neu begin json := TJSONObject.ParseJSONValue(AResultObjectAsJson); WebsiteContent_SL.Text:=json.AsType<string>; json.Free; end;
Delphi-Quellcode:
procedure TForm2.EdgeBrowser1WebMessageReceived(Sender: TCustomEdgeBrowser;
Args: TWebMessageReceivedEventArgs); var WebMessage: PWidechar; begin args.ArgsInterface.TryGetWebMessageAsString(PWidechar(WebMessage)); WebsiteContent_SL.Text:=WebMessage; DatenAbgreifen; end; Der aktuelle stand ist, das alles funktioniert.
Delphi-Quellcode:
die Zeile richtig eingesetzt und es hat gepasst.
EdgeBrowser1.executescript('setTimeout(() => {chrome.webview.postMessage(document.documentElement.outerHTML);}, "2000");');
|
AW: auf EdgeBrowser.ExecuteScript warten
Prima, dass es so klappt. Einfach 2 Sekunden zu warten ist natürlich nicht optimal, denn je nach Netzwerkverbindung kann es auch mal länger dauern, bis die Seite vollständig geladen ist. Oder es geht schneller und man verliert Zeit mit warten.
Deine Beispielseite habe ich mir angeschaut. Die verwendet tatsächlich ein Javascript-Framework (Angular) und lädt Daten dynamisch nach. Der Vorgang startet auch erst im Event "DomContentloaded", daher ist das zu früh, um die Daten auszulesen. Eigentlich ist die Verwendung einer API ja ideal, weil man die Daten dann gleich dort abgreifen könnte, ohne sie umständlich aus dem Browser auszulesen. Das erfordert aber natürlich einen ganz anderen Ansatz. Sollte man eine Geschäftsbeziehung zu dem Anbieter haben, könnte man ja auch den offiziellen Weg gehen und nach einem API-Zugang fragen. Aber nehmen wir mal an, das ist nicht möglich und möchte die Daten per Browser auslesen. Dann müsste man in NavigationCompleted ein Script ausführen, das wartet, bis die gesuchten Elemente erzeugt wurden und den HTML-Quelltext dann auslesen. Hier ein Beispiel:
Delphi-Quellcode:
Und die Datei script.js, die im Exe-Verzeichnis von Delphi liegen muss:
procedure TForm2.EdgeBrowser1NavigationCompleted(Sender: TCustomEdgeBrowser;
IsSuccess: Boolean; WebErrorStatus: TOleEnum); var Script: string; begin Script := TFile.ReadAllText('script.js', TEncoding.UTF8); EdgeBrowser1.executescript(Script); end;
Code:
Die Klasse "productrow" muss man natürlich anpassen an die Klasse der gesuchten Daten.
function waitForElements() {
var elements = document.getElementsByClassName('productrow'); if (elements.length > 0) { chrome.webview.postMessage(document.documentElement.outerHTML); } else { setTimeout(waitForElements, 500); } } waitForElements(); Natürlich ist noch der Fall zu berücksichtigen, dass keine Elemente erzeugt werden, weil eine Suche gar keine gefunden hat. Das muss eben individuell an die Seite angepasst werden. Außerdem könnte man jetzt, nachdem man sowieso schon nach einzelnen HTML-Elementen sucht, diese auch gleich statt des gesamten Quelltextes an Delphi liefern und sich so die weitere Verarbeitung über Python sparen. |
AW: auf EdgeBrowser.ExecuteScript warten
Nein, es ist nicht unbedingt optimal die 2 Sekunden zu warten. Aber bei mir spielt es jetzt keine Rolle. Wichtig ist nur das es funktioniert.
Und auch hier gebe ich dir recht. Die Verwendung einer API wäre natürlich der bessere Weg, aber für den überschaubaren Einsatz meiner Anwendung wäre das zu viel Aufwand (Absprachen Berechtigungen usw.) Der Ansatz für die zusätzliche .JS klingt sehr interessant. Dies würde dann aber wirklich sehr speziell auf diese Webseite passen. Ich versuche aber mit dem Ansatz den ich jetzt habe erstmal alles zu erschlagen was da noch kommt. Wie gesagt. Mein Projekt wird nur Zeitlich begrenzt benötigt, deswegen will ich auch nicht zu viel Energie hineinstecken. Ich bin dir auf jeden Fall sehr dankbar für deine Hilfe und Geduld.:cheers: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:50 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz