Scala Html Table parsen

DaveX

Mitglied
Hallo Scala-ianer,

ich suche einen besseren Weg um Werte aus einer Html Table zu extrahieren.

Die Table sieht so aus:

<table width="597" border="0" cellspacing="0" cellpadding="0" summary="blah blah">
<tr><td colspan="8" class="dateline">Fr. 01.10.10</td></tr>
<tr>
<td width="38" class="planline0">TIME</td>
<td width="57" class="planline0">CATEGORY</td>
<td width="20" class="planline0">ID</td>
<td width="96" class="planline0">TEXT1</td>
<td width="108" class="planline0">TEXT2</td>
<td width="77" class="planline0" style="...">&nbsp;</td>
<td width="77" class="planline0" style="...">2,75&nbsp;(1:1)</td>
<td width="101" class="planline0" style="...">&nbsp;</td>
</tr>
<tr>
<td width="38" class="planline1">TIME</td>
<td width="57" class="planline1">CATEGORY</td>
<td width="20" class="planline1">ID</td>
<td width="96" class="planline1">TEXT1</td>
<td width="108" class="planline1">TEXT2</td>
<td width="77" class="planline1" style="...">&nbsp;</td>
<td width="77" class="planline1" style="...">&nbsp;</td>
<td width="101" class="planline1" style="...">1,40&nbsp;(1:2)</td>
</tr>
...
...
</table>

Es kommen also 2 Typen von tr's. Einmal mit einem td class ="dateline" und einmal mit mit exact 8 td's wie oben.

Mein erster Schnellschuss um die zu parsen war folged:
(die table bekomme ich in einer Zeile von einer seite)

1. replace tr with \n<tr dann splitt nach \n
2 each line ( contains class="dateline" or contains class="planline)
3. jenachdem extrahiere ich:
- dateline mit einen RegExExtractor : """<tr><td colspan="\d" class="dateline">(.+)</td></tr>""".r
- bei planline htmlLine.replaceAll("<tr>","").replaceAll("</tr>","").replaceAll("<td>", "\n<td>").split("</td>")
dann hole ich mir alles ab lastIndexOf(">")

Dies gefällt mir eigentlich gar nicht, und das war nur eine übergangslösung um weiter zu kommen.
Scala kann doch nativ xml - hab da was ausprbiert aber ne exception des internen SAX parsers hat mich davon abgehalten.

Irgendwie konnte man nicht die table als XML umwandeln - wahrscheinlich nicht xhtml konform oder so.
Wennda gehen würde würde ich mir die ganzen regex sachen Sparen können.
und einfach für jedes tr die children hole und jenachdem passend mit .text - den htmltext extrahieren.

Hat jemand schon sowas gemacht?
Strings ins xml umwandeln und damit gearbeitet ?

Im Voraus Vielen Dank für Tipps und Vorschläge

Grüße
DaveX
 

DaveX

Mitglied
Danke für den Tipp.

Ich habe aber gesehen dass das Projekt schon seit 2006 nicht weiter entwickelt worden ist, zumidest ist die letzte Version so alt.

Auf dieser Seite: Open Source HTML Parsers in Java - Java HTML Parser habe ich weitere Parser gesehen, ich muss mal testen welcher von den am einfachsten ist da, ich für mein vorhaben nur Date extrahieren muss und damit keine Änderungen an dem HTML Dokument nötig sind.

Noch besser wäre wenn ich auf mein HTML Dokument jQuery Selektoren anwenden konnte, das wäre einfach unschlagbar - da konnte man mit wenigen Code an die Elemente kommen und deren Text extrahieren.

Muss mal nach solcher lib Suchen, glaube aber nicht, dass ich fundig werde.

Grüße
DaveX
 

DaveX

Mitglied
Es ging mir darum, dass seit ziemlich langer Zeit nichts an dem Projekt gemacht worden ist.
Nichts ist perfekt und mann kann immer was optimieren usw.

Zum Vergleich, die letzte Version des Jericho HTML Parsers ist von Mitte 2009 - vielleicht ist das kein Grund dies zu nutzen, dennoch habe ich das Gefühl das je neuer das Projekt desto höher die Chance, dass die Entwickler die aktuellen Trends in der Softwareentwicklung verfolgen.
 
A

Antedeluvisch

Gast
Vielleicht eine dumme Frage, aber warum brichst Du es nicht direkt über einen regulären Ausdrücke auseinander bevor Du so eine IMHO gewagte Konstruktion aufbaust?
Mit dem Zeilenumbruch als Merkmal zu arbeiten halte ich sowieso für zu gefährlich. EIn \n könnte auch bereits so im Text sitzen.
 

DaveX

Mitglied
Ich wollte am Anfang tatsächlich mit regulären Ausdrücken das ganze extrahieren, leider wusste ich nicht wie ich sowas in scala realisieren kann. Vor allem effizient und so, das man es schnell abändern kann falls die Seite geändert wird. ( und reguläre Ausdrücke kann man ja schnell ändern. Und sogar in eine externe lib packen)
Es waren 3 Sachen die ich extrahieren wollte die o.g. Tabelle und 2 Select Elemente.
Leider habe ich bis jetzt nur einfache Extraktoren gebaut.

Aus einer Seite dann ein Teil zu extrahieren zB. mit val selectFilter = """.+(<select.+</select>).+""".r
funktioniert nicht.

Würde das funktionieren, müsste ich anschließend die <option>'s extrahieren, das weiss ich auch nicht wie ich die Variable anzahl der options matchen konnte so dann ich dann nur die Values in einen Container wie List oder Array extrahiere.

Mit der Gegebenen Tabelle wäre das ein wenig aufwendiger, da wie man sehen kann, ab un zu ein <tr> mit "Datum" auftaucht was dann für wichtig ist da es die folgenden <tr>'s beeinflusst.

Ich habe leider keine Beispiele für solche für mich advanced RegEx Ausdrücke in Scala gefunden.

Habe jetzt den jericho Html Parser benutzt mit dem ich echt zufrieden bin. Ich weiss nicht wie gut der für Datenmanipulation ist, aber für die Extraktion ist er vollkommen OK. Gute Beispiele sind da, und der Einstieg dadurch sehr leicht.


Natürlich würde mich das sehr sehr interessieren wie man das mit RegEx realisieren kann.
Ich habe auch nochmal versucht, RegEx zu benutzen aber leider ohne erfolg.

Ich bin für jeden Tipp dankbar der mich bei dem RegEx in Scala weiterbringt

Grüße
DaveX
 
A

Antedeluvisch

Gast
Ich arbeite selbst nicht mit Scala - ich mag die Sprache ehrlich gesagt wegen des Syntax überhaupt nicht - man möge mich dafür ruhig schlagen ;-)
Grundsätzlich ist das aber ein Thema für RegEx und bei Scala liefert ja nur um den Syntax. Es ist also genaugenommen nur die Frage passende RegEx-Muster zu erstellen. Da wirst Du problemlos Hilfe finden. Das beschriebene Problem ist ja vom Ausdruck her nicht schwer.

Aber hier ist ein Beispielcode aus "Programming Scala"

Code:
// code-examples/Rounding/match-regex-script.scala

val BookExtractorRE = """Book: title=([^,]+),\s+authors=(.+)""".r
val MagazineExtractorRE = """Magazine: title=([^,]+),\s+issue=(.+)""".r

val catalog = List(
  "Book: title=Programming Scala, authors=Dean Wampler, Alex Payne",
  "Magazine: title=The New Yorker, issue=January 2009",
  "Book: title=War and Peace, authors=Leo Tolstoy",
  "Magazine: title=The Atlantic, issue=February 2009",
  "BadData: text=Who put this here??"
)

for (item <- catalog) {
  item match {
    case BookExtractorRE(title, authors) =>
      println("Book \"" + title + "\", written by " + authors)
    case MagazineExtractorRE(title, issue) =>
      println("Magazine \"" + title + "\", issue " + issue)
    case entry => println("Unrecognized entry: " + entry)
  }
}
 

Noctarius

Top Contributor
Es gibt Dinge an der Syntax die sind toll (wenn man sich mal dran gewöhnt hat), aber manches finde ich doch sehr "erzwungen" geschönt :D
 

Landei

Top Contributor
Ja, es gibt einige Ecken und Kanten. Aber im Großen und Ganzen ist die Syntax ziemlich konsistent, und mit weniger Extra-Würsten als Java.
 

DaveX

Mitglied
Abgesehen davon, dass die letzten Beiträge am Thema vorbeilaufen, will ich zu der Problematik des RegEx zurückkehren.

@Antedeluvisch danke für das Beispiel, welches ich wahrscheinlich schon lange vor Dir gesehen habe.
Es geht mir nicht um das, sowas von geiles Extractor Pattern was Scala dem Programmierer bietet und bei Java vermisst wird.

Es ging mir um RegEx Ausdruck welches mir bestimmte Elemente aus dem HTML Source extrahiert.

Angenommen die Seite verfügt über ein select element.
Denn sollte man mit """.+(<select.+</select>).+""" extrahiert bekommen oder ?
Analog dazu müsse man die <table> extrahieren können.

Das ging bei mir leider nicht.
Wenn es geklappt hätte, würde ich jeweils das element in "( )" haben und müsste es weiter unterteilen in options / tr's.
Wei konnte das realisiert werden dass ich aus dem Extractor eine Liste bekomme mit den gematchten Elementen - die ja beliebig viele sein können.

Grüße
DaveX
 

Antedeluvisch

Neues Mitglied
...
@Antedeluvisch danke für das Beispiel, welches ich wahrscheinlich schon lange vor Dir gesehen habe.
Super :applaus:

Es ging mir um RegEx Ausdruck welches mir bestimmte Elemente aus dem HTML Source extrahiert.

Angenommen die Seite verfügt über ein select element.
Denn sollte man mit """.+(<select.+</select>).+""" extrahiert bekommen oder ?
Analog dazu müsse man die <table> extrahieren können.
Bist Du eventuell in die "is"-Todesfalle getappt? :autsch: Ich vermute mal, dass Scala auch PCRE als Grundlage hat, sollte ich noch mal nachlesen :rtfm:, aber Scala und ich... :eek:

Immer nachsehen ob man den Case mit "i" unberücksichtigt lassen kann und mit "s" alles als eine Zeile behandelt. Mag nicht immer ganz sauber sein, ist aber effektiver.
Ich weiß auch erhlichgesagt nicht ob man in Scala das "/" maskieren muss.

Also, ich komme aus einer ganz anderen Richtung, aber hier mal ein Ansatz um grundsätzlich die Inhalte der td's zu parsen und den relevanten Inhalt in einer Suchgruppe festzuhalten. So etwas aus dem Bauch heraus als PCREs ohne es getestet zu haben:

Code:
td.*?="planline0">(.*?)<\/td
oder allgemeiner
Code:
td.*?="planline.">(.*?)<\/td
oder für alle td's
Code:
td.*?=".*?">(.*?)<\/td
Wobei die Frage ist ob das sicher genug ist? Können da auch andere Tabellen, bzw. td's sitzen?

Man könnte ansonsten auch alle tds (bzw. deren Inhalte) einfach in einem Rutsch sequentiell auslesen und dann über die erste Suchgruppe den Typ auslesen (was für eine class es denn ist, dateline oder planline?)
Code:
td.*?="(.*?)">(.*?)<\/td
Dann könnte man nach einem "dateline" in der ersten Suchgruppe die dann eigentlich folgenden 8 (oder 16?) "planlines." weiter zusammengehörend (?) auslesen.

Natürlich kannst Du auch erst die Tabelle komplett via Regex auslesen (gerade hier auf "is" achten:reflect:) und dann das Ergebnis weiter bearbeiten
Code:
<table.*?>(.*?)</table>

Danach könntest Du Dir die zusammengehörigen td's aus diesem Ergebnis einsammeln, usw.
Aber das wird dann eher wieder komplizierter und man baut mehr Fehler ein, als dass man Ergebnisse bekommt.

Ist natürlich nur so aus dem Bauch heraus, da ich die HTML und potentiell störende Inhalte nicht kenne. Möglicherweise habe ich das Problem auch nicht richtig erfaßt :) Sonst schreib einfach noch einmal und ich versuche ein getestetes, valides Regex zu basteln.

Ach und von Scala habe ich auch keine Ahnung (schlagt mich ruhig :D)
 

Neue Themen


Oben