Webkrauts Logo

Webkrauts Webkrauts Schriftzug

- für mehr Qualität im Web

Webinhalte einfach vermischen mit YQL

Webinhalte einfach vermischen mit YQL

Das Netz stellt uns die unterschiedlichsten Informationen zur Verfügung. Wir müssen nur zugreifen und sie für unsere eigenen Ziele zusammenstellen. Christian Heilmann zeigt heute, wie wir mit YQL recht einfach verschiedene APIs abfragen und ihre Antworten sinnvoll aufbereiten können.

Es ist verblüffend, wieviele Angebote es im Internet gibt, die einem als Entwickler die Arbeit erleichtern. Flickr speichert Terabytes von Fotos und verkleinert diese automatisch in verschiedene handliche Formate. Flickr erkennt auch Personen in den Fotos, erlaubt es, Fotos geographisch zu platzieren und sogar online zu verändern. YouTube macht ähnliches mit Videos; LinkedIn oder Xing erlauben seinen Lebenslauf im Netz zu pflegen, Delicious verwaltet Favoriten und so weiter und so fort.

Alle diese Arbeiten müssen wir nicht mehr von Hand erledigen, da alle diese Angebote uns mittels Application Programming Interfaces – oder kurz APIs – Zugriff auf unsere Daten erlauben. Eine API funktioniert, indem wir mittels Parametern bestimmte Daten anfordern und in verschiedenen Formaten zurück bekommen.

Das Problem dabei ist, dass jeder API-Anbieter eine andere Idee davon hat, was denn sinnvolle Parameter und Datenformate sind. Mehrere APIs in einem Produkt zu verwenden, wird damit zu einem Problem, da man sich mehr damit beschäftigt, Dokumentationen zu lesen als zu programmieren.

Ein einfacherer Zugang zu APIs

Was wir als Entwicker brauchen sind Bibliotheken und Systeme, die unsere Arbeit erleichtern. Bibliotheken wie jQuery und YUI machen Webdesign einfacher, da sie Browserprobleme und Fehler beheben und es uns erlauben, uns auf das Programmieren zu konzentrieren anstatt für den Browser zu arbeiten. Genau das gleiche Prinzip steckt hinter der Yahoo Query Language oder YQL. YQL erlaubt es einem, APIs und Daten im Netz in einer einfachen und einheitlichen Sprache zu erreichen und weiter zu verwenden. Die Syntax dieser Sprache ist ähnlich wie die Datenbanksprache SQL.

Select * from web (und gib mir nur zurück, was ich wirklich brauche)

YQL ist ein Web-Service der nur ein paar einfache Eingabeparameter erwartet:

  • Eine Datenanfrage (query) die angibt, welche API man ansprechen will
  • Das Ausgabeformat, was XML oder JSON (mit den Unterformaten JSON-P und JSON-P-X) sein kann und
  • Den Namen einer Funktion, die aufgerufen werden soll, wenn die Daten geladen sind (nur für JSON-P oder JSON-P-X sinnvoll).

Am einfachsten ist es, YQL mal auszuprobieren. Eine Anfrage wie select * from flickr.photos.search where text="santa" geht zu Flickr und sucht nach Fotos mit dem Text »Santa«. Diese Anfrage an den Datenendpunkt von YQL geschickt und gibt uns die Daten der Fotos als XML.

Um die Arbeit mit YQL ganz einfach zu gestalten, gibt es eine Konsole. In diesem Interface kann man Beispielsanfragen sehen, alle Datenquellen abfragen und erfahren, welche Art von Daten erhältlich sind und komplexe Anfragen einfach zusammenklicken. In diesem Artikel will ich allerdings aufzeigen, dass die Konsole zwar praktisch ist, aber nicht unbedingt nötig. Wir können die gleichen Ergebnisse mit PHP erzielen.

Als Beispiel wollen wir eine kleine Seite erstellen, die alle möglichen Daten einer Person aus dem Netz holt und in einem Interface darstellt. Die Daten sind Fotos von Flickr, Videos von YouTube, Blogeinträge und Favoriten von Delicious.

Die Seite ist hier zu sehen, und der Quellcode ist auf GitHub erhältlich.

  1. <?php
  2.   /* YouTube RSS Ausgabe */
  3.   $query = 'select description from rss(5) where url=" »
  4.     http://gdata.youtube.com/feeds/base/users/ »
  5.     chrisheilmann/uploads?alt=rss&v=2 »
  6.     &orderby=published&client=ytapi-youtube-profile";';
  7.  
  8.   /* Flickr Suche nach user id */
  9.   $query .= 'select farm,id,owner,secret,server,title from »
  10.     flickr.photos.search where user_id="11414938@N00";';
  11.  
  12.   /* Delicious RSS Ausgabe */
  13.   $query .= 'select title,link from rss where url=" »
  14.  
  15. http://feeds.delicious.com/v2/rss/codepo8?count=10";';
  16.  
  17.   /* Blog RSS Ausgabe */
  18.   $query .= 'select title,link from rss where url=" »
  19.  
  20. http://feeds.feedburner.com/wait-till-i/gwZf"';
  21.  
  22.   /* Der Datenendpunkt von YQL mit JSON als Ausgabeformat */
  23.   $root = 'http://query.yahooapis.com/v1/public/yql »
  24.     ?format=json »
  25.     &env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';
  26.  
  27.   /* Zusammenfügung der Anfrage */
  28.   $query = "select * from query.multi where  »
  29.     queries='".$query."'";
  30.   $url = $root . '&q=' . urlencode($query);
  31.  
  32.   /*
  33.     Eine Anfrage mittels cURL ist genau das gleiche wie die
  34.     Daten in einem Browser einzugeben. cURL lädt die
  35.     Daten und gibt sie zurück.
  36.   */
  37.   $ch = curl_init();
  38.   curl_setopt($ch, CURLOPT_URL, $url);
  39.   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  40.   $output = curl_exec($ch);
  41.   curl_close($ch);
  42.   $data = json_decode($output);
  43.   $results = $data->query->results->results;
  44.  
  45.   /* YouTube HTML */
  46.   $youtube = '<ul id="youtube">';
  47.   foreach($results[0]->item as $r){
  48.     $cleanHTML = undoYouTubeMarkupCrimes($r->description);
  49.     $youtube .= '<li>'.$cleanHTML.'</li>';
  50.   }
  51.   $youtube .= '</ul>';
  52.  
  53.   /* Flickr HTML */
  54.   $flickr = '<ul id="flickr">';
  55.   foreach($results[1]->photo as $r){
  56.     $flickr .= '<li>'.
  57.        '<a href="http://www.flickr.com/photos/codepo8/'.
  58.        $r->id.'/">'.
  59.        '<img src="http://farm' . $r->farm .
  60.        '.static.flickr.com/' . $r->server . '/' .
  61.        $r->id . '_' . $r->secret . '_s.jpg"
  62.       alt="'.$r->title.'"></a></li>';
  63.   }
  64.   $flickr .= '</ul>';
  65.  
  66.   /* Delicious HTML */
  67.   $delicious = '<ul id="delicious">';
  68.   foreach($results[2]->item as $r){
  69.     $delicious .= '<li><a href="'.$r->link.'">'.$r->title.'
  70.       </a></li>';
  71.   }
  72.   $delicious .= '</ul>';
  73.  
  74.   /* Blog HTML */
  75.   $blog = '<ul id="blog">';
  76.   foreach($results[3]->item as $r){
  77.     $blog .= '<li><a href="'.$r->link.'">'.$r->title.
  78.        '</a></li>';
  79.   }
  80.   $blog .= '</ul>';
  81.  
  82.   /* Layout Tabellen in 2009? Echt, Google??? */
  83.   function undoYouTubeMarkupCrimes($str){
  84.     $cleaner = preg_replace('/555px/','100%',$str);
  85.     $cleaner = preg_replace('/width="[^"]+"/','',$cleaner);
  86.     $cleaner = preg_replace('/<tbody>/','<colgroup><col  »
  87.       width="20%"><col width="50%"><col width="30%">  »
  88.       </colgroup><tbody>',$cleaner);
  89.     return $cleaner;
  90.   }
  91. ?>

Ziemlich einfach, eigentlich. Alles, was wir hier machen, sind verschiedene YQL-Anfragen zu erstellen und mittels der query.multi-Tabelle als eine einzelne Anfrage an YQL zu schicken. Jede dieser Anfragen ist auch einzeln in YQL möglich. Die folgenden Links öffnen die einzelnen Anfragen in der YQL Konsole:

Der Vorteil der query.multi-Anfrage ist, dass wir nur eine Datenanfrage an YQL schicken und der Rest der Anfragen an die verschiedenen Datenquellen erfolgt auf der YQL-Serverfarm. Da diese schneller im Netz unterwegs ist als unser Server, bedeutet das, dass unsere Seite schneller lädt und damit glücklichere Endnutzer hat.

Wir schicken unsere Anfrage an den YQL-Endpunkt und verwenden cURL, um die Daten zu laden. Einfach gesagt ist cURL ein Browser in PHP – wir können alles das, was wir im Browser laden, von einem Programm aus erledigen. Nach einer erfolgreichen Abfrage gibt uns cURL die Daten als JSON zurück und mittels json_decode können wir diese in ein PHP verständliches Format bringen.

Alles, was wir dann noch machen müssen, ist die Daten in ein sinnvolles HTML-Format zu bringen und in einem Template anzuzeigen. Fertig.

Mehrere Datenquellen vermischen und HTML als Datenquelle

Das erste Beispiel war relativ einfach, da die meiste Arbeit von uns in PHP erledigt wurde. Richtig interessant wird YQL allerdings, wenn wir in einer Anfrage mehrere APIs und Datenquellen vermischen. Als Beispiel werden wir nun die neuesten Nachrichten der BBC Webseite abrufen und aus den Titeln Schlüsselwörter erstellen. Dadurch kann man eine Liste von derzeit interessanten »Hot Topics« erstellen.

Um das zu erreichen brauchen wir zwei Datentabellen in YQL: Die HTML-Tabelle, die es erlaubt HTML von Seiten zu laden und per XPATH auf das Notwendigste zu reduzieren, und die Yahoo Term Extractor API (eine API die aus Texten Schlüsselwörter extrahiert). Um mehrere APIs in YQL zu verwenden, müssen wir den in() Befehl aufrufen:

  1. select * from search.termextract where context in (
  2.   select content from html where url="http://news.bbc.co.uk"  »
  3.   and xpath="//table[@width=800]//a"
  4. )

Hier kann man die Abfrage in der Konsole sehen und die Ergebnisse der Abfrage sind auch erhältlich. Auf Deutsch bedeutet die Anfrage:

  1. Gehe nach http://news.bbc.co.uk und gib mir das HTML zurück
  2. Konvertiere das HTML mit HTMLTidy um eventuelle Markup-Probleme zu beheben
  3. Gib mir alle Links innerhalb der Tabelle mit einem width-Attribut und einem Wert von 800
  4. Extrahiere den Textinhalt (content) der inviduellen Links und schicke den Textinhalt als context an die Yahoo Term Extractor API.

Wenn wir JSON-P als Ausgabeformat verlangen, können wir das Ergebnis der Anfrage direkt in JavaScript weiterverwenden (hier zu sehen und hier als Quellcode):

  1. <ul id="hottopics"></ul>
  2. <script type="text/javascript">
  3. function hottopics(o){
  4.   var res = o.query.results.Result,
  5.       all = res.length,
  6.       topics = {},
  7.       out = [],
  8.       html = '',
  9.       i=0;
  10.   /* create hash from topics to prevent repetition */
  11.   for(i=0;i<all;i++){
  12.    topics[res[i]] = res[i];
  13.  };
  14.  for(i in topics){
  15.    out.push(i);
  16.  };
  17.  html = '<li>' + out.join('</li><li>') + '</li>';
  18.   document.getElementById('hottopics').innerHTML = html;
  19. };
  20. </script>
  21. <script type="text/javascript" src="  »
  22. http://query.yahooapis.com/v1/public/yql?q=select  »
  23. %20content%20from%20search.termextract%20where%20context  »
  24. %20in%20(select%20content%20from%20html%20where%20url%3D  »
  25. %22http%3A%2F%2Fnews.bbc.co.uk%22%20and%20xpath%3D%22%2F%2F  »
  26. table%5B%40width%3D800%5D%2F%2Fa%22)&format=json&  »
  27. callback=hottopics"></script>

Natürlich kann man JSON auch in PHP verwenden, was bedeutet, dass jeder Besucher die »Hot Topics« sehen kann und nicht nur die, die JavaScript verwenden können (Beispiel hier und Quellcode bei GitHub):

  1. <ul id="hottopics"><li>
  2. <?php
  3. $url = 'http://query.yahooapis.com/v1/public/yql?q=select'.
  4.        '%20content%20from%20search.termextract%20where'.
  5.        '%20context%20in%20(select%20content%20from%20html'.
  6.        '%20where%20url%3D%22http%3A%2F%2Fnews.bbc.co.uk%22'.
  7.        '%20and%20xpath%3D%22%2F%2Ftable%5B%40width%3D800%5D'.
  8.        '%2F%2Fa%22)&format=json';
  9. $ch = curl_init();
  10. curl_setopt($ch, CURLOPT_URL, $url);
  11. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  12. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  13. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  14. $output = curl_exec($ch);
  15. curl_close($ch);
  16. $data = json_decode($output);
  17. $topics = array_unique($data->query->results->Result);
  18. echo join('</li><li>',$topics);
  19. ?>
  20. </li></ul>

Zusammenfassung

Dieser Artikel kann aufgrund seiner Länge nur einen Bruchteil davon aufzeigen, was YQL einem Entwickler ermöglicht. Durch YQL kann man nicht nur APIs lesen, sondern auch schreiben. Wir können zum Beispiel Twitter updates verschicken, neue Artikel in WordPress Blogs einpflegen oder eine Webadresse mit bit.ly verkürzen. Mittels Open Tables können wir jeden Datenendpunkt im Netz zu YQL hinzufügen und JavaScript auf dem Server ausführen, was zum Beispiel sehr sinnvoll ist, um Flickr-Fotos als HTML zu erhalten oder HTML-Inhalte von Seiten zu lesen, die POST-Daten benötigen.

Das Web der Daten ist hier und YQL erlaubt es jedem teilzunehmen – nicht nur den Webservice-Experten.

Anmerkung der Redaktion

Logo: 24 ways - to impress your friends

Dieser Artikel ist die deutsche Übersetzung von Christians Beitrag für die Seite 24ways. Dieser Adventskalender bietet noch viele weitere interessante Beiträge, alle in englischer Sprache.

Kommentare

domingos
am 17.12.2009 - 08:05

Danke für den Tipp, kannte YQL noch gar nicht. Alles in allem der nützlichste Beitrag bis jetzt für mich;-)

Permanenter Link

Alex B.
am 17.12.2009 - 10:03

Kannte ich auch noch nicht. Vielen Dank für den Tipp. Werde gleich heute mal ausprobieren.

Permanenter Link

Henry Zeitler
am 17.12.2009 - 10:05

Danke! Habe deinen Vortrag bereits auf Technikwürze gehört (Tw 151) und finde diese Herangehensweise bahnbrechend und zukunftsweisend...

Permanenter Link

Julia
am 17.12.2009 - 12:37

Super! Ich habe mich mit YQL auch bisher noch nicht befasst und bin begeistert von den Möglichkeiten. Ich werde mich jetzt aber explizit nicht, nie, auf gar keinen Fall bedanken, da ich aufgrund dieses wirklich wundervollen Artikels jetzt schon weiß, wie sich mein Abend gestalten wird :-)
Naja... na gut... "Danke!"

Permanenter Link

Peter
am 17.12.2009 - 13:19

Vielen Dank für diesen Artikel!
Bedeutet das evtl. auch, damit Flickr-Abfragen wie z.B. auf urbandirty.com mit YQL schneller als mit der Klasse phpFlickr (http://phpflickr.com) wären? Vielen Dank.

Permanenter Link

Peter
am 17.12.2009 - 14:31

Vielen Dank für diesen Artikel!
Bedeutet das evtl. auch, damit häufige Flickr-Abfragen wie z.B. auf urbandirty mit YQL schneller als mit der phpFlickr Klasse wären? Vielen Dank.

Permanenter Link
Christian Heilmann

Christian Heilmann (Autor)
am 17.12.2009 - 18:30

@peter, klar wenn das ne normale anfrage is dann geht das einfacher. select * from flickr.photos.search where text="urbandirty.com"

Permanenter Link

Stefan
am 17.12.2009 - 19:01

Christian ... Dafür liebe ich dich ... Danke

Permanenter Link

Peter
am 17.12.2009 - 20:10

@Chris: Danke, aber ich meinte "urbandirty.com" nicht als searchstring sondern die zahlreichen Flickr-Abfragen mittels phpFlickr-Class auf der Website urbandirty.com. ;-)

Permanenter Link
Christian Heilmann

Christian Heilmann (Autor)
am 18.12.2009 - 08:57

@peter da ich keine Ahnung habe *was* du abfragst und *wie* ist es schwierig dazu ne Aussage zu machen. Allerdings wenn es einfache Suchanfragen sind dann wird es natuerlich mit YQL schneller weil du sie per einem http request machen kannst. Ich hab das mal mit 5 RSS feeds gemacht und die Geschwindigkeitsunterschiede sind erstaunlich: http://is.gd/5saGI

Permanenter Link

Andreas Fritsch
am 19.12.2009 - 13:27

Da YQL ja auch cacht, bedeutet das, dass ich mir einen eigene Cache sparen kann? Was passiert, wenn die Dienste (z.B. Twitter) down sind?

Permanenter Link

Die Kommentare sind geschlossen.