Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   TWebBrowser - zwei Formulare nacheinander ausfüllen (https://www.delphipraxis.net/171367-twebbrowser-zwei-formulare-nacheinander-ausfuellen.html)

Marco Steinebach 2. Nov 2012 13:48

TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Hallo zusammen,
Ich möchte mich, mittels TWebBrowser, auf einer Seite einloggen, und, nachdem ich eingeloggt bin, auf der anschließend erscheinenden Seite eine Nummer eingeben.
Bis nach dem einloggen klappt alles ganz prima, nur, wenn ich auf der Folgeseite das Feld für die Nummer ausfüllen will, knallt's.
Kann mir bitte jemand verraten warum?

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  x: variant;
begin
  // br ist meine TWebBrowser-Komponente - mit unveränderten Standardwerten
  br.Navigate ('https://secure.freedomscientific.com/DealerILM/default.asp');
  while br.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;
  x := br.OleObject.document.forms.item('input');
  x.Elements.item('username').value := 'bla';
  x.Elements.item('password').value := 'bla';
  x.Elements.item('agree').click;
  x.submit;
  while br.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;
  // bis hierhin läuft alles ganz prima, und die Seite zur Eingabe der Nummer wird auch angezeigt.
  x := br.OleObject.document.forms.item('input');
  x.Elements.Item('serial').value := '24520';
  // und genau diese Zuweisung verursacht den Fehler.
end;
Viele Grüße
Marco

sx2008 2. Nov 2012 16:11

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Welcher Fehler??

http://www.chiark.greenend.org.uk/~s...m/bugs-de.html

Ich rate jetzt einfach mal - du bekommst eine Zugriffsverletzung, oder?
Wann immer du mit der Funktion Items() ein Objekt holst muss du prüfen ob es überhaupt existiert:
Delphi-Quellcode:
x := br.OleObject.document.forms.item('input');
if not Assigned(x) then
  raise Exception.CreateFmt('Web-Formalar %s nicht gefunden', ['input']);
x.Elements.Item('serial').value := '24520';

Marco Steinebach 2. Nov 2012 17:03

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Joa richtig, ;-), eine Zugriffsverletzung.
Der Tipp mit "assigned" ist schonmal gold wert, mir war nämlich nicht klar, auf was ich prüfen soll.

Kann es sein, daß die Seite noch nicht fertig geladen ist?
Oder anders gefragt: taugt die prüfung in der While-Schleife, oder gibt's 'ne bessere Methode um rauszufinden, wann er mit dem Seitenaufbau fertig ist?

Vielen Dank schonmal und viele Grüße
Marco
p.s.:
Delphi-Quellcode:
  if not assigned (x) then
findet mein Compiler überhaupt nicht witzig, da es "inkompatible Typen" sind - wohl weil's 'ne Variant ist...

sx2008 2. Nov 2012 18:29

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Um darauf zu warten, dass eine Webseite komplett geladen ist würde ich folgenden Code verwenden:
Delphi-Quellcode:
procedure WaitForBrowser(WebBrowser:TWebBrowser);
begin
   while WebBrowser.ReadyState <> READYSTATE_COMPLETE do
   begin
      Application.ProcessMessages;
      Sleep(50);
   end;
end;
Manchmal funktioniert das Submitten eines Webformulars nicht richtig; man kann das so umgehen:
Delphi-Quellcode:
procedure SubmitWebForm(webform:OleVariant);
var
   i : Integer;
   formitem : OleVariant;
   itemtype, itemname : string;
begin
   // Schleife über alle Items eines WebFormulars
   For i:= webform.Length-1 downto 0 do
   begin
      formitem := webform.Item(i);
      itemtype := UpperCase(formitem.Type);
      itemname := UpperCase(formitem.Name);

      // if it's a submit button: click it
      if itemtype = 'SUBMIT' then
      begin
         formitem.Click;
         Exit;
      end
      else if (itemtype='BUTTON') and (itemname='SUBMIT') then
      begin
         formitem.Click;
         Exit;
      end
   end;

   // try default submit Method
   webform.submit;
end;
Um zu prüfen, ob ein Variant ein Dispatch-Interface enthält:
Delphi-Quellcode:
function VarIsDispatchObject(const v : Variant): Boolean;
var
   vt : Integer;
begin
   vt := VarType(v) and not varByRef;
   Result := (vt = varDispatch);
end;
Damit sieht der Test so aus:
Delphi-Quellcode:
x := br.OleObject.document.forms.item('input');
if not VarIsDispatchObject(x) then
  raise Exception.CreateFmt('Web-Formalar %s nicht gefunden', ['input']);
x.Elements.Item('serial').value := '24520';

MuTzE.Y85 3. Nov 2012 13:26

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Ich mache das mit dem Warten immer so:
Code:
 repeat
   Application.ProcessMessages;
 until
   ((Browser.ReadyState = READYSTATE_COMPLETE) and (Browser.Busy = False));

Auf alle Fälle würde ich kein Sleep nehmen.

Hier wäre noch eine Variante:
Code:
procedure Delay(ATime: Integer);
var
 Start : Integer;
begin
 Start := GetTickCount;
 repeat
  Application.ProcessMessages;
 until
  (GetTickCount - Start) > ATime;
end;


 repeat
   Delay(100);
 until
   ((Browser.ReadyState = READYSTATE_COMPLETE) and (Browser.Busy = False));

sx2008 3. Nov 2012 14:15

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Zitat:

Zitat von MuTzE.Y85 (Beitrag 1189571)
Auf alle Fälle würde ich kein Sleep nehmen.

Doch, genau das ist nötig.
Sleep gibt die Kontrolle an andere Prozesse ab, was ja genau das ist was während des Wartens auf den Internet Explorer gebraucht wird.
Ohne Sleep würde die eigene Anwendung bis zu 100% Prozent (50% bei Dual-Core) an Rechenleistung unnötigerweise verbrauchen.
Wer's nicht glaubt und selber testen möchte:
* neues Projekt anlegen
* neuen Button auf's Formular
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
   while not Application.Terminated do
      Application.ProcessMessages;
end;
Der Nachteil von sleep(50) ist, dass die Reaktionszeit auf Mausklicks, Tastendrücke um bis zu 50ms verzögert wird, aber diese Verzögerung ist so kurz, dass sie nicht zu spüren ist.
Des weiteren könnte der Webbrowser schon fertig geladen haben aber die eigene Anwendung bekommt dies erst nach 50ms mit.
Auch das ist kein Beinbruch; im Gegenteil, wenn die Webseite komplett geladen ist sollte man dem Browser besser noch etwas Zeit geben eventuelle Java-Scripts abzuarbeiten.

MuTzE.Y85 3. Nov 2012 14:42

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
OK, ich hab es ausprobiert, überzeugt ;)

Marco Steinebach 3. Nov 2012 18:26

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Hallo,
und erstmal vielen Dank für die raschen Antworten.
Dank deines Codes Sx2008 bin ich dem Problem auf die Spur gekommen. Wenn ich nacheinander auf die Elemente des Forms zugreife, muß ich feststellen, daß es mein Feld "serial" gar nicht gibt, obwohl es angezeigt wird. Hä?
Könnte das ein Cache-Problem oder so sein? Und wenn, wie kann man das Lösen?
Sowas blödes, ich dachte,daß, was angezeigt wird ist auch daß, auf das ich via b.OleObject... zugreifen kann....
Viele Grüße
Marco

Sir Rufo 3. Nov 2012 19:53

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Es hilft doch sich den HTML-Code anzusehen ... oder?

Marco Steinebach 3. Nov 2012 20:00

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1189590)
Es hilft doch sich den HTML-Code anzusehen ... oder?

Joa, aber immer doch. Und ruft man mit dem Internet-Explorer die Seite auf, loggt sich ein, erhält man, nachdem man auf Submit geklickt hat, eine Seite, auf der unter "ansicht | Quelltext" ein Feld namens "serial" zu finden ist.
Also dachte ich, bistde schlau, logstde dich ein und greifst, nachdem dein Programm auf "submit" gteklickt hat, eben auf dieses Feld zu. Aber genau das gibt's im Quelltext nicht, obwohls angezeigt wird, und mir ist nicht klar, wieso das so ist.
Kann natürlich sein, daß die Seite, via Script oder sonstwie, die Formulare aufbaut, keine Ahnung, ich hab die Seite nicht programmiert.
Vielleicht hat ja jemand 'ne idee?
Viele Grüße
Marco

Sir Rufo 3. Nov 2012 21:02

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Seltsam, wenn es angezeigt wird, dann muss es auch im Quelltext vorhanden sein ...

Im Anhang habe ich ein kleines Testprogramm mit einem TWebBrowser.
Damit bis auf die Seite surfen und dann auf dem Analyzer-Tab auf "Untersuchen" klicken.
Jetzt sollten dort alle Form-Elemente (INPUT, TEXTAREA, SELECT, BUTTON) aufgelistet werden, die es auf der aktuellen Seite gibt.

Schau mal, ob das entsprechende Eingabefeld aufgelistet wird ... wenn es da ist, sollte es auch angezeigt werden.

Die Quellen kann ich dir gerne zur Verfügung stellen, allerdings ist da auch einiges mit Generics drin, so dass dies mit Delphi 5 nicht läuft.

sx2008 3. Nov 2012 23:10

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Eine HTML-Seite kann mehr als ein Web-Formular enthalten.
Am Besten man lässt sich die Struktur in einem TreeView anzeigen.

Delphi-Quellcode:
function VariantIsObject(const value:OleVariant):boolean;
begin
   result := (VarType(value) = varDispatch);
end;


procedure Browser2TreeView(WebBrowser: TWebBrowser; root:TTreeNodes);
var
  i,j, k :Integer;
  FormItem, Element, SubElement: OleVariant;
  child, child2, child3 : TTreeNode;
  s_type : string;

begin
   Assert(Assigned(WebBrowser));
   Assert(Assigned(root));

   root.Clear;
   

  //count forms on document
  for I:=0 to WebBrowser.OleObject.Document.forms.Length -1 do
  begin
    FormItem := WebBrowser.OleObject.Document.forms.Item(I);

    if VariantIsObject(FormItem.Name) then
       child := root.AddChild(nil, 'Form'+IntToStr(i)+': '+FormItem.Name.Name)
    else
       child := root.AddChild(nil, 'Form'+IntToStr(i)+': '+FormItem.Name);
    child.ImageIndex := 3;


    For j:= 0 to FormItem.Length-1 do
    begin
      try
         Element := FormItem.Item(j);
         //when the fieldname is found, try to fill out
         child2 := root.AddChild(child, Element.Name+' = '+Element.Value);

         s_type := lowercase(Element.Type);

         if s_type = 'submit' then
            child2.ImageIndex := 1
         else if s_type = 'text' then
            child2.ImageIndex := 0
         else if s_type = 'file' then
            child2.ImageIndex := 2
         else if s_type = 'hidden' then
            child2.ImageIndex := 4
         else if s_type = 'checkbox' then
            child2.ImageIndex := 5
         else if s_type = 'radio' then
            child2.ImageIndex := 6
         else if s_type = 'select-one' then
            child2.ImageIndex := 7
         else
            child2.ImageIndex := -1;

         child3 := root.AddChild(child2, 'Type='+s_type);
         child3.ImageIndex := -1;


         if s_type = 'text' then
         begin
            child3 := root.AddChild(child2, 'MaxLen='+IntToStr(Element.maxLength));
            child3.ImageIndex := -1;
         end
         else if s_type = 'select-one' then
         begin
            for k := 0 to Element.Options.Length-1 do
            begin
               SubElement := Element.Options.Item(k);
               child3 := root.AddChild(child2, SubElement.Text+ ' = <'+SubElement.Value+'>');
               child3.ImageIndex := -1;
            end;
         end;
      except
        on E:Exception do
         root.AddChild(child, E.Message);
      end;
    end;
  end;

   if root.Count > 0 then
      root.GetFirstNode.Expand(True);
end;

Marco Steinebach 4. Nov 2012 13:43

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Hallo zusammen,
erstmal vielen Dank nochmal für die Hilfe! Super!
Nach etwas gebastel mußte ich feststellen, es ist ein Zeitproblem.
Warte ich nämlich nnicht, wie es ja sinnig ist, bis der Browser fertig ist, und lege dann los, sondern warte einfach 5 Sekunden, funktioniert alles prima.
also
Delphi-Quellcode:
for i := 0 to 100 do
begin
  Application.ProcessMessages;
  Sleep (50);
end;
  x := br.OleObject.document.forms.Item('input');
  x.Elements.Item('serial').value := '24520';
Irgendwie kriegt mein Programm nicht richtig mit, trotz br.ReadyStat, wann die Seite fertig ist. hä?

Hat dazu noch jemand 'ne Idee, weil der Ansatz ist nicht nur dirty, sondern ganz dirty. ;-)

Viele Grüße
Marco

Sir Rufo 4. Nov 2012 13:52

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Auf den WebBrowser wartet man wie folgt:
Delphi-Quellcode:
procedure TMain_View.Browser_WebBrowserDocumentComplete( ASender : TObject; const pDisp : IDispatch;
  const URL : OleVariant );
var
  CurBrowser, TopBrowser : IWebBrowser;
begin
  CurBrowser := pDisp as IWebBrowser;
  TopBrowser := ( ASender as TWebBrowser ).DefaultInterface;
  if CurBrowser = TopBrowser
  then
    begin
      // Jetzt ist das Haupt-Dokument fertig geladen
    end;
end;
Allerdings hat man ein kleines Problem, wenn in der Website noch JavaScript enthalten ist, dass noch weitere Daten nachlädt.

Auch frames (nicht iframes) werden in einem eigenen Kontext geladen. ALso muss man auch hier noch aufpassen.

Marco Steinebach 6. Nov 2012 08:18

AW: TWebBrowser - zwei Formulare nacheinander ausfüllen
 
Hallo Zusammen,
Vielen Dank für eure Hilfe.
Ich denke, diese Seite ist eine definitive Zumutung, denn die Formulare werden, wie auch immer, via Skript aufgebaut. Es gibt also keine wirklich Chance festzustellen, wann die Seite fertig geladen ist.
Ich hab's jetzt schlicht so gemacht, daß ich
1. 3 Sekunden warte
2. warte, bis das gesuchte Formular vorhanden ist (varIsDispatchObject = true) und
3. warte, bis das Feld, das ich suche, da ist.
So funktioniert's - ist nicht sehr schön aber tut, was es soll.

Vielen Dank nochmal und viele Grüße
Marco


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:58 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz