Andreas Bruns

Softwareentwicklung für Oldenburg und Bremen

Daten von Webseiten scrapen mit ScraperWiki

ScraperWiki ist ein Internetdienst, der Daten aus verschiedenen Quellen des Internets zusammenführt. Dabei betonen die Macher von ScraperWiki den kollaborativen Charakter ihres Dienstes. Ein Journalist kann beispielsweise eine Anfrage stellen, dass er bestimmte Daten für einen Artikel benötigt, die so zusammengeführt im Internet nicht verfügbar sind. Programmierer können sich dieser Anfrage widmen und ein entsprechendes Scraper erstellen, das die Daten von verschiedenen Webseiten scrapt und zusammenführt. Zusätzlich bietet ScraperWiki Visualisierungen, sogenannte Views, für die Daten an.

Der Programmierer wählt für das Erstellen eines Scrapers zwischen den Programmiersprachen Python, PHP, Ruby und neuerdings auch JavaScript. Die gesammelten Daten werden in einer Datenbank gespeichert und können als CSV, JSON oder SQLite Datenbank heruntergeladen werden. Zusätzlich bietet ScraperWiki eine Abfrage-API per HTTP. Die Abfrage lässt sich per SQL ausdrücken und die Daten stehen dann in verschiedenen Formaten zur Verfügung, wie JSON, CSV, HTML-Tabelle und RSS. Damit die Daten in der Datenbank aktuell bleiben, kann man bei ScraperWiki mit einem Timer festlegen, wie oft das Scraping der Daten durchgeführt werden soll.



Dann kommen wir jetzt mal zur Praxis. Der Wikipedia-Artikel Liste der Kernreaktoren in Deutschland enthält unter anderem eine Tabelle mit allen Atomkraftwerken in Deutschland. Die aufgelisteten AKWs sollen beispielsweise auf einer Karte mit Zusatzinformationen angezeigt werden. Dazu benötigen wir zum einen die Daten aus der Tabelle und zum anderen noch Detaildaten von der Wikipedia-Seite des jeweiligen AKWs (z.B.: Lage des AKWs und Bild). Mein Scraper ist hier verfügbar und die Daten sehen beispielsweise in JSON so aus: AKW-Daten in JSON

Ich habe mich für die Programmiersprache Ruby entschieden, weil die Ruby-Bibliothek Nokogiri zum Parsen von HTML/XML-Dateien sehr leistungsfähig ist. Das folgende Listing bietet einen ersten Überblick:

require 'nokogiri'
listAkwHtml = ScraperWiki.scrape('http://de.wikipedia.org/wiki/Liste_der_Kernreaktoren_in_Deutschland')
listAkwDoc = Nokogiri::XML(listAkwHtml)
listAkwDoc.css('body * table:nth-of-type(2) tr').each do |singleAkwRow|
  singleAkwCells = singleAkwRow.css('td')
  if (!singleAkwCells.empty?)
    akwData = {
      'kuerzel' => singleAkwCells[1].child.content,
      'bezeichnung' => singleAkwCells[0].child.content
    }
    puts akwData
    unique_keys = ['kuerzel']
    ScraperWiki.save_sqlite(unique_keys, akwData)
  end
end

Erläuterungen zu den Programmzeilen:

  • require 'nokogiri' – Bibliothek Nokogiri einbinden
  • listAkwHtml = ScraperWiki.scrape(...) – die Seite laden und das Ergebnis als String erhalten
  • listAkwDoc = Nokogiri::XML(listAkwHtml) – Wikipedia nutzt XHTML, also Nokogiri::XML(string) und nicht Nokogiri::HTML(string)
  • listAkwDoc.css('body * table:nth-of-type(2) tr').each do |singleAkwRow| – per CSS-Selektor die Zeilen der passenden Tabelle auswählen und über die Zeilen iterieren
  • singleAkwCells = singleAkwRow.css('td') – Array mit allen td-Elementen innerhalb einer Zeile erstellen
  • if (!singleAkwCells.empty?) – die Kopfzeile der Tabelle ignorieren
  • akwData = { – in einem Hash werden die Daten gesammelt
  • 'kuerzel' => singleAkwCells[1].child.content, – aus dem zweiten td-Element den Inhalt des ersten Kindes auswählen
  • puts akwData – den Hash zur Kontrolle auf der Konsole ausgeben
  • unique_keys = ['kuerzel'] – die Key-Spalten für die Datenbank definieren
  • ScraperWiki.save_sqlite(unique_keys, akwData) – den Hash eines AKWs abspeichern

Einfache Tabellendaten können wir mit singleAkwCells[X].child.content sehr gut auslesen. Etwas mehr Aufwand benötigen wir, wenn innerhalb des td-Tags mehrere Kinder vorhanden sind. Dann müssen wir beispielsweise Bindestriche oder <br>-Tags nachträglich bearbeiten. Manche Zellen sind übrigens unsichtbar und nur für das Sortieren der Tabelle vorhanden. Es kann trotzdem sinnvoller sein, die unsichtbaren Daten statt der angezeigten Daten zu benutzen, wie es beispielsweise bei dem leichter zu parsendem Datum der Fall ist.

Die Position des AKWs lässt sich nicht der Tabelle entnehmen, sodass wir zu der Wikipedia-Seite des jeweiligen AKWs navigieren müssen. Da Wikipedia eine Vorlage für die AKW-Seiten bereitstellt, sind alle Seiten glücklicherweise gleich strukturiert. Mit dem folgenden Code wird die URL des AKWs aus der Tabelle extrahiert, die entsprechende Seite aufgerufen, die Position als Latitude und Longitude ausgelesen und in den Typ Float umgewandelt. Die genauen Werte Latitude und Longitude werden übrigens auf der Seite gar nicht angezeigt, sondern sind innerhalb der Sektion #Infobox_Kernkraftwerk unsichtbar. Auf der Seite können wir uns auch gleich die URL von dem Bild des AKWs geben lassen.

singleAkwUrl = wikipediaUrl + singleAkwCells[0].search('a')[1].attribute('href')
singleAkwHtml = ScraperWiki.scrape(singleAkwUrl)
singleAkwDoc = Nokogiri::XML(singleAkwHtml)
singleAkwLongitude = Float(singleAkwDoc.css('#Infobox_Kernkraftwerk .longitude')[0].child.content)
singleAkwLatitude = Float(singleAkwDoc.css('#Infobox_Kernkraftwerk .latitude')[0].child.content
singleAkwImageUrl = wikipediaUrl + singleAkwDoc.css('#Infobox_Kernkraftwerk a.image img')[0].attribute('src')

Man muss ein bisschen mit den CSS-Selektoren herumspielen, bis man die passenden Elemente an der Hand hat. Die Firebug-Erweiterung Firefinder hilft entsprechende CSS-Selektoren und XPath-Selektoren zu finden. Damit haben wir unsere Daten und können jedes AKW gemeinsam mit einem hübschen Bild auf einer Karte darstellen. Leider gibt es noch einen Haken bei den Bildern. Während die Daten frei nutzbar sind, unterliegt jedes Bild gewissen Lizenzbedingungen, die wir eventuell gemeinsam mit dem Bild veröffentlichen müssen (siehe Wikipedia: Weiternutzung von Bildern und Mediendateien).

Kommentare sind geschlossen.