Rafazwonull vs Joe I/O


Crawling und große Dokumente: Marcels Herausforderung
24.02.2009, 2:12
Gespeichert unter: Datamining, In eigener Sache, Studium | Schlagworte: , , ,

Marcel hat gerade  die 5000-Comments-Challenge des Smashing-Magazine als Herausforderung für den Crawler zugetwittert, die ich gerne annehme.

Die ersten drei Mal habe ich einen Timeout bekommen, was mir im Augeblick aber auch im Browser passiert und bei einer 1,6 MB großen HTML (denke ich) für das erste ok ist. Das vierte Mal lief der Crawler erfolgreich durch, wenn auch nicht schnell. Damit ergeben sich einige interessante mitgeloggte Features, von denen ich hier einen Teil aufführe. Ich widme sie: Marcel.

nrOutLinks: 2629
nrOutLinksSameHost: 258
fileSize: 1572606
nrDOMElems: 20672
nrTagMeta: 8
nrTagTable: 2
nrTagTd: 6
nrTagTr: 3
nrTagH1: 2
nrTagH2: 1
nrTagP: 0
nrTagB: 0
nrTagScript: 38
nrTagLayer: 0
nrTagStyle: 0
nrTagHr: 0
nrTextLayoutTags: 2298
nrTagCursBold: 17
nrTagFont: 0
linkLabelLengthDev: 13.0
linkLabelLengthMedian: 13.0
linkLabelLengthAve: 13191616766467000
nrTagFrameset: 0
nrTagForm: 2
nrSentenceMarkers: 6171
nrTableInTables: 0
blanksInText: 54122
lengthTitle: 73
lengthPureText: 304992
uniqueWordsPureText: 3895
nrWordsPureText: 16835
nrStopwordsPureText: 5623
nrImgLinks: 2322
relationLinksToLinksToSameHost: 0.09813617
nrhtmlLinkstoFeeds: 7
nrAlternateLinkstoFeeds: 1

Wer will, kann gerne nachzählen.

-r-



Last und Lust des Crawling
22.02.2009, 16:34
Gespeichert unter: Datamining, In eigener Sache, Studium | Schlagworte: , , ,

Nachdem ich ja kürzlich schon grob auf die Kernidee meiner Arbeit eingegangen bin, will ich jetzt die Gelegenheit nutzen, über meine Erfahrungen mit dem Crawler ein wenig mehr zu berichten.

Mein Bot basiert auf dem OpenSource-Projekt JoBo1.4. Auf der Seite wird ein wenig tiefer gestapelt als notwenig, denn es heißt, JoBo verfolge Links und lade die Seiten herunter, im Prinzip es ist aber ein tolle Grundlage für einen Crawler. Mit dem Aufrufen der Seiten ist aber noch nicht getan, denn ich könnte im besten Fall einen Batzen Quellcode auslesen, ohne aber auf die Struktur des Dokuments schließen zu können, in der ganz wesentliche Informationen über die Seite stecken. In AQUAINT wurde schon implementiert, dass die aufgerufenen HTML-Seiten mit JTidy geparst und in DOM überführt werden, so dass ich die Markup-Informationen effektiv nutzen kann.

In diesem Rahmen sind nun die anderen Pakete und Klassen angeordnet, die unterschiedliche Fähigkeiten haben, und unterschiedliche Teile eines Blogs analysieren:

HTMLAnalyzer

Aus AQUAINT stammt der HTML-Analyzer, der gut 100 Markups analysiert und mitloggt. Wenn sich herausstellt, dass die Seite, auf die der Crawler trifft eine Blog sein sollte, wird diese Klasse aufgerufen, um entsprechende Features mitzuloggen. Wie ich schon im letzten Beitrag geschrieben habe, passiert die Überprüfung, ob ein Blog vorliegt, ganz simpel mit der Analyse, ob im Header des Blogs die Information über einen verfügbaren ALTERNATE Feed vorliegt. Mir ist bewusst, dass das kaum ausreicht, um definitiv zu sagen, ob ein Blog vorliegt, denn auch Seiten, die keine Blogs, sondern ganz einfach redaktionell erstellte Nachrichten sind, verfügen inzwischen über Aggregationen. Dennoch will ich den Raum für alle Arten von möglichen Blogs übrig lassen, denn es gibt auch ausgezeichnete redaktionell erstellte Blogs, die zwar geprüft sind, und eher dem Konzept einer Zeitung näher kommen, aber immernoch der Kategorie Blog zuzuzählen sind. Der Übergang ist leider fließend, und ohne einen Katalog, die Reduzierung auf einige blogtypische Hosts wie WordPress oder Blogspot, oder eine qualitative Analyse, ist wirklich schwer zu sagen, ob ein Blog vorliegt oder Online-Nachrichten. Das ist leider eine Ungenauigkeit, die ich wohl akzeptieren muss.

Wrapper

Zusätzlich ist ein Wrapper implementiert, d.h. eine Klasse, die eine Reihe von Suchmaschinen aufruft, um Rang, Inlinks der Seite usw. zu prüfen. Beliebt ist diese Methode nicht gerade bei Suchmaschinenanbietern, weil sie eine Menge Last erzeugt. Um meine IP nicht bei der dritten Seite bannen lassen zu müssen, habe ich eine Verzögerung im Wrapper eingebaut, die soweit angepasst werden kann, dass der Wrapper in seinem Seitenaufrufverhalten kaum von einem echten Nutzer zu unterscheiden sein sollte. Er funktioniert bei den meisten Seiten recht problemlos.

Bloganalyzer

Eine Kernklasse des Blog-Bots ist der BlogAnalyzer. Er analysiert all die Kriterien eines Blogs, die HTMLs üblicherweise nicht haben, und die der HTML-Analyzer dementsprechend auch nicht analysiert. Dazu gehören z.B. die Anzahl der Kommentare auf einer Seite, die Anzahl der Tags und Kategorien, usw. Problematisch ist hier vor allem, dass Standards fehlen und mein BlogAnalyzer natürlich oft nicht weiß, wonach er suchen soll. Ich hatte anfangs die Idee, die Blogroll zu analysieren, soweit vorhanden. Auch, wenn es einige wirklich gute Initiativen gibt, z.B. XOXO als Standard durchzusetzen, halten sich nicht alle Blogger und Bloganbieter daran, so dass es hier kein standardisiertes Markup gibt. Blogrollanalyse böte zwar interessante weitere Möglichkeite, z.B. zu prüfen welche Authority die verlinkten Sites besitzen, scheitert vorerst aber ganz trivial am Fehlen der Standards.

FeedAnalyzer

Eine weitere wesentliche Klasse, und eine, auf die ich besonders stolz bin, ist mein FeedAnalyzer. Der FeedAnalyzer z.B. liefert mir Informationen über die Anzahl der Beiträge, die durchschnittlichen Intervalle zwischen den Veröffentlichungen einzelner Posts und über die Länge ihrer Titel. Besonders interessant werden die Möglichkeiten bei Kommentarfeeds, über die  z.B. die Anzahl der Kommentierenden ermittelt werden kann. Ich analysiere nur RSS2.0-Feeds, weil die vermeintlich am weitesten verbreitet sind. Atom ist zwar das neuere und stärker detaillierte Format, allerdings wird es nicht von allen Blogs angeboten, und so ist RSS2.0 meist der kleinste gemeinsame Nenner. Bei allen modellierten Features ist es wichtig, dass sie beim Großteil aller Blogs mehr oder weniger gut funktionieren, denn wenn eine hochspezialisierte Methode bei 3/4 der Kollektion Exceptions wirft und abstürzt, habe ich keine aussagekräftigen Zahlen. RSS bietet schon eine ganze Menge, ist schon schön in XML aufbereitet und kann gut von einem weiteren auf SAX basierenden Parser analysiert werden. Ich hatte an dieser Stelle auch versucht mit ROME zu arbeiten, das eine Weiterentwicklung für alle möglichen Aggregationsformate darstellt, bin aber leider gescheitert: irgendwie hat ROME nicht die Funktionen bereitgestellt, die ich brauchte, und so kam es zu kaum ordentlichen Ergebnissen. Zwar wurde die Seite schön geparst, ich konnte aber nicht auf einzelne Elemente von Feeds zugreifen. So nutze ich ROME derzeit nur, um zu prüfen, welche Art von Feed vorliegt, bevor ich den FeedAnalyzer losschicke, was eigentlich Verschwendung ist… Wenn sich jemand gut mit ROME auskennen sollte, sind Tips hoch geschätzt!

Die Sache mit der Zeit…

Der Crawler ruft, wenn man ihm eine Kollektion von Seiten gibt, nicht nur durch den Wrapper, sondern vor allem durch den BlogAnalyzer eine ganze Menge zusätzlicher Seiten auf, d.h. für jede Seite, die ich ihm zur Analyse vorgebe greift er gut 25 Mal auf per HTTP-GET auf irgendeinen Server zu. Demenstprechend produziert er ein wenig Last. Ich habe die Belastung anderer Server zwar durch die Drosselung verringert, allerdings grenzt das aufrufen von 25 Seiten innerhalb von 1,5 Minuten schon an geschäftliche Nutzung, so dass es nur eine Frage der Zeit ist, bis mein Provider mir zornige Emails schreibt. Der Crawler läuft also seit geraumer Zeit nur noch auf dem Server der Uni. Das hat weitere Vorteile, denn der Server ist natürlich auch um einiges fixer als mein Rechner bei der Berechnung einiger Features. Trotzdem ist es vielleicht von Interesse, wenn ich einige Zahlen nenne, damit ihr die Dauer einer Crawlsession einschätzen könnt:

Für die Analyse einer Seite braucht der Crawler gut 1,5 Minuten, ruft dabei 25 weitere Seiten auf und pausiert einige Sekunden zwischen ihnen. Meine kleine kontrollierte Kollektion von Blogs ist 300 Seiten dick, meine unkontrollierte derzeit 2400. Für die Analyse meiner kontrollierten Kollektion braucht mein Crawler vom Server aus etwa einen Tag, bei der großen hat es letztens 4-5 gedauert. Diese Dauer wird noch um einiges vervielfacht, wenn ich einige meiner Testanalysen zuschalte, die sich noch akut im Beta-Stadium befinden, und so noch nicht zur Analyse großer Kollektionen herangezogen werden.

Wie eine LogFile des Servers aussehen kann, seht ihr unten. Die Analyse ist nicht ganz sauber gelungen, was in diesem Fall an unsauberem XML im Feed lag.

http://bulgariana.blogspot.com/ 19 Feb 2009 16:31:27 GMT
text/html; charset=UTF-8

***Alternate feed found. Should be a Blog here!
***Starting to log HTML features!

***Starting Stopword Analysis

***Starting Wrapper with 11 sec SleepTime
***Finishing Wrapper

***Starting BlogAnalyzer
***Finishing BlogAnalyzer

***Trying to find Alternate Feeds
***Alternate Feed found: http://bulgariana.blogspot.com/feeds/posts/default
***Feed Type: rss_2.0
***Alternate Feed found: http://bulgariana.blogspot.com/feeds/posts/default?alt=rss
***Feed Type: rss_2.0
***More than single alternate RSS2.0 feed found: 2
***Applying heuristics.
***Got single alternate feed: http://bulgariana.blogspot.com/feeds/posts/default

***Starting to log RSS features
19.02.2009 17:32:49 hellmann.quality.AnalyzedURL setFeature
SCHWERWIEGEND: Fehler bei SetFeature: null
***Feed successfully analyzed.
***Processing HTMLLinks heuristically to find Comments Feed
*Error parsing CommentsFeed: Invalid XML: Error on line 42: The entity name must immediately follow the ‘&’ in the entity reference.
*Error parsing CommentsFeed: Invalid document
***RSS Comments Feed Determination failed

-r-



Qualitätsmodelle und Data Mining in Blogs
17.02.2009, 1:57
Gespeichert unter: Datamining, In eigener Sache, Netzkultur, Studium | Schlagworte: , , , ,

Ich muss nicht in meiner Freizeit bloggen, denn mit Blogs beschäftige ich mich schon jetzt auch während der Uni bis zum Umfallen. Ich habe Marcel davon erzählt und auch Stefan, und alle waren der Meinung, dass ich über meine Blog-Magisterarbeit bloggen soll. Meta-Blogging sozusagen. Ich habe das lange vor mir hergeschoben, aber inzwischen will mir niemand mehr zuhören (ich scheine ein ziemlicher Fachidiot geworden zu sein in den letzten Wochen), und ich fange lieber an, das jetzt als Beitrag zu verarbeiten, bevor ich tatsächlich Freunde verliere.

Seit Robert Basic seinen Blog verkauft hat, ist endlich auch in Deutschland klar, dass Blogs von hoher Qualität sowohl wirtschaftliche als auch gesellschaftliche Bedeutung haben können. In den Staaten gibt es diesen Trend schon lange: Huffingtonpost ist (zumindest gefühlt) seitdem es das Internet gibt auf Platz 1 bei Technorati. Blogs sind also zu einem mehr oder weniger festen Bestandteil unserer Medienlandschaft geworden, und vor allem den besonders hochwertigen und oft referenzierten A-Listern (oder auch Power-Bloggern) scheint dieser Trend zuzuschreiben zu sein.

Unser Blog ist kein A-Lister. Er ist vielleicht auch nicht besonders hochwertig. Trotzdem hat er sicherlich einige Kriterien, die ihn wiederum qualitativ von schlechteren Blogs abheben. Vielleicht ist es eine gewisse Update-Frequenz, allerdings kann man Blogs auch mit Spam updaten. Möglicherweise ist es eine bestimmte Bandbreite an Themen, oder aber auch eine gewisse Sorgfalt, mit der er designt und die Beiträge verfasst wurden. Vielleicht ist es die Beitragslänge. Oder aber die Länge aller Beiträge zusammen. Oder die Kombination mehrerer Kriterien. Keiner kann das so definitiv sagen, und wenn auch die meisten bestimmte Vermutungen haben („NEIN! Die Anzahl der Zeichenumbrüche kann es niemals sein!“), geht das, was man mit Sicherheit sagen kann, bislang nicht allzu weit über eben diese Vermutungen hinaus.

Hier kommt jetzt meine Arbeit ins Spiel. Keiner möchte Tausende von Blogs auf übereinstimmende Kriterien überprüfen, zumindest nicht händisch (auch, wenn Leitfragen zu konstruieren und Sie anhand von 7 Blogs exemplarisch zu beantworten, die normale Vorgehensweise an unserer Uni wäre). Was man dazu braucht, ist ein ordentlicher Bot, der eine vorgegebene Kollektion durchgeht, Links verfolgt, und alle interessanten Features mitloggt. Genau das passiert hier.

Ich bin sicherlich kein guter Programmierer. Da sind andere besser, und ich danke dem OpenSource-Prinzip und allen, die irgendwie etwas mit ihm zutun haben, schon einmal pauschal: Mein Crawler basiert auf Java1.6 und nutzt crawlerseitig ganz wesentlich die Bestandteile des OpenSource-Tools JoBo, das im Rahmen des Projektes AQUAINT an der Uni Hildesheim für die Automatische Qualitätsabschätzung von HTML in Form einer Suchmaschine implementiert wurde. Ich nutze einen Teil der in AQUAINT modellierten Features und Klassen, und habe auf Basis einiger weiter frei verfügbarer Klassen einen Crawler mit folgender Struktur zusammenprogrammiert:

bc_architektur

Blogcrawler Architektur in Java1.6

Die Dokumente, auf die der Crawler stößt, werden mit den org.w3c Paketen in ein DOM überführt, sofern es sich um HTML-Dokumente handelt. Ich verfolge keine Dokumente weiter, die keine HTMLs sind, allerdings verzichte ich auch auf Dokumente, die keine Feeds in ihrem Header ausgezeichnet haben. Wenn man davon ausgeht, dass die Möglichkeit, einen Blog per Feed zu abonieren, ein wesentliches Kriterium für einen Blog ist, kann man hier schon die erste Einschränkung machen, um eine saubere Kollektion zu gewährleisten, sodass im Endeffekt folgende Zeilen bestimmen, ob die Site weiterverfolgt werden soll oder nicht. In unserem Fall sieht der relevante Teil des Headers folgendermaßen aus:

<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="de">
<head>
<title> Rafazwonull vs Joe I/O</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<style type="text/css" media="screen">
		@import url( http://s3.wordpress.com/wp-content/themes/pub/benevolence/style.css?m=1232213194b );
	</style>
	<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://rafazwonull.wordpress.com/feed/" />
	<link rel="pingback" href="http://rafazwonull.wordpress.com/xmlrpc.php" />

Was bedeuten diese Zeilen für die Analyse? Allein durch den Header, lassen sich an sich schon folgende Aussagen treffen:

  • Es könnte sich um einen Blog handeln, denn wir können ihn abonieren.
  • Es ist ein Blog, der nur das Format RSS2.0 unterstützt.
  • Der Titel ist in unserem Fall 23 Zeichen lang, was relevant wird, wenn man bedenkt, dass es Spamblogs gibt, die etwa den Titel „Zeichnen-Backen-Basteln-mit-Fingermalfarben-und-Salzteig“ haben…

Ich habe mich inzwischen auf diese und ähnliche Weise mit Blogs beschäftigt, und rund 150 Features in Java modelliert, die z.T. aus der Literatur, teils aus AQUAINT kommen, und z.T. selbst entwickelt sind. Sie lassen sich grob in die folgenden Bereiche gliedern:

  • Datei-Maße (z.B. Dateigröße).
  • HTML- Maße (z.B. <br>-Tags).
  • Tabellen-Maße
  • Listen-Maße (z.B. <li>-Tags)
  • Farbmaße
  • Verhältnismaße (d.h. Berechnung von Featuren, oder Kombination)
  • Sprachliche Maße (d.h. Anzahl von Wörtern und Satzzeichen).
  • RSS-Maße (d.h. alles, was man über die Feeds erfährt)
  • Reputationsmaße (d.h. alles, was mit durch HITS oder PageRank-basierte Verfahren erfährt)

Eines dieser Kriterien sagt sicherlich nichts isoliert über die Beschaffenheit von qualitativ hochwertigen Blogs aus, die eine große Leserschafft haben, hochwertige Artikel und ein gutes Renommé. In ihrer Kombination, und sagen wir mal, über eine Kollektion von einem guten Tausend Blogs schaffen wir es durch den Abgleich und die Prüfung von sinntragenden Strukturen Korrelationen zu ermitteln, Features sinnvoll zu clustern usw. – kurz, alles, was mit durch die Möglichkeiten des Data Mining über zusammenhangslos scheinenden Daten ermitteln kann. Einige von diesen Zusammenhängen sind sicherlich offensichtlich, z.B. der Zusammenhang von Authority und InLinks. Bei anderen greift wiederum nur die statistische Analyse von großen Mengen an Datensätzen.

Mal schauen wie es damit weitergeht, vielleicht schreibe ich beizeiten noch ein wenig mehr hierzu, und halte euch auf dem Laufenden.

Soviel dazu. Gute Nacht.

-r-