Entwickler-Ecke
Internet / Netzwerk - IdHTTP - reinen Textstring extrahieren
galagher - Fr 07.02.14 18:20
Titel: IdHTTP - reinen Textstring extrahieren
Hallo!
Gibt es eine vorgefertigte Methode, den reinen Text ohne HTML-Formatierung zu extrahieren, wenn ich TIdHTTP verwende? Bisher mache ich das manuell.
Delphi-Quelltext
1: 2: 3:
| s := IdHTTP1.Get(... |
So enthält die Variable s einfach den HTML-Code, ich brauche aber nur den reinen Textstring!
galagher - Fr 07.02.14 19:42
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.
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!
jaenicke - Fr 07.02.14 20:09
galagher hat folgendes geschrieben : |
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 - Fr 07.02.14 20:17
jaenicke hat folgendes geschrieben : |
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.
jaenicke - 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 - Fr 07.02.14 21:11
jaenicke hat folgendes geschrieben : |
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.
Delphi-Quelltext
1: 2:
| s := IdHTTP1.Get(... sPureString := HTMLToText(s); |
Denn flexibel ist meine Methode nicht, da stecken viele hardgecodete Strings drin. Ich dachte, es gibt etwas Besseres!
jaenicke - Sa 08.02.14 00:25
Ich hab mal kurz ein komplettes Beispiel dafür erstellt:
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;
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 PageLoader := TIdHTTP.Create; try PageContents := PageLoader.Get(AURL); finally PageLoader.Free; end; HtmlDocument := CoHTMLDocument.Create as IHTMLDocument2; OleVariant(HtmlDocument).write(PageContents); HtmlDocument.close; while HtmlDocument.ReadyState <> 'complete' do Application.ProcessMessages; HtmlDocumentEx := HtmlDocument as IHTMLDocument3; for CurrentElement in THtmlElementEnumerator.Enum(HtmlDocumentEx.getElementsByTagName('sup')) do (CurrentElement as IHTMLDOMNode).removeNode(true); ContentsElement := HtmlDocumentEx.getElementById('mw-content-text'); ParagraphElement := (ContentsElement.children as IHTMLElementCollection).item(1, EmptyParam) as IHTMLElement; Result := ParagraphElement.innerText; end;
ShowMessage(GetFirstWikipediaParagraph('http://de.wikipedia.org/wiki/Topinambur')); |
Den THtmlElementEnumerator bräuchte man natürlich nicht, aber es ist damit praktischer. ;-)
galagher - Sa 08.02.14 13:25
jaenicke hat folgendes geschrieben : |
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! :)
galagher - 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
http://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!
jaenicke - Sa 08.02.14 22:32
Dann so:
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 PageLoader := TIdHTTP.Create; try PageContents := PageLoader.Get(AURL); finally PageLoader.Free; end; HtmlDocument := CoHTMLDocument.Create as IHTMLDocument2; OleVariant(HtmlDocument).write(PageContents); HtmlDocument.close; while HtmlDocument.ReadyState <> 'complete' do Application.ProcessMessages; HtmlDocumentEx := HtmlDocument as IHTMLDocument3; for CurrentElement in THtmlElementEnumerator.Enum(HtmlDocumentEx.getElementsByTagName('sup')) do (CurrentElement as IHTMLDOMNode).removeNode(true); 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; |
galagher - So 09.02.14 12:41
Mit ein bisschen Umbau klappt es jetzt! :D
jaenicke - 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 - Di 11.02.14 18:22
jaenicke hat folgendes geschrieben : |
// 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:
Delphi-Quelltext
1:
| Result := Document.body.innerText; |
So funktioniert es jedenfalls auch.
jaenicke - Di 11.02.14 18:55
Ja, genau.
Aber ich dachte du brauchst gar nicht den kompletten Text der Seite?
galagher - Di 11.02.14 19:14
jaenicke hat folgendes geschrieben : |
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!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!