[Gelöst] HTML Parser in Lazarus benutzen

Rund um die LCL und andere Komponenten
Antworten
Namos

[Gelöst] HTML Parser in Lazarus benutzen

Beitrag von Namos »

Hallo, wie benutzt man den HTML-Parser in Lazarus, es gibt im Wiki nur ein XML beispiel http://wiki.freepascal.org/XML_Tutorial.
Ich habe mal ein wenig versucht das Beispiel für XML umzuschreiben. Geht das überhaupt mit dem Typ THTMLDocument ? Jedenfalls komme ich schon beim einlesen nicht weiter...

Code: Alles auswählen

uses
  Classes, SysUtils, FileUtil, IdMessage, Forms, Controls, Graphics, Dialogs,
  StdCtrls, DOM,  DOM_HTML, HTMLDefs;    
.
.
.
procedure TForm1.Button5Click(Sender: TObject);
Var
  S : TStringStream;
  HTMLDoc: THTMLDocument;
  i: Integer;
  TmpList: TStringList;
  Str1: String;
begin
  S:= TStringStream.Create('');
  TmpList:= TStringList.Create;
  HTMLDoc:= Nil;
 
  Try
    Memo1.Lines.SaveToStream(S); //HTML-Text
    S.Position:=0;
 
    //ReadHTMLFile(HTMLDoc,S); //Befehl gibt es nicht
 
    with HTMLDoc.DocumentElement.ChildNodes do
    begin
      for i:= 0 to (Count - 1) do
      begin
        if Item[i].FirstChild <> nil then
        begin
          Str1:= utf8encode(Item[i].FirstChild.TextContent);
          TmpList.Add(Str1);
        end;
      end;
    end;
 
    Memo2.Lines.AddStrings(TmpList);
  Finally
    FreeAndNil(S);
    FreeAndNil(HTMLDoc);
    FreeAndNil(TmpList);
  end;
end;
Hier das sieht auch interessant aus http://www.benibela.de/documentation/internettools/
Zuletzt geändert von Namos am So 5. Mai 2013, 10:10, insgesamt 1-mal geändert.

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 395
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: HTML Parser in Lazarus benutzen

Beitrag von MitjaStachowiak »

Hallo,
also als ich mal mit XML gearbeitet habe, habe ich meinen eigenen Parser geschrieben. Wenn du Dinge, wie Fehlerkorrektur nicht brauchst, ist das mit der nötigen Erfahrung in einer Woche machbar. Das Ergebniss ist dann genau auf dein Programm zurechtgeschnitten und bestimmt deutlich schneller.

Falls du also mit den fertigen Parsern nicht klar kommst: Mach' dir erstmal eine abstrakte Klasse, die als Grundlage für das Dokument dient. Die muss dann einen Pointer auf das Parent haben und einen Array aus allen Kindelementen, sowie eine Zeichenkette, die den Text enthällt, also alles, was nicht in einem Kindelement steht. Wenn du zum Beispiel überall da, wo ein Kindelement steht, ein "<" in der Zeichenkette stehen lässt, kannst du das Ganze hinterher sogar identisch wieder abspeichern.

Das fiese: Sobald du das selbst geschrieben hast, verstehst du auch, wie du einen fertigen Parser hättest verwenden können. :mrgreen:

Also so als Plan B - nicht abschrecken lassen :wink:

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: HTML Parser in Lazarus benutzen

Beitrag von gocher »

Hallo Namos,

ich habe zwar auch meinen eigenen Parser geschrieben, aber zu Deinem Code:

1. Das Objekt HTMLDoc sollte erst einmal erzeugt werden

Code: Alles auswählen

HTMLDoc := THTMLDocument.Create();
2. ich glaube Du brauchst erst einmal einen Parser, füge doch unter

Code: Alles auswählen

uses sax_html
hinzu

3. Mit dieser Unit steht Dir dann auch die benötigte Funktion zur Verfügung

Code: Alles auswählen

procedure ReadHTMLFile(HTMLDoc, AFilename);
procedure ReadHTMLFile(HTMLDoc, SStream);
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

Namos

Re: HTML Parser in Lazarus benutzen

Beitrag von Namos »

@MitjaStachowiak danke für die Anregung, wegen des Lerneffekts werde ich da wahrscheinlich nochmal drauf zurückkommen.

@gocher danke genau das habe ich gesucht.
Es klappt auch schon fast optimal:

Code: Alles auswählen

 uses ...DOM_HTML, sax_html ...
.
.
.
procedure TForm1.Button1Click(Sender: TObject);  
Var
  S : TStringStream;
  HTMLDoc: THTMLDocument;
  i: Integer;
  TmpList: TStringList;
begin
  S:= TStringStream.Create('');
  TmpList:= TStringList.Create;
  HTMLDoc := THTMLDocument.Create();
 
  Try
    Memo1.Lines.SaveToStream(S);
    S.Position:=0;
    //ReadHTMLFile(HTMLDoc,S);   //Aus Stream laden
    ReadHTMLFile(HTMLDoc,'\index.html'); //Aus Datei laden
 
    //Text aus HTML extrahieren
    with HTMLDoc.DocumentElement.ChildNodes do 
      for i:= 0 to (Count - 1) do
        if Item[i] <> nil then 
          TmpList.Add(utf8encode(Item[i].TextContent)); //Text in Stringliste (je nach bedarf...)
     
    //Ausgabe
    Memo2.Lines.Assign(TmpList);  
  Finally
    FreeAndNil(S);
    FreeAndNil(HTMLDoc);
    FreeAndNil(TmpList);
  end;
end; 
Html-Datei:

Code: Alles auswählen

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>text-align</title>
</head><body>
<p style="text-align:left; margin-left:50px; margin-right:50px">Der Absatz, den Sie gerade lesen, wurde mit <b>text-align</b> linksbündig ausgerichtet. Ferner wurde ein Rand von 50px eingestellt, just for fun oder auch, damit Sie ein Gefühl für die Prioritäten zwischen den einzelnen Stylesheet-Angaben bekommen.<br>
Noch eine Textzeile<br>
Noch eine Textzeile</p>
 
<p style="text-align:right; margin-left:0px; margin-right:50px">Der Absatz, den Sie gerade lesen, wurde mit <b>text-align</b> rechtsbündig ausgerichtet. Ferner wurde ein Rand von 50px eingestellt, just for fun oder auch, damit Sie  sehen, wie die einzelnen Stylesheet-Angaben zusammenspielen.<br>
Noch eine Textzeile<br>
Noch eine Textzeile</p>
 
<p style="text-align:center; margin-left:50px; margin-right:50px">Der Absatz, den Sie gerade lesen, wurde mit <b>text-align</b> zentriert ausgerichtet. Ferner wurde ein Rand von 50px eingestellt, just for fun oder auch, damit Sie sehen, wie die einzelnen Stylesheet-Angaben zusammenspielen.<br>
Noch eine Textzeile<br>
Noch eine Textzeile</p>
 
</body>
</html>
 
Ausgabe:

Code: Alles auswählen

text-align
Der Absatz, den Sie gerade lesen, wurde mit text-align linksbündig ausgerichtet. Ferner wurde ein Rand von 50px eingestellt, just for fun oder auch, damit Sie ein Gefühl für die Prioritäten zwischen den einzelnen Stylesheet-Angaben bekommen.
Noch eine Textzeile
Noch eine TextzeileDer Absatz, den Sie gerade lesen, wurde mit text-align rechtsbündig ausgerichtet. Ferner wurde ein Rand von 50px eingestellt, just for fun oder auch, damit Sie sehen, wie die einzelnen Stylesheet-Angaben zusammenspielen.
Noch eine Textzeile
Noch eine TextzeileDer Absatz, den Sie gerade lesen, wurde mit text-align zentriert ausgerichtet. Ferner wurde ein Rand von 50px eingestellt, just for fun oder auch, damit Sie sehen, wie die einzelnen Stylesheet-Angaben zusammenspielen.
Noch eine Textzeile
Noch eine Textzeile

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: HTML Parser in Lazarus benutzen

Beitrag von pluto »

Für einer meiner Projekte habe ich einen recht "guten" HTML und CSS Parser geschrieben. Der Vorteil hier: Man kann die Datenstruktur selbst bestimmen. Im Moment ist noch etwas Handarbeit notwendig. Später soll es auch eine Fertige Datenstruktur geben, nur die ist im Moment in mein Projekt fest eingebunden.
Ich habe aber jedoch noch vor, dass zu verfeinern. Der Parser ist jedoch noch nicht Tolerant, so wie der HTML Parser von FF. D.H. Der Code musst Syntaktisch 100% Richtig sein.

Der Parser erkennt bestimmte Code Bestandteile wie z.b. das ist jetzt ein Attribute und ruft dann eine Methode wie etwa FundAttribut auf. Das könnte auch ein Event sein. So muss muss man vom HTML Parser ableiten.

Ein HTML Parser zu schreiben ist eigentlich recht einfach. Problematisch ist nur der CSS Parser, wegen den ganzen Regeln, die es hier so gibt.
MFG
Michael Springwald

Antworten