Nutzung von ConGen

 

 

Das folgende Kapitel ist ein Auszug aus dem Bericht zum Laborpraktikum „ConGen – Dynamische Content-Erweiterung von Webseiten“ von Nicole Mencke und Steffen Kernchen am Institut für Verteilte Systeme an der Otto-von-Guericke-Universität Magdeburg. Im weiteren Verlauf wird der grundsätzliche Umgang mit dem ConGen-System erläutert. Dabei wird zuerst auf die Nutzung der graphischen Benutzeroberflächen und danach auf das Erstellen eigener Parser eingegangen.

 

 

5.1 Die Oberflächen

 

Für eine problemlose Nutzung des ConGen-Systems wurden die GUI's ergonomisch gestaltet und die einzelnen logischen Bereiche klar voneinander differenziert. Für das Arbeiten mit dem System wurde ein Programminterface zum Arbeiten mit den Parsern und ein Datenbearbeitungsinterface bereitgestellt. Der Umgang mit ihnen wird in den nächsten  Abschnitten erläutert.

 

 

5.1.1 Programminterface

 

Die in Abbildung 1 dargestellte GUI dient zum Verwalten der Parser und zum Einleiten des Parsens.

 

 

Abbildung 1 Programminterface

 

 

Der obere Bereich der Oberfläche dient der ersten erwähnten Aufgabe. Über die Benutzung des Buttons '1' können neue Parser dem System hinzugefügt werden. Name und Standort auf dem Rechner werden dabei vom System gespeichert. Sie stehen dem System auch nach wiederholtem Start zur Verfügung und müssen nicht erneut integriert werden. Button '2' dient dem Löschen nicht mehr benötigter Parser. Dafür wird im Bereich 'A' der GUI der entsprechende Parser markiert und das Entfernen über das Betätigen dieses Buttons eingeleitet. Dabei wird nur die Referenz auf diesen Parser im ConGen-System gelöscht und nicht die Datei auf dem Rechner. Der untere Bereich des Programminterfaces dient dem eigentlichen Vorgang des Parsens. Dafür werden im Bereich 'B' die entsprechenden Parser markiert. Über den Button '5' wird das Parsen mit den markierten Parsern eingeleitet. Als Ergebnis wird eine XML- Datei mit den extrahierten Informationen erzeugt. Mit Hilfe des Buttons '3' können diese Informationen manuell kontrolliert, geändert und erweitert werden. Dafür öffnet dieser Button das Datenbearbeitungsinterface, welches im nächsten Abschnitt näher beschrieben wird. Button '4' dient der Darstellung der XML-Datei in einem vorher spezifizierten Browser. Ist noch kein Browser angegeben, erscheint ein Dialog, in welchem der Standort des Browsers auf dem Rechner angegeben werden kann. Der EXIT-Button '6' terminiert das ConGen-System.

 

 

5.1.2 Datenbearbeitungsinterface

 

 

Abbildung 2 Datenbearbeitungsinterface

 

Das Datenbearbeitungsinterface wurde ebenfalls für einen intuitiven Umgang mit dem System entwickelt. Es erlaubt die Kontrolle, die Änderung und das Hinzufügen bzw. Löschen von Konferenzdaten. Im linken Bereich 'A' der Oberfläche werden die extrahierten Informationen der jeweiligen Konferenz präsentiert. Zum Wechsel der Darstellung zwischen den Konferenzen dienen die Buttons, die unter '6' zu finden sind. Diese Buttons haben unterschiedliche Darstellungsmodi, um dem Nutzer intuitiv den Beginn und das Ende der Konferenzliste anzuzeigen. Neue Konferenzen können über den Button '1' hinzugefügt werden. Die aktuell angezeigte Konferenz kann über den Button '2' gelöscht werden. Diese und alle weiteren Änderungen werden erst durch das Betätigen der Buttons '3' oder '4' endgültig wirksam. Button '5' schließt die aktuelle GUI, ohne die bis dato getätigten Änderungen in die XML-Datei zu übernehmen.

 

 

5.2 Erstellen eigener Parser

 

Die Erstellung eigener Parser ist relativ simpel. Die Vorgehensweise ist vorgegeben und wird im weiteren Verlauf detailliert am Beispiel eines Parsers für die

Seite "http://www.multiagent.com/Conferences/Related Conferences/index.html" beschrieben. Der allgemeine Vorgang des Parsens ist dem Bild 3 zu entnehmen.

 

 

Abbildung 3 Interaktionsdiagramm: Parsen

 

 

 

5.2.1 Erste Schritte

 

Vor der Implementation der notwendigen Methoden des Parsers sind einige Punkte zu beachten. Jeder Parser, der für das ConGen-System entwickelt wird, ist vom Interface ConGenParserInterface abzuleiten. So wird sichergestellt, dass der Parser alle notwendigen Methoden enthält und die ermittelte Datenstruktur korrekt erzeugt wurde. Es werden vom ConGen-System nur Parser akzeptiert, die dieses Interface implementieren.

Zum besseren Verständnis des Interfaces wurde aus ihm eine Referenzklasse erstellt. Jeder ConGen-Parser enthält eine Reihe von globalen, privaten Variablen, die innerhalb des Konstruktors instantiiert bzw. initialisiert werden müssen. Dazu gehören:

 

 

 

5.2.2 Parsen des HTML-Quellcodes

 

Erster Ansatzpunkt der Informationsextraktion ist, wie schon in 4.2.1 beschrieben, die Extraktion der HTML-Tags aus dem HTML-Quellcode der gewünschten Seite mit der Methode parse(). Dafür wird zuerst ein Parser des HTMLParser-Paketes mit der gewünschten URL erzeugt:

 

Parser parser = new Parser(url, new DefaultParserFeedback());

 

Dieser erzeugt eine listenartige Datenstruktur, in welcher die einzelnen extrahierten Tags des Quellcodes, sogenannte Nodes, enthalten sind. Neben vordefinierten Scannern, welche nach den gängigsten Tags suchen, besteht die Möglichkeit eigene Scanner zu definieren. Für die normale Anwendung sollte dies aber nicht notwendig sein. Mittels eines NodeIterators kann nun über diese Datenstruktur iteriert werden. Sinn dieses Vorgehens ist es, alle Nodes, die zu einer Konferenz gehören, in einer NodeList zusammenzufassen. Sollte dies innerhalb dieser Methode nicht vollständig möglich sein, so stehen Methoden innerhalb der Klasse Wastebasket bereit. Eigene unterstützende Methoden sollten ebenfalls gut kommentiert dieser Klasse hinzugefügt werden, um für zukünftige Parserentwicklungen zur Verfügung zu stehen. Überflüssige Nodes, wie solche, die Tags für das Einfügen von Bildern oder die Formatierung von Text enthalten, können über die Methode clearEntrys(LinkedList) aus der Klasse Wastebasket aus den extrahierten NodeList entfernt werden.

Die Besonderheit der verwendeten Beispielseite ist, dass die Informationen zu den einzelnen Seiten als HTML-Listenelemente abgespeichert sind. So beginnt eine neue Node-List, sobald ein weiteres LI-Tag auftaucht. Die Node-Extraktion findet ihren Abschluss, sobald die HTML-Listenstrukturen geschlossen werden. So werden nur Nodes in die weitere Betrachtung einbezogen, die potentiell Informationen enthalten können.

Ergebnis dieser ersten Methode ist eine LinkedList entrys von NodeLists mit Text, der Informationen zu den einzelnen Konferenzen enthält. Diese Liste wird global abgespeichert, um zur Weiterverarbeitung zur Verfügung zu stehen.

 

Hinweise:

 

 

5.2.3 Einleiten der Informationsextraktion

 

Die eigentliche Informationsextraktion wird, wie das eben beschriebene Parsen des HTML-Quelltextes, ebenfalls außerhalb des Parsers eingeleitet. Dieses Vorgehen muss unbedingt eingehalten werden, damit aus dem ConGen-System auf den Parser zugegriffen werden kann. Die im Folgenden beschriebene getContents()-Methode leitet die Extraktion der einzelnen Informationen ein. Sie hat keine Parameter und gibt eine LinkedList mit Conf-Objekten zurück. Diese Objekte stellen die interne Datenstruktur zur Speicherung der Konferenzdaten dar. Im Folgenden wird über die in der parse()-Methode erzeugte LinkedList iteriert und deren NodeLists werden mittels noch zu beschreibender Methoden die Konferenzinformationen entzogen. Diese Informationen werden im Konferenzobjekt Conf gespeichert und dieses der LinkedList contents hinzugefügt, die zurückgegeben wird.

Die eben beschriebene Methode kann ohne Änderung von allen ConGen-Parsern implementiert werden. Bei den Extraktionsmethoden ist dabei auf eine korrekte Belegung der zurückgegebenen Datenstrukturen zu achten, da hier die entsprechenden Daten dem Conf -Objekt hinzugefügt werden. So muss beispielsweise das Datum, bis zu welchem die Paper eingetroffen sein müssen, das Jahr 1900 aufweisen, wenn keine entsprechende Information zu extrahieren war. Darüber wird die Belegung der booleschen Variablen noCFPDate geregelt, welche unkompliziert Auskunft über das Vorhandensein des entsprechenden Datums gibt.

 

Hinweise:

 

 

5.2.4 Methode findShortName(NodeList)

 

Diese Methode dient der Suche nach der Abkürzung des offiziellen Konferenznamens. Dafür wird der Methode die zu durchsuchende NodeList als Parameter mit übergeben. Die eigentliche Extraktionsarbeit wird von der Methode getPossibleShortNames(NodeList) erledigt. Sie liefert eine Liste mit möglichen Abkürzungen zurück. Unter Berücksichtigung der Informationsstruktur der Webseite wird die erste gefundene mögliche Abkürzung zurückgegeben und im entsprechenden Conf -Objekt abgespeichert. Kerngedanke dieser Informationsextraktion in der Methode getPossibleShortNames(NodeList) ist, dass bestimmte Wörter mögliche Abkürzungen sind, wenn sie mindestens zwei Großbuchstaben enthalten. Der Methodenablauf lässt sich kurz wie folgt skizzieren:

 

  1. Zerlegen aller Elemente der NodeList in einzelne Wörter (Methode: StringUtilities.separate(String, boolean, boolean)) und Sammlung dieser Wörter in einer LinkedList
  2. Iteration über jedes Wort und Überprüfung auf Existenz von mindestens zwei Großbuchstaben
  3. Hinzufügen aller gefundenen möglichen Abkürzungen zur Liste, die zurückgegeben wird

 

 

5.2.5 Methode findLongName(NodeList, String)

 

findLongName(NodeList, String) dient der Extraktion des vollständigen Namens der Konferenz. Die Methode hat zwei Parameter, die zu durchsuchende NodeList und die bereits extrahierte Abkürzung des Konferenznamens. Zurückgegeben wird der komplette Name der Konferenz, falls einer im HTML-Quellcode angegeben war. Hier zeigt sich ein weiterer  Grund, warum der Ablauf der getContents()-Methode nicht geändert werden sollte. Ohne eine bereits extrahierte Abkürzung ist das Auffinden des ganzen Konferenznamens nach dem  hier beschriebenen Muster nicht möglich. Natürlich sei es dem Nutzer freigestellt, einen eigenen Weg zum Extrahieren des Konferenznamens zu implementieren. In diesem Fall sollte ein leerer String als Parameter übergeben werden, um die Konsistenz des Parsers mit dem ConGenParserInterface zu gewährleisten.

Der Ablauf dieser Methode lautet im Groben:

 

  1. Erstellen eines Suchpatterns aus der Abkürzung des Konferenznamens
  2. Herausfiltern aller möglichen Sätze, die dem Suchpattern entsprechen
  3. Extraktion des vollständigen Konferenznamens

 

Das Suchpattern wird nach einem bestimmten Muster aufgebaut. Nähere Informationen dazu gibt es in der Java-API im Paket: java.util.regex.Pattern. In ConGen wird an dieser Stelle ein Suchpattern erzeugt und verwendet, das sich wie folgt aufbaut: an erster Stelle steht (betrachtet wird der Text innerhalb der Hochkommata) die Zeichenkette '.*'. Dadurch werden beliebige Folgen von Zeichen zugelassen. Danach folgt das erste Zeichen der Abkürzung des Konferenznamens, gefolgt von der Zeichenkette '[a-z].*'. Damit wird sichergestellt, dass mindestens ein Kleinbuchstabe auf den entsprechenden Großbuchstaben folgt. Danach sind weitere Zeichen möglich. Im weiteren Verlauf wird dieses Vorgehen für jedes Zeichen der Abkürzung wiederholt. Am Ende wird beispielsweise das Suchpattern für die Abkürzung 'ABC' so aussehen: '.*A[a-z].*B[a-z].*C[a-z].*'.

Im zweiten Schritt werden mögliche Sätze aus der NodeList extrahiert. Dafür wird zuerst der Text jedes Nodes dieser Liste mittels der Methode separateToSentences(String) aus der Klasse StringUtilities in Sätze zerlegt. Ebenfalls in dieser Klasse existiert die Methode findSentenceByPattern(String, String). Sie sucht aus allen Sätzen diejenigen heraus, die dem Suchpattern entsprechen. Dies passiert mit den vordefinierten Methoden des bereits angesprochenen java.util.regex.Pattern-Paketes.

Der dritte Schritt besteht in der Extraktion des eigentlichen Namens der Konferenz. Wieder wird sich einer Methode der Klasse StringUtilities bedient. getMatch(String,

String) liefert aus einem Text den minimalen Teilstring zurück, der dem Suchpattern entspricht. Dieser String ist der gesuchte Name der Konferenz und wird an die aufrufende getContents()-Methode zurückgegeben, wo er im entsprechenden Conf –Objekt abgespeichert wird.

 

Hinweise:

 

 

5.2.6 Methode findLocations(NodeList)

 

Wie bereits durch den Methodennamen zu vermuten ist, dient diese Methode der Extraktion des Ortes, an welchem die Konferenz stattfindet. Dafür erhält die Methode wieder die entsprechende NodeList als Parameter übergeben und gibt an die aufrufende getContents()-Methode ein Stringarray zurück. Dieses wird dort ausgelesen und die interessanten Werte im entsprechenden Conf -Objekt abgespeichert. An der nullten Stelle im Array ist die Stadt, in welcher die Konferenz stattfindet gespeichert. An erster Stelle der Staat und an zweiter Stelle das Land. Informationen über den Staat werden zwar im weiteren Verlauf nicht benötigt, aber vielleicht ist die Information im Sinne einer späteren Erweiterung sinnvoll. In der Beispiel-HTML-Seite wurden zwei mögliche Standorte des Austragungsortes der Konferenz identifiziert. Nach einer Separation des Textes der NodeList in einzelne Sätze wird der entsprechende Ort lokalisiert. In diesem Beispiel kann der Austragungsort am Ende oder in der Mitte eines Satzes stehen. Je nach Standort wird die weitere Bearbeitung eingeleitet. Diese Unterscheidung wurde angestrebt, um mögliche Satzzeichen in die Erkennung mit einzubeziehen.

Die eigentliche Erkennung erfolgt wieder über Suchpattern. Dafür wird vorher der entsprechende Satz mittels der Methode separate(String, boolean, boolean) in eine Liste von Worten zerlegt. Wichtig in diesem Zusammenhang ist die Methode trimm() der Supportklasse StringUtilities. Sie löscht Satzzeichen am Ende von Wörtern und entfernt Klammerungen.

 

 

5.2.7 Methode findDescription(NodeList)

 

Diese Methode ist relativ einfach gehalten, da im vorliegenden Fall die Beschreibung in einem bestimmten Knoten der NodeList gespeichert ist. Die einzig verbliebene Aufgabe stellt die Bereinigung des Textes von unerwünschten Eigenschaften dar. Dafür werden die folgenden Methoden der Klasse StringUtilities eingesetzt.

 

 

 

5.2.8 Methode findLink(NodeList, int)

 

findLink(NodeList, int) extrahiert den Link, unter dem weitere Informationen zur Konferenz zu finden sind. Für die Bearbeitung dieser Aufgabe werden der Methode wieder die entsprechende NodeList und hier zusätzlich noch die Position dieser NodeList in der globalen LinkedList entrys übergeben. Der Grund dafür ist die Bereinigung dieser Liste

von nun überflüssig gewordenen Textbestandteilen.

Für die Extraktion des Links wird in allen Nodes der NodeList nach dem String: "<A HREF=" gesucht. Auf diese Art wird in HTML-Seiten die Angabe eines Links eingeleitet.

Die einzig dann noch verbliebene Aufgabe ist die Extraktion des interessierenden Substrings und seine Rückgabe zur aufrufenden getContents()-Methode, wo die Information im entsprechenden Conf -Objekt abgespeichert wird.

 

 

5.2.9 Methode findDate(NodeList)

 

Zum Herausfiltern der Start- und Endtermine der Konferenz wurde die Methode findDate(NodeList) geschaffen. Als Parameter erhält sie die entsprechende NodeList. Zurückgegeben wird ein GregorianCalender-Array. Dieses enthält an der nullten Stelle das Startdatum und an erster Stelle das Enddatum der Konferenz. Nach der Initialisierung bestimmter Variablen wird im Beispielparser die Extraktion der gewünschten Informationen eingeleitet. Dafür wird zuerst der Text in Sätze zerlegt. Dann wird mittels eines Suchpatterns der Satz herausgefiltert, der eine vierstellige Zahl enthält. Dies ist das Jahr, in welchem die Konferenz stattfindet. Mit Hilfe der Methode getTwoNumbers(LinkedList) aus der Klasse DateUtilities werden aus einer Liste von Wörtern alle Zahlen extrahiert, die nicht aus vier Ziffern bestehen. Dabei werden auch Zahlen in Verbindung mit Buchstaben extrahiert (Bsp.: '12' aus '12th'). Das erste Element dieser Liste ist der Tag des Startdatums und das letzte Element ist der Tag des Enddatums der Konferenz.

In einem zweiten Schritt erfolgt die Extraktion der zugehörigen Monate. Dafür wird der Satz, welcher das Datum enthält in eine Wortliste zerlegt. Aus dieser Liste wird mit der Methode findMonth(LinkedList) aus der Klasse DateUtilities eine Liste der Monate ermittelt. Diese Methode ist nur einsetzbar, wenn deutsche oder englische Monatsnamen verwendet werden. Für weitere Sprachen ist diese Methode zu erweitern. Für eine andere Angabe der Monatsnamen sind eigene Methoden zu implementieren. Das erste Element dieser ermittelten Liste stellt den Monat des Startdatums dar und das letzte Element den Monat des Enddatums der Konferenz.

Im dritten und letzten Schritt wird das Jahr ermittelt. Dies erledigt die DateUtilities-Methode findYear(LinkedList). Sie sucht aus einer Wortliste das Jahr heraus. Das Jahr muss einem der folgenden Formate für Suchpattern entsprechen: "20\\d\\d", "19\\d\\d" oder ".*(\\xFA|\\x27|\\x60)\\d\\d\\D.*".

 

 

5.2.10 Methode findCFPDate(NodeList)

 

Dieser Methode wird ebenfalls die entsprechende NodeList als Parameter übergeben. Der Typ des Rückgabewertes an die aufrufende getContents()-Methode ist Gregorian-Calender. Auf der Grundlage dieses Wertes werden im entsprechenden Conf -Objekt das Datum, bis zu welchen die Paper eingesandt werden müssen und der boolesche Wert, der angibt, ob ein solches Datum vorhanden ist, gesetzt. Nachdem alle Texte der NodeList in Sätze zerlegt wurden, wird mittels der StringUtilities-Methode  findSentence(LinkedList, String) der Satz herausgesucht, welcher das gesuchte Datum enthält. Dafür wird dieser Methode das Suchwort "due" übergeben, nach welchem in den Sätzen gesucht wird. Die Informationsstruktur des Beispiels ist so organisiert, dass im Satz, welcher das gesuchte Datum enthält, dieses Suchwort vorhanden ist. Dadurch ist eine einfache Lokalisierung des entsprechenden Satzes möglich. Konnte kein potentieller Satz identifiziert werden, wird das Jahr des zurückgegebenen

Datums auf '1900' gesetzt, so dass in der getContents()-Methode das Setzen des booleschen Wertes erfolgen kann. Wurden potentielle Sätze gefunden, wird der letzte

dieser Sätze in Worte zerlegt. Mit Hilfe der Methode findDate(LinkedList) der Klasse DateUtilities kann das gesuchte Datum extrahiert werden.

 

 

5.2.11 Fazit

 

Im Verlauf der letzten Abschnitte wurde die Vorgehensweise der Parsererstellung an einem konkreten Beispiel beschrieben. Es wurde verdeutlicht, welche Konventionen einzuhalten sind. Die Implementation der eigentlichen Extraktionsmethoden bleibt der Kreativität des Anwenders überlassen, wobei dieser auf vorhandene unterstützende Methoden der lassen Wastebasket, StringUtilities und DateUtilities zurückgreifen kann. Eigene Erweiterungen in den Support-Klassen sollten gut dokumentiert werden. Dabei ist darauf zu achten, dass Erweiterungen vorhandener Methoden sehr vorsichtig vorzunehmen sind, da dadurch evtl. die Ausführung bereits existierender Parser eingeschränkt werden kann. Es ist weiterhin sinnvoll, nachdem aus einer Node alle Informationen extrahiert sind, diese aus der NodeList zu löschen, um den Bearbeitungsaufwand für die folgenden Extraktionsmethoden zu verringern.

Für weitergehende Informationen existiert der bereits erwähnte Bericht zum Laborpraktikum und der dokumentierte Quellcode. Weiterhin ist es möglich, sich mit den Autoren in Verbindung zu setzen.

 

 

 

 

 

 

 

Quellen: Bericht zum Laborpraktikum „ConGen – Dynamische Content-Erweiterung von Webseiten“ von Nicole Mencke und Steffen Kernchen