AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi DIV classes mit getElementByID auslesen
Thema durchsuchen
Ansicht
Themen-Optionen

DIV classes mit getElementByID auslesen

Ein Thema von Ajintaro · begonnen am 19. Mai 2014 · letzter Beitrag vom 22. Mai 2014
Antwort Antwort
Benutzerbild von Ajintaro
Ajintaro

Registriert seit: 20. Okt 2004
Ort: Sankt Augustin
138 Beiträge
 
Delphi XE6 Starter
 
#1

DIV classes mit getElementByID auslesen

  Alt 19. Mai 2014, 13:49
Hi DP !

Ich möchte folgende, immer gleich aufgebaute HTML Struktur auslesen:

Code:
<div class="FFT_header">[B]29Apr14 15:30[/B]<span class="FFT_header_for_name">[B]Tom Jerry[/B]</span>
<br>
<span class="FFT_header_group">[B]Delphi Praxis Team[/B]</span>
</div>
<div class="fftText">
<pre>[B]Lorem Ipsum[/B]<br></pre>
</div>

<div class="FFT_header">[B]29Apr14 15:32[/B]<span class="FFT_header_for_name">[B]Eduard Junge[/B]</span>
<br>
<span class="FFT_header_group">[B]Torry Pages[/B]</span>
</div>
<div class="fftText">
<pre>[B]Lorem Ipsum 2[/B]<br></pre>
</div>
Das sind 2 Einträge von über 300. Ich möchte pro div-Block die 4 fett markierten Informationen auslesen:

das Datum,
den Namen,
die Gruppe
und den Text

Ein ähnliches Problem habe ich mit String-Funktionen gelöst, aber himitsu erwähnte den Einsatz von HTML-DOM. Ich habe einige Gehversuche damit gestartet, komme aber nicht zurecht:

Delphi-Quellcode:
var
   divbody, div_class1, div_class2, Inputs : OleVariant;
   i,j,k: Integer;
begin
  divBody := Webbrowser1.OleObject.document.getElementById('div class="FFT_header"');
  div_class1 := divBody.getElementsByTagName('div class="FFT_header"');
  for i := 1 to div_class1.length - 1 do
  begin
    div_class2 := div_class2.item(i, null).getElementsByTagName('class="FFT_header_group"');
    for j := 0 to div_class2.length - 1 do
    begin
      Inputs := div_class2.item(j, null).getElementsByTagName('input');
      for k := 0 to Inputs.length - 1 do
        memo1.Lines.add(Inputs.item(k, null).value);
    end;
  end;
end;
Wie spreche ich denn eine div class richtig an ?
Jaimy
DAoC 2.0 -> Camelot Unchained !
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.624 Beiträge
 
Delphi 12 Athens
 
#2

AW: DIV classes mit getElementByID auslesen

  Alt 19. Mai 2014, 13:59
Ich denke, Du suchst getElementsByClassName, aber das wird nicht von allen Browsern unterstützt, siehe Tabelle. Außerdem ist zu beachten, dass da wohl ein Array aller passenden Elemente zurückkommt, denn mehrere Elemente können einer Klasse angehören, wohingegen eine ID nur einmal im Dokument vergeben werden darf und daher die entsprechende Funktion auch nur ein (oder gar kein) Element zurückliefert.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: DIV classes mit getElementByID auslesen

  Alt 19. Mai 2014, 14:11
Kannst ja auch alternativ versuchen mit dieser Klasse
http://www.delphipraxis.net/180405-k...ldocument.html
zu arbeiten. Evtl. geht das leichter von der Hand.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Volker Z.

Registriert seit: 4. Dez 2012
Ort: Augsburg, Bayern, Süddeutschland
419 Beiträge
 
Delphi XE4 Ultimate
 
#4

AW: DIV classes mit getElementByID auslesen

  Alt 19. Mai 2014, 22:04
Hallo,

Zitat:
Ich möchte pro div-Block die 4 fett markierten Informationen auslesen [...] Wie spreche ich denn eine div class richtig an ?
Das könnst z. B. Du so machen (das Exception Handling musst Du halt noch sauber programmieren):
Delphi-Quellcode:
uses
  MSHTML;

function DOMNodeClassNameIs (const Node : IHTMLDOMNode; const Name : string) : Boolean;
var
  e : IHTMLElement;
begin
  e := Node as IHTMLElement;
  if not Assigned (e) then
    Exception.Create ('Fehlermeldung');

  Result := e.className = Name
end;

function DOMNodeIsTextNode (const Node : IHTMLDOMNode) : Boolean;
begin
  if Assigned (Node) then
    Result := Node.nodeType = 3
  else
    Result := False
end;

function DOMNodeTagNameIs (const Node : IHTMLDOMNode; const Name : string) : Boolean;
begin
  if Assigned (Node) then
    Result := LowerCase (Node.nodeName) = LowerCase (Name)
  else
    Result := False
end;

function FindSpanByClassName (Node : IHTMLDOMNode; const Name : string) : IHTMLDOMNode;
begin
  Result := nil;
  while Assigned (Node) do
    begin
      if (LowerCase (Node.nodeName) = 'span') and DOMNodeClassNameIs (Node, Name) then
        begin
          Result := Node.firstChild;
          Break
        end;

      Node := Node.nextSibling
    end
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  d : IHTMLDocument3;
  c : IHTMLElementCollection;
  i : Integer;
  n : IHTMLDOMNode;
  s : string;

  procedure AddNodeValue (const Node : IHTMLDOMNode; var S : string);
  begin
    if not Assigned (Node) then
      Exception.Create ('Fehlermeldung');

    if S <> 'then
      S := S + ' ';

    S := S + Node.nodeValue
  end;

  procedure AddFFTHeader (const Node : IHTMLDOMNode; var S : string);
  var
    n : IHTMLDOMNode;

    procedure AddFFTDateTime (var Node : IHTMLDOMNode; var S : string);
    begin
      if not DOMNodeIsTextNode (Node) then
        Exception.Create ('Fehlermeldung');

      AddNodeValue (Node, S);
      Node := Node.nextSibling
    end;

    procedure AddFFTSpanByClassName (var Node : IHTMLDOMNode; var S : string; const Name : string);
    var
      n : IHTMLDOMNode;
    begin
      n := FindSpanByClassName (Node, Name);
      if not Assigned (n) then
        Exception.Create ('Fehlermeldung');

      AddNodeValue (n, S);
      Node := Node.nextSibling
    end;

  begin
    n := Node.firstChild;
    AddFFTDateTime (n, S);
    AddFFTSpanByClassName (n, S, 'FFT_header_for_name');
    AddFFTSpanByClassName (n, S, 'FFT_header_group')
  end;

  procedure AddFFTText (Node : IHTMLDOMNode; var S : string);
  begin
    if not (DOMNodeTagNameIs (Node, 'div') and DOMNodeClassNameIs (Node, 'fftText')) then
      Exception.Create ('Fehlermeldung');

    Node := Node.firstChild;
    if not DOMNodeTagNameIs (Node, 'pre') then
      Exception.Create ('Fehlermeldung');

    Node := Node.firstChild;
    if DOMNodeIsTextNode (Node) then
      AddNodeValue (Node, S)
  end;

begin
  d := WebBrowser1.Document as IHTMLDocument3;
  if not Assigned (d) then
    Exit;

  c := d.getElementsByTagName ('div');
  for i := 0 to c.length - 1 do
    begin
      n := c.item (i, EmptyParam) as IHTMLDOMNode;
      if not Assigned (n) then
        Exception.Create ('Fehlermeldung');

      if DOMNodeClassNameIs (n, 'FFT_header') then
        begin
          s := '';
          AddFFTHeader (n, s);
          AddFFTText (n.nextSibling, s);

          Memo1.Lines.Add (s)
        end
    end
end;

Gruß
Volker Zeller
  Mit Zitat antworten Zitat
Benutzerbild von Ajintaro
Ajintaro

Registriert seit: 20. Okt 2004
Ort: Sankt Augustin
138 Beiträge
 
Delphi XE6 Starter
 
#5

AW: DIV classes mit getElementByID auslesen

  Alt 21. Mai 2014, 11:49
Hallo Volker !

Ich habe mich gerade mit deinem Code beschäftigt und etwas damit experimentiert. Abgesehen von einer klitzekleinen Änderung (siehe unten) funktioniert der Code bis an folgender Stelle AddFFTText (n.nextSibling, s); sehr gut ! Da gibt es eine Access violation welche ich derzeit näher auf den Grund gehe. Aber vielen Dank schon mal für deine Hilfe, ich werde mich weiter mit diesem Thema beschäftigen !


Hallo,


Das könnst z. B. Du so machen (das Exception Handling musst Du halt noch sauber programmieren):
[DELPHI]
uses
MSHTML;

function DOMNodeClassNameIs (const Node : IHTMLDOMNode; const Name : string) : Boolean;
var
e : IHTMLElement;
begin
e := Node as IHTMLElement;
if not Assigned (e) then
Exception.Create ('Fehlermeldung');

Result := e.className = Name //richtig ist: e._className
end;
Jaimy
DAoC 2.0 -> Camelot Unchained !
  Mit Zitat antworten Zitat
Benutzerbild von Ajintaro
Ajintaro

Registriert seit: 20. Okt 2004
Ort: Sankt Augustin
138 Beiträge
 
Delphi XE6 Starter
 
#6

AW: DIV classes mit getElementByID auslesen

  Alt 21. Mai 2014, 17:07
Okay eine Frage habe ich noch:

Delphi-Quellcode:

procedure AddNodeValue (const Node : IHTMLDOMNode; var S : string);
  begin
    if not Assigned (Node) then
      Exception.Create ('Fehlermeldung');

    if S <> 'then
      S := S + ' ';

    S := S + Node.nodeValue
  end;

procedure AddFFTText (Node : IHTMLDOMNode; var S : string);
  begin
    if not (DOMNodeTagNameIs (Node, 'div') and DOMNodeClassNameIs (Node, 'fftText')) then
      Exception.Create ('Fehlermeldung');

    Node := Node.firstChild;
    if not DOMNodeTagNameIs (Node, 'pre') then
      Exception.Create ('Fehlermeldung');

    Node := Node.firstChild;
    if DOMNodeIsTextNode (Node) then
      AddNodeValue (Node, S)
  end;
Die obige Prozedur speichert den Text zwischen <pre> </pre> nur bis zum 1. Vorkommen eines <br>, der Rest wird nicht mehr mitgenommen.

Code:
<div class="fftText">
<pre>Das ist der 1. Satz<br>Und dies ist der 2. Satz. In diesem Falle mit X<br>Ich mag auch mit !</pre>
</div>
Muss ich da noch eine Schleife über die <br> Knoten hinzufügen ?
Jaimy
DAoC 2.0 -> Camelot Unchained !
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.116 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: DIV classes mit getElementByID auslesen

  Alt 21. Mai 2014, 19:44
Kannst ja auch alternativ versuchen mit dieser Klasse
http://www.delphipraxis.net/180405-k...ldocument.html
zu arbeiten. Evtl. geht das leichter von der Hand.
Ich habe dieses hier mal als Beispiel eingefügt http://www.delphipraxis.net/1259689-post2.html
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Volker Z.

Registriert seit: 4. Dez 2012
Ort: Augsburg, Bayern, Süddeutschland
419 Beiträge
 
Delphi XE4 Ultimate
 
#8

AW: DIV classes mit getElementByID auslesen

  Alt 21. Mai 2014, 22:14
Hallo,

Zitat:
Die obige Prozedur speichert den Text zwischen <pre> </pre> nur bis zum 1. Vorkommen eines <br>, der Rest wird nicht mehr mitgenommen. [...] Muss ich da noch eine Schleife über die <br> Knoten hinzufügen ?
Leider ist mir nicht klar was Du mit einer Schleife über die BR-Knoten meinst.

Dein
Code:
<div class="fftText">
<pre>Das ist der 1. Satz<br>Und dies ist der 2. Satz. In diesem Falle mit X<br>Ich mag auch mit !</pre>
</div>
Kann man sich als DOM-Baumstruktur so vorstellen ([-] heißt es existieren Kindknoten, eingerückt heißt Knoten auf derselben Ebene):
Code:
[-]<div class="fftText">
   [-]<pre>
         Das ist der 1. Satz
         <br>
         Und dies ist der 2. Satz. In diesem Falle mit X
         <br>
         Ich mag auch mit !
Wenn Dich die Kinder eines gegeben DOM-Knotens interessieren, dann gibt Dir Node := Node.firstChild; die Referenz auf den ersten Kindknoten - oder nil, falls kein Kindknoten existiert. Wenn Du den DIV-Knoten an procedure AddFFTText (Node : IHTMLDOMNode; var S : string); übergibst, dann liefert die erste Zuweisung den PRE-Knoten und die zweite Zuweisung den Textknoten "Das ist der 1. Satz".
Möchtest Du DOM-Knoten auf derselben Ebene untersuchen, dann sind die Zuweisungen: Node := Node.nextSibling; bzw. Node := Node.previousSibling; hilfreich; erstere liefert eine Referenz auf den nächsten Kindknoten, letztere eine Referenz auf den vorherigen Kindknoten derselben Ebene.

Wenn Du nur die Kinder der ersten Ebene des PRE-Knotens und dann auch nur Textknoten berücksichtigen möchtest: das erste Kind holen, solange diese Knoteneben durchlaufen bis kein weiterer Knoten mehr vorhanden ist, dabei jeden Knoten prüfen, ob es ein Textknoten ist - alles andere links liegen lassen.
In Code gegossen:
Delphi-Quellcode:
procedure AddFFTText (Node : IHTMLDOMNode; var S : string);
begin
  if not (DOMNodeTagNameIs (Node, 'div') and DOMNodeClassNameIs (Node, 'fftText')) then
    Exception.Create ('Fehlermeldung');

  Node := Node.firstChild;
  if not DOMNodeTagNameIs (Node, 'pre') then
    Exception.Create ('Fehlermeldung');

  Node := Node.firstChild;
  while Assigned (Node) do
    begin
      if DOMNodeIsTextNode (Node) then
        AddNodeValue (Node, S);

      Node := Node.nextSibling
    end
 end;
Dann ist auch "Ich mag auch mit !" mit von der Partie.

Ich hoffe ich konnte Deine Frage beantworten.

Zu Deiner Anmerkung: Result := e.className = Name //richtig ist: e._className kann gut sein, dass es ab XE5 oder XE6 mit Unterstrich sein muss.
Und was war da mit der Access violation. Kannst Du dazu mehr sagen?

Gruß
Volker Zeller
  Mit Zitat antworten Zitat
Benutzerbild von Ajintaro
Ajintaro

Registriert seit: 20. Okt 2004
Ort: Sankt Augustin
138 Beiträge
 
Delphi XE6 Starter
 
#9

AW: DIV classes mit getElementByID auslesen

  Alt 22. Mai 2014, 13:44
Hallo nochmal,

Ich hatte heute wieder die Gelegenheit am Code zu arbeiten. Zunächst sei gesagt, dass mir die Sichtweise eines TreeViews im Bezug auf die Arbeit mit DOM nicht nur geholfen, sondern auch inspiriert hat die Elemente als TreeView Knoten darzustellen:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  d : IHTMLDocument3;
  c : IHTMLElementCollection;
  i,entries : Integer;
  n : IHTMLDOMNode;
  s, datum, logger, group, text: string;
  tn: TTreeNode;


  procedure AddFFTHeader (const Node : IHTMLDOMNode; var S : string);
  var
    n : IHTMLDOMNode;
    //-------------------Timestamp--------------------------------------------------
    procedure AddFFTDateTime (var Node : IHTMLDOMNode; var S : string);
    begin
      if not DOMNodeIsTextNode (Node) then Exception.Create ('AddFFTHeader Error!');
      datum := Node.nodeValue;
      Node := Node.nextSibling
    end;
    //-------------------logger-------------------------------------------------
    procedure AddFFTName (var Node : IHTMLDOMNode; var S : string; const Name : string);
    var
      n : IHTMLDOMNode;
    begin
      n := FindSpanByClassName (Node, Name);
      if not Assigned (n) then Exception.Create ('AddFFTName Error');
      logger := n.nodeValue;
      Node := Node.nextSibling
    end;
    //-------------------Group-------------------------------------------------
    procedure AddFFTgroup (var Node : IHTMLDOMNode; var S : string; const Name : string);
    var
      n : IHTMLDOMNode;
    begin
      n := FindSpanByClassName (Node, Name);
      if not Assigned (n) then Exception.Create ('AddFFTgroup Error');
      group := n.nodeValue;
      Node := Node.nextSibling
    end;

  begin
    n := Node.firstChild;
    AddFFTDateTime (n, S);//Datum adden
    AddFFTName (n, S, 'FFT_header_for_name');
    AddFFTGroup (n, S, 'FFT_header_group');
  end;
  //-------------------TEXT -------------------------------------------------
  procedure AddFFTText (Node : IHTMLDOMNode; var S : string);
  begin
    if not (DOMNodeTagNameIs (Node, 'div') and DOMNodeClassNameIs (Node, 'fftText')) then
      Exception.Create ('DOMNodeTagNameIs error: Weder div noch fftText gefunden');

    Node := Node.firstChild;
    if not DOMNodeTagNameIs (Node, 'pre') then Exception.Create ('DOMNodeTagNameIs error: pre Tag nicht gefunden');

    if assigned(node) then
    begin
      Node := Node.firstChild;
      text := '';
      while Assigned (Node) do
      begin
        if DOMNodeIsTextNode (Node) then
          text := text + ' ' + Node.nodeValue;
          Node := Node.nextSibling
      end;
    end;
  end;

begin
  d := WebBrowser1.Document as IHTMLDocument3;
  if not Assigned (d) then
    Exit;

  c := d.getElementsByTagName ('div');
  for i := 0 to c.length - 1 do
    begin
      n := c.item (i, EmptyParam) as IHTMLDOMNode;
      if not Assigned (n) then
        Exception.Create ('Fehlermeldung');

      if DOMNodeClassNameIs (n, 'FFT_header') then
        begin
          s := '';
          AddFFTHeader (n, s);
          AddFFTText (n.nextSibling, s);

          inc(entries);
          label1.Caption := IntToStr(entries)+' Einträge gefunden';

          //Add Treenode
          tn := Treeview.Items.Add(TreeView.Items.GetFirstNode, datum);
          TreeView.Items.AddChild(tn, logger);
          TreeView.Items.AddChild(tn, group);
          TreeView.Items.AddChild(tn, text);
        end
    end
end;
Ich fühle mich dank euren Erklärungen schon etwas sicherer mit dem Umgang von DOM. Ich habe auch die Access Violation gefunden: es klingt seltsam, aber sobald die Webseite einen meta-tag enthält, ist die Node in:

Delphi-Quellcode:
procedure AddFFTText (Node : IHTMLDOMNode; var S : string);
  begin
    if not (DOMNodeTagNameIs (Node, 'div') and DOMNodeClassNameIs (Node, 'fftText')) then
      Exception.Create ('DOMNodeTagNameIs error: Weder div noch fftText gefunden');

    Node := Node.firstChild;
    if not DOMNodeTagNameIs (Node, 'pre') then Exception.Create ('DOMNodeTagNameIs error: pre Tag nicht gefunden');

    if assigned(node) then
    begin
      Node := Node.firstChild;
      text := '';
      while Assigned (Node) do
      begin
        if DOMNodeIsTextNode (Node) then
          text := text + ' ' + Node.nodeValue;
          Node := Node.nextSibling
      end;
    end;
  end;
immer NIL und deshalb NOT ASSIGNED. Deshalb hab ich ein if assigned(node) eingebaut um den Fehler zu umgehen. Dabei ist es egal was im meta tag steht, die Node ist dann immer NIL...

Ich habe auch einen kleinen Demonstrator gebaut, welchen ich euch gerne zum Testen zur Verfügung stellen kann.
Den Code von Christian werde ich mir jetzt mal anschauen !
Jaimy
DAoC 2.0 -> Camelot Unchained !
  Mit Zitat antworten Zitat
Benutzerbild von Ajintaro
Ajintaro

Registriert seit: 20. Okt 2004
Ort: Sankt Augustin
138 Beiträge
 
Delphi XE6 Starter
 
#10

AW: DIV classes mit getElementByID auslesen

  Alt 22. Mai 2014, 20:26
Guten Abend !

Ich habe mein Problem selbst behoben aufgrund Christian's Code:

Delphi-Quellcode:
LDOC := TcsHTMLDocument.Create;
LDOC.Content := Memo1.Text;
Damit muss ich nicht mit dem original HTML Dokument leben und kann mich auf die Bereiche konzentrieren, welche ich auswerten möchte. Vielen, vielen Dank für dein Beispiel, jetzt hab ich 2 sehr geniale Ansätze um mich mit den HTML Elementen vertrauter zu machen
Jaimy
DAoC 2.0 -> Camelot Unchained !
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:14 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