Autor Beitrag
galagher
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 07.02.14 18:20 
Hallo!

Gibt es eine vorgefertigte Methode, den reinen Text ohne HTML-Formatierung zu extrahieren, wenn ich TIdHTTP verwende? Bisher mache ich das manuell.

ausblenden Delphi-Quelltext
1:
2:
3:
s := IdHTTP1.Get(...
//Ab hier mache ich sehr umständlich mit selbstgeschriebenem Code weiter
//...

So enthält die Variable s einfach den HTML-Code, ich brauche aber nur den reinen Textstring!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 07.02.14 18:25 
Dafür brauchst du einen HTML-Parser. Eine Möglichkeit ist der, der bei Windows dabei ist:
stackoverflow.com/a/14349613
(also via IHTMLDocument2)

Oder auch eigene Implementierungen:
htmlp.sourceforge.net/

Für diesen Beitrag haben gedankt: galagher
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 07.02.14 19:42 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Dafür brauchst du einen HTML-Parser. Eine Möglichkeit ist der, der bei Windows dabei ist:
stackoverflow.com/a/14349613
(also via IHTMLDocument2)
Komme nicht damit zurecht! Da ist HTML ja eine Konstante, ich muss also eine Sringvariable mit dem HTML-String füllen und das dann auswerten. Da kommt aber weder LABEL noch SPAN vor.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Oder auch eigene Implementierungen:
htmlp.sourceforge.net/
Möchte andererseits nichts installieren.

Da bleib ich lieber bei meinem selbstgeschriebenen Code.

//Edit: Was nicht heissen soll, dass ich nicht doch noch gerne Vorschläge und Tipps annehmen möchte!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 07.02.14 20:09 
user profile icongalagher hat folgendes geschrieben Zum zitierten Posting springen:
Komme nicht damit zurecht! Da ist HTML ja eine Konstante, ich muss also eine Sringvariable mit dem HTML-String füllen und das dann auswerten. Da kommt aber weder LABEL noch SPAN vor.
:gruebel:
In der Konstante mit dem Beispiel kommen doch die Tags label und span vor, und dieser Beispieltext wird in das HTML-Dokument geschrieben und dann über die Tags ausgelesen.

Wenn du das Beispiel ausführst, wird genau Name: und Value ausgegeben, so wie es auch in dem Beispiel in den Tags label und span drin ist. Probier es doch einfach aus, das funktioniert bei mir 1:1 kopiert problemlos.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 07.02.14 20:17 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wenn du das Beispiel ausführst, wird genau Name: und Value ausgegeben, so wie es auch in dem Beispiel in den Tags label und span drin ist. Probier es doch einfach aus, das funktioniert bei mir 1:1 kopiert problemlos.
Ja, das schon, aber das ist doch ein Beispiel, in dem "HTML" eine Konstante mit HTML-Code ist.

Will man dieses Beispiel einsetzen, muss man also stattdessen eine Variable mit dem HTML-Code befüllen, den man parsen will. Das klappt aber nicht, weil ich nicht weiss, was ich anstelle von 'LABEL', 'tvLabel', 'SPAN' und 'tvValue' angeben muss.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 07.02.14 20:41 
Das kann dir niemand sagen ohne den Quelltext der Seite zu kennen, um die es geht. Du kannst mir ein Beispiel auch per PN schicken, wenn du es hier nicht posten möchtest.

Du nimmst die Seite aber doch im Moment selbst auseinander. Da musst du doch wissen in welchen Tags der Inhalt steht, um den es dir geht.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 07.02.14 21:11 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das kann dir niemand sagen ohne den Quelltext der Seite zu kennen, um die es geht.
Es ist Text aus der Wikipedia, da brauche ich immer nur den ersten Satz. Ich lese also den gesamten HTML-Text ein, parse, bis ich den puren Text habe, suche dann die Position des ersten Punktes und schneide mit Copy ab.

Am Besten wäre natürlich ein Befehl wie HTMLToText. Das, was der tun soll, ist zwar auch, was ich jetzt mache, nur dachte ich, das gibt es vielleicht schon als fertige Methode.

ausblenden Delphi-Quelltext
1:
2:
s := IdHTTP1.Get(...
sPureString := HTMLToText(s);  //Leider habe ich keine Funktion HTMLToText!


Denn flexibel ist meine Methode nicht, da stecken viele hardgecodete Strings drin. Ich dachte, es gibt etwas Besseres!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 08.02.14 00:25 
Ich hab mal kurz ein komplettes Beispiel dafür erstellt:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
uses
  ActiveX, MSHTML, IdHTTP;

type
  IHtmlElementEnumerator = interface
    function GetEnumerator: IHtmlElementEnumerator;
    function GetCurrent: IHTMLElement;
    function MoveNext: Boolean;
    property Current: IHTMLElement read GetCurrent;
  end;

  THtmlElementEnumerator = class(TInterfacedObject, IHtmlElementEnumerator)
  private
    var
      FEnum: IEnumVariant;
      FCurrent: IHTMLElement;
    function GetCurrent: IHTMLElement;
    function MoveNext: Boolean;
  public
    constructor Create(const AElements: IHTMLElementCollection);
    function GetEnumerator: IHtmlElementEnumerator;
    class function Enum(const AElements: IHTMLElementCollection): IHtmlElementEnumerator;
  end;

{ THtmlElementEnumerator }

constructor THtmlElementEnumerator.Create(const AElements: IHTMLElementCollection);
begin
  FEnum := AElements._newEnum as IEnumVariant;
end;

class function THtmlElementEnumerator.Enum(const AElements: IHTMLElementCollection): IHtmlElementEnumerator;
begin
  Result := THtmlElementEnumerator.Create(AElements);
end;

function THtmlElementEnumerator.GetCurrent: IHTMLElement;
begin
  Result := FCurrent;
end;

function THtmlElementEnumerator.GetEnumerator: IHtmlElementEnumerator;
begin
  Result := Self;
end;

function THtmlElementEnumerator.MoveNext: Boolean;
var
  CurrentElement: OleVariant;
  ElementCount: Cardinal;
begin
  Result := FEnum.Next(1, CurrentElement, ElementCount) = S_OK;
  if Result then
    FCurrent := IUnknown(CurrentElement) as IHTMLElement
  else
    FCurrent := nil;
end;

function GetFirstWikipediaParagraph(const AURL: String): String;
var
  PageLoader: TIdHTTP;
  HtmlDocument: IHTMLDocument2;
  HtmlDocumentEx: IHTMLDocument3;
  PageContents: String;
  CurrentElement, ContentsElement, ParagraphElement: IHTMLElement;
begin
  // fetch page contents
  PageLoader := TIdHTTP.Create;
  try
    PageContents := PageLoader.Get(AURL);
  finally
    PageLoader.Free;
  end;
  // load page contents to parser
  HtmlDocument := CoHTMLDocument.Create as IHTMLDocument2;
  OleVariant(HtmlDocument).write(PageContents);
  HtmlDocument.close;
  // wait for parser to be ready
  while HtmlDocument.ReadyState <> 'complete' do
    Application.ProcessMessages;
  HtmlDocumentEx := HtmlDocument as IHTMLDocument3;
  // delete all annotations
  for CurrentElement in THtmlElementEnumerator.Enum(HtmlDocumentEx.getElementsByTagName('sup')) do
    (CurrentElement as IHTMLDOMNode).removeNode(true);
  // find contents element
  ContentsElement := HtmlDocumentEx.getElementById('mw-content-text');
  // first element inside is the table on the right, second is the first paragraph, so take index 1
  ParagraphElement := (ContentsElement.children as IHTMLElementCollection).item(1, EmptyParam) as IHTMLElement;
  // return text inside
  Result := ParagraphElement.innerText;
end;

// example call
ShowMessage(GetFirstWikipediaParagraph('http://de.wikipedia.org/wiki/Topinambur'));
Den THtmlElementEnumerator bräuchte man natürlich nicht, aber es ist damit praktischer. ;-)

Für diesen Beitrag haben gedankt: galagher
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Sa 08.02.14 13:25 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Ich hab mal kurz ein komplettes Beispiel dafür erstellt:
Ja, kann ich gut brauchen, danke! Werde ich testen, sieht aber schon mal gut aus! :)

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Sa 08.02.14 14:15 
Jetzt ist ein neues Problem aufgetaucht: Manchme Sätze enden mit einem Doppelpunkt. Wie muss ich deinen Code ändern, damit er beides, Punkt und Doppelpunkt, erkennt?

Als Beispiel de.wikipedia.org/wiki/Mers:
Zitat:
Mers ist der Name zweier Gemeinden in Frankreich:

Mers-les-Bains, Gemeinde im Département Somme
Mers-sur-Indre, Gemeinde im Département Indre

Hier kann ich schon "Mers ist der Name zweier Gemeinden in Frankreich:" als Satz gebrauchen.

//Edit: Bin schon an der Lösung dran!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 08.02.14 22:32 
Dann so:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
function GetFirstWikipediaParagraph(const AURL: String): String;
var
  PageLoader: TIdHTTP;
  HtmlDocument: IHTMLDocument2;
  HtmlDocumentEx: IHTMLDocument3;
  PageContents: String;
  CurrentElement, ContentsElement, ParagraphTestElement: IHTMLElement;
  ContentsElementChildren: IHTMLElementCollection;
  i: Integer;
begin
  // fetch page contents
  PageLoader := TIdHTTP.Create;
  try
    PageContents := PageLoader.Get(AURL);
  finally
    PageLoader.Free;
  end;
  // load page contents to parser
  HtmlDocument := CoHTMLDocument.Create as IHTMLDocument2;
  OleVariant(HtmlDocument).write(PageContents);
  HtmlDocument.close;
  // wait for parser to be ready
  while HtmlDocument.ReadyState <> 'complete' do
    Application.ProcessMessages;
  HtmlDocumentEx := HtmlDocument as IHTMLDocument3;
  // delete all annotations
  for CurrentElement in THtmlElementEnumerator.Enum(HtmlDocumentEx.getElementsByTagName('sup')) do
    (CurrentElement as IHTMLDOMNode).removeNode(true);
  // find contents element
  ContentsElement := HtmlDocumentEx.getElementById('mw-content-text');
  ContentsElementChildren := ContentsElement.children as IHTMLElementCollection;
  Result := '';
  for i := 0 to ContentsElementChildren.length - 1 do
  begin
    ParagraphTestElement := ContentsElementChildren.item(i, EmptyParam) as IHTMLElement;
    if AnsiSameText(ParagraphTestElement.tagName, 'p'then
    begin
      Result := ParagraphTestElement.innerText;
      Break;
    end;
  end;
  if Result = '' then
    Result := ContentsElement.innerText;
end;

Für diesen Beitrag haben gedankt: galagher
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 09.02.14 12:41 
Mit ein bisschen Umbau klappt es jetzt! :D

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 10.02.14 21:59 

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 10.02.14 23:15 
Ach du Schande, einen TWebBrowser zu missbrauchen ist... ähm... ich sag mal freundlich ungünstig. Da kannte sich der Autor leider nicht aus. Den Code dort kannst du genauso rein mit dem IHTMLDocument2 Interface aus dem CoHTMLDocument machen wie in meinem Code.

// EDIT:
Ach ja, und das createTextRange kann man sich meines Erachtens auch sparen, es reicht innerText des Body-Elements, wenn man den kompletten Text möchte. Aber es wäre ja Schwachsinn den hinterher zu parsen, wenn man wie in deinem Fall nur einen bestimmten Teil braucht.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Di 11.02.14 18:22 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
// EDIT:
Ach ja, und das createTextRange kann man sich meines Erachtens auch sparen, es reicht innerText des Body-Elements, wenn man den kompletten Text möchte. Aber es wäre ja Schwachsinn den hinterher zu parsen, wenn man wie in deinem Fall nur einen bestimmten Teil braucht.
Meinst du so:
ausblenden Delphi-Quelltext
1:
Result := Document.body.innerText;					

So funktioniert es jedenfalls auch.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 11.02.14 18:55 
Ja, genau.

Aber ich dachte du brauchst gar nicht den kompletten Text der Seite?
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Di 11.02.14 19:14 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Ja, genau.

Aber ich dachte du brauchst gar nicht den kompletten Text der Seite?
Diesen Code will ich auch meiner Sammlung hinzufügen! :mrgreen:
Für das aktuelle Projekt brauche ich tatsächlich nur die erste Zeile, nochmals danke für deinen Code dafür!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!