Die neue Zeit-API

Am 21. Februar 1946 erschien die erste Ausgabe der Zeit. Seitdem haben Journalisten, Redakteure, Drucker und Archivare einen riesigen Artikel-Berg angehäuft. Führen wir uns den technologischen Wandel vor Augen, der seit dem stattgefunden hat, wird uns die Herausforderung bewusst, diesen gedruckten Schatz der Öffentlichkeit nutzbar (also digital) zur Verfügung stellen zu wollen. 2006 begann die Zeit mit diesem Projekt: Man lese Die Digitalisierung des ZEIT Archivs .

Nun ist eine Programmierer-Schnittstelle zu den Metadaten des Archives (also eine API) als Beta-Version online geschaltet worden. Die Nachricht kam Freitag 23.11. über den Open-Data-Blog der Zeit. Die Idee einer solchen API kommt aus der Erkenntnis, dass durch die Digitalisierung der Artikel, deren Inhalte noch längst nicht aus dem Dunkelgrau des Kellers befreit sind. Dazu bedarf es intelligenter und praktikabler Endanwendungen, die auf die Daten zugreifen, sie auswerten und anzeigen. Die Veröffentlichung der Schnittstelle ist als Einladung an Programmierer zu verstehen, sich mit den Daten auseinanderzusetzen und Nutzungs-Szenarien zu entwickeln.

Das wollte ich mir auch mal anschauen. Startpunkt ist die Web-Site des Projektes http://developer.zeit.de/. Da liest man dann am besten erstmal die Nutzungsbedingungen. Wenn man kein kommerzielles Interesse hat, ist man schon mal auf der richtigen Seite. Man muss aber zwischen der Nutzung der Schnittstelle und der Nutzung der Inhalte der Artikel unterscheiden. Für letztere gelten natürlich die Urheberrechte der Autoren und die allgemeinen Nutzungsbedingungen von Zeit-Online. Ach ja: Zur Zeit bietet die API noch keinen Zugriff auf die Text-Inhalte der Artikel. Zu jedem Artikel gibt es aber einen Link zu einer Zeit-Online-Webseite, auf der der Text angezeigt wird.

Ohne Registrierung geht heute natürlich nichts. Unter “Quick Start” kann das geschehen, in dem man Name und Email-Adresse angibt. Dann bekommt man einen Zugriffscode, den man für jede Schnittstellen-Abfrage verwenden muß. Die Registrierung bewirkte bei mir im IE aber einen Javascript-Fehler, sodass ich auf den Firefox ausgewichen bin. So hatte ich dann meinen Zugang und konnte über “API Explorer” auf den Developer-Web-Seiten erste Abfrageerfahrungen bekommen.

Technisch ist die API eine sogenannte REST-Schnittstelle. Das bedeutet, dass man an einen Web-Server eine HTTP-Anfrage stellt, und dieser statt mit einer Web-Seite mit einem einfach strukturiertem Text-Output antwortet, der das Ergebnis der Anfrage enthält. Für die Output-Formatierung wird JSON verwendet. Das sieht zum Beispiel so aus: Die Anfrage

http://api.zeit.de/author?q=*Martenstein*

ergibt den Output

{
  "matches": [
  {
    "type": "author",
    "uri": "http://api.zeit.de/author/Harald-Martenstein",
    "value": "Harald Martenstein"
    },
  { 
    "type": "author",
    "uri": "http://api.zeit.de/author/Martenstein",
    "value": "Martenstein"
    }
  ],
  "found": 2,
  "limit": 10,
  "offset": 0
  }

Der von mir geschätzte Autor Harald Martenstein muss hier als Versuchskaninchen herhalten. Aber wie stellt man so eine Anfrage eigentlich unabhängig von dem API-Explorer auf der Web-Seite. Am einfachsten kann man versuchen die Anfrage als URL in seinem Web-Browser einzugeben. Man muss aber noch den Zugangscode als weiteren Parameter mit übergeben. Unsere Anfrage lautet dann z.B.

http://api.zeit.de/author?q=*Martenstein*&api_key=qwert1234567890

Firefox zeigt mir das Ergebnis direkt als Text an. Der Internet-Explorer weiss aber nichts damit anzufangen und bietet mir an, es abzuspeichern. Danach kann ich es dann mit einem Text-Editor öffnen.

Soweit der erste Eindruck. Es ergeben sich jetzt drei Fragenkomplexe:

  • Die Frage nach den Details der Schnittstelle: Welche Abfragemöglichkeiten bietet die Schnittstelle im Detail und wie sehen dann jeweils die Antworten aus. Wie sind die Daten technisch strukturiert.
  • Die Frage nach technischen Möglichkeiten: Wie kann ich mit einer solchen Schnittstelle umgehen, und sie in Anwendungen einbauen.
  • Die Frage nach dem Inhalt: Was steckt denn wirklich drin in dieser Datenbank und welche Qualität hat der Inhalt.

Die Frage nach den Details

Es gibt verschiedene sogenannte “Endpunkte”. Oben habe ich den Endpunkt “author” verwendet. Jeder Endpunkt bietet die Möglichkeit einer Suche an (http://api.zeit.de/author?q=…) und die Möglichkeit mit der Angabe einer Id ein konkretes Datenobjekt anzusprechen (http://api.zeit.de/author/Martenstein). Bei einer Suche bekommt man die Liste der Suchergebnisse (s.o.) angezeigt, aber beschränkt auf eine Anzahl “limit”. Dieser Parameter wird defaultmäßig auf 10 gesetzt. Man kann Ihn aber verändern in dem man zB die Anfrage http://api.zeit.de/author?q=*stein*&limit=20 formuliert. Der Ausgabe-Parameter “found” sagt uns, dass 129 Objekte gefunden wurden, aber nur 20 werden angezeigt. Die nächsten 20 bekommt man mit derAbfrage http://api.zeit.de/author?q=*stein*&limit=20&offset=20 .

Ruft man ein konkretes Objekt auf, so bekommt man auch alle damit verknüpften anderen Objekte angezeigt. Bei einem Autor ist das die Liste der Artikel dieses Autors, und bei einem Artikel (Endpunkt “content) ist es die Liste der Autoren und eine Liste von Schlagwörtern (Endpunkt “keyword”) und weiteres. Z.B ergibt dieser Martenstein-Artikel über “Mainstream” und “Schwarminteligenz” mit der URI (Uniform Resource Identifier) http://api.zeit.de/content/3iPD4MgYlRa4rr1zJCHFp0 den Output

{
  "creators": [
  {
    "uri": "http://api.zeit.de/author/Harald-Martenstein",
    "rel": "author",
    "name": "Harald Martenstein"
    }
  ],
  "subtitle": "Er beherrscht Medien, treibt Minister aus dem Amt und wechselt alle paar Jahre die Richtung: Der Mainstream hat gewaltige Kraft \u2013 er ist der Geist der Mehrheit. Aber hat er deshalb recht? Ein Essay",
  "title": "Der Sog der Masse",
  "release_date": "2011-11-10T06:00:00Z",
  "uri": "http://api.zeit.de/content/3iPD4MgYlRa4rr1zJCHFp0",
  "relations": [
  {
    "uri": "http://api.zeit.de/content/1xD2amStxoI8VBLUAzhWQm",
    "rel": "related",
    "name": "Der Sog der Masse"
    },
  {
    "uri": "http://api.zeit.de/content/63eeTFG26WQ2I0lSJCuIsg",
    "rel": "related",
    "name": "Der Sog der Masse"
    }
  ],
  "supertitle": "Mainstream",
  "href": "http://www.zeit.de/2011/46/DOS-Mainstream",
  "teaser_text": "Er beherrscht Medien, treibt Minister aus dem Amt und wechselt alle paar Jahre die Richtung: Der Mainstream hat gewaltige Kraft \u2013 er ist der Geist der Mehrheit.",
  "keywords": [
    {
      "uri": "http://api.zeit.de/keyword/guido-westerwelle",
       "rel": "person",
       "name": "Guido Westerwelle"
       },
     {
       "uri": "http://api.zeit.de/keyword/angela-merkel",
       "rel": "person",
       "name": "Angela Merkel"
       },
    {
       "uri": "http://api.zeit.de/keyword/karl-theodor-zu-guttenberg",
       "rel": "person",
       "name": "Karl-Theodor zu Guttenberg"
       },
     {
       "uri": "http://api.zeit.de/keyword/harald-schmidt",
       "rel": "person",
       "name": "Harald Schmidt"
       },
    {
      "uri": "http://api.zeit.de/keyword/gruene",
      "rel": "organization",
      "name": "Gr\u00fcne"
      },
    {
      "uri": "http://api.zeit.de/keyword/usa",
      "rel": "location",
      "name": "USA"
      },
    {
      "uri": "http://api.zeit.de/keyword/bundestag",
      "rel": "subject",
      "name": "Bundestag"
      },
    {
      "uri": "http://api.zeit.de/keyword/schwarmintelligenz",
      "rel": "subject",
      "name": "Schwarmintelligenz"
      },
    {
      "uri": "http://api.zeit.de/keyword/galileo-galilei",
      "rel": "person",
      "name": "Galileo Galilei"
      }, 
    {
      "uri": "http://api.zeit.de/keyword/talkshow",
      "rel": "subject",
      "name": "Talkshow"
      }
    ],
  "teaser_title": "Der Sog der Masse",
   "categories": [
     {
       "uri": "http://api.zeit.de/department/gesellschaft",
       "rel": "department",
       "name": "Gesellschaft"
       },
    {
      "uri": "http://api.zeit.de/product/zei",
      "rel": "product",
      "name": "DIE ZEIT"
      },
    {
      "uri": "http://api.zeit.de/department/zeitgeschehen",
      "rel": "sub_department",
      "name": "Zeitgeschehen"
      }
    ]
  }

Darin ist auch der Parameter “href” verborgen, womit ein Link auf den Arikel im Zeit-Online-Angebot gegeben wird: http://www.zeit.de/2011/46/DOS-Mainstream

Die Frage nach der Technik:

Am besten begibt man sich für den Anfang auf eine Linux-Kommandozeile. Da gibt es die Kommandos “wget” und “curl”. Ich beziehe meine Beschreibung auf curl. Studenten oder Mitarbeiter unserer Uni können sich auf einen der Linux-Login-Server stud.uni-due.de oder staff.uni-due.de mit ihrer Unikennung einloggen. Da ist curl und auch wget verfügbar. Der Aufruf von curl hat im einfachsten Fall die Form

curl URL

Man sollte die URL aber in Hochkomma einschließen. Das Zeichen &, das ja in solchen URLs oft vorkommt, würde sonst vom Kommandointerpreter falsch interpretiert. Details zu curl erfragt man mit curl --help . Die Zeit-API bietet auch die Möglichkeit den Zugangscode als einen http-Header mit zusenden und nicht als Parameter im Query-String, wie wir es oben gemacht haben. Dann würde eine Schnittstellen-Anfrage so aussehen.

curl -H 'X-Authorization: 1234567890qwert' 'http://api.zeit.de/...die Anfrage...'

Wir wollen nun anreißen, wie man so eine REST-Schnittstelle mit JSON-Output in einer AJAX-Web-Anwendung nutzen kann. Die vier Buchstaben AJAX bedeuten, dass eine vom Web-Browser dargestellte Web-Seite Javascript-gesteuert Daten per http nachläd, diese mit Javascript verarbeitet und durch dynamische Veränderung der Seitenstruktur die Daten darstellt (dynamisches HTML).

Um mit Javascript einen HTTP-Request abzusetzen stellen die heutigen Browser ein spezielles Objekt bereit. Zuerst muss man davon eine Instanz erzeugen:

var httpRequest = new XMLHttpRequest();

Wir benötigen eine Funktion, die die Antwort des Request auswertet und auf das Request-Objekt als globale Variable zugreifen kann. Sagen wir

function antwort_auswerten() {
  …
  }

Diese Funktion muss mit dem Request-Objekt verbunden werden:

httpRequest.onreadystatechange = antwort_auswerten;

Mit dem folgenden Befehl wird der Request formuliert, aber noch nicht gesendet:

httpRequest.open('GET', url);

Der Befehl führt zu einem Fehler, wenn die Sicherheitseinstellung des Browsers die Aktion nicht zuläßt. Beim Internet-Explorer trat dieses Problem bei mir auf. Ich konnte es lösen, indem ich die Site “api.zeit.de” unter “Extras, Internetoptionen, Sicherheit, lokales Internet” unter “Sites, erweitert” aufgenommen habe, und den Bereich “lokales Internet” von der Sicherheitsstufe “mittel” nach “niedrig” oder “sehr niedrig” verschoben habe. Bei “niedrig” wird man bei jedem Request nochmal gefragt, ob man ihn zulassen will. Bei “sehr niedrig” geht es einfach durch. Als sicherheitskritisch wird hier auch bewertet, wenn eine Web-Seite eines Servers A (bei mir www.uni-due.de) Inhalte von einem Server B (hier api.zeit.de) laden will.

Es bietet sich an, den Open-Befehl in ein try-catch-Konstrukt zu nehmen:

try {
  httpRequest.open('GET', url);
  } catch(e) {
  alert("Aufgefangener Fehrler: " + e.description);
  }

Danach setzt man noch den Autorisierungs-Header und sendet den Request.

httpRequest.setRequestHeader('X-Authorization','123456789qwert');
httpRequest.send();

Das Warten auf die Antwort geschieht nun versteckt im Hintergrund. Irgent wann schlägt die Antwort auf, was bewirkt, dass die Funktion antwort_auswerten aufgerufen wird. In dieser Funktion sollte man dann erst mal prüfen ob die Schnittstelle nicht mit einem Fehler geantwortet hat. Wenn httpRequest.readyState den Wert 4 hat und httpRequest.status den Wert 200, dann ist alle Ok und man kann den Resposetext verarbeiten. JSON liefert genau das Textformat in dem man ein strukturiertes Datenobject innerhalb eines Javascript-Programmen serialisiert schreiben würde. Also könnte man einfach so vorgehen

var response = new Object();
eval("response = " + httpRequest.responseText);

Allgemein wird davon aber abgeraten, weil es ein Sicherheitsrisiko beinhaltet. Schließlich führt man ja einen Programmcode aus, den man vorher nicht gesehen hat. Viele Browser bieten heute einen JSON-Parser als ein Objekt an. Dann kann man

response = JSON.parse(httpRequest.responseText);

schreiben. Leider muss man bei der AJAX-Programmierung viel Aufwand hineinstecken, wenn das Ergebnis in beliebigen Browsern lauffähig sein soll.

In dem Objekt response ist nun der gesamte Inhalt der Antwort strukturiert enthalten. Haben wir z.B. einen konkreten Autor abgefragt (z.B. http://api.zeit.de/author/Harald-Martenstein) dann ist response.matches die Liste seine Artikel, response.matches[0] ist der erste Artikel und response.matches[0].title beinhaltet den Titel des Artikeln und response.matches[0].href die URL, die auf den Artikel bei Zeit-Online verweist. Nun kann man sich der Möglichkeiten dynamischer Webseiten Web-Seiten bedienen und die abgerrufene Information in der Webseite darstellen (man siehe z.B. Neue Knoten erzeugen und in Baumstruktur einhängen bei SELFHTML).

Die Frage nach dem Inhalt

Verlassen wir zuletzt wieder die Technik um einige Dinge zu erwähnen, die mir zum Inhalt aufgefallen sind. Das sind gewissermaßen Unzulänglichkeiten des Datenbestandes, doch will ich ihre Erwähnung nicht als Kritik verstanden sehen. Es soll stattdessen deutlich werden wie schwierig der Aufbau einer solchen Datenbank ist.

Der erste Punkt ist, dass die Autoren oft mehrfach vorkommen: mit unterschiedlichen Schreibweisen und IDs. Harald Martenstein finden wir als author/Harand-Martenstein (72 Artikel), als author/Martenstein (2 Artikel) und als author/martenstein (1 Artikel). Dazu kommt, dass das CMS von Zeit-Online offenbar noch mehr Artikel kennt. Die Seite http://www.zeit.de/autoren/M/Harald_Martenstein/index.xml listet 591 Artikel auf. Hier ist also noch ein ToDo, um alle Artikel eines Autor zu erfassen und auch nur einem einzigem Autoren-Objekt zuzuordnen.

Ein anderer Aspekt bezieht sich auf die Information zu einem einzelnen Artikel. Da gibt es die Attribute “title”, “subtitle”, “supertitle”, “teaser_title” und “teaser_text”. Vermutlich ist nur “title” zwingend und immer vorhanden. Alle anderen Attribute sind optional. Mir ist auch nicht klar ob sie immer im gleichen Sinne verwendet werden. Das macht es schwierig eine einheitliche Darstellung eines Artikels zu programmieren.

Ich bin gespannt, wie sich die Sache weiterentwickeln wird. Welche Wege werden eingeschlagen, um die Meta-Datenbank zu verbessern, und welche Anwendungen (APPs) werden entstehen? Und ich bin natürlich gespannt, welche interessanten alten Artikel man erstöbern kann.

Dieser Beitrag wurde unter Anwendungen & Dienste, Code & Kernel abgelegt und mit , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>