Zum Inhalt springen

Webkrauts: Für mehr Qualität im Web.

Werbung

Webkongress Erlangen/Nürnberg 2010

Artikel

Webinhalte einfach vermischen mit YQL

17. Türchen des Webkrauts-Adventskalenders

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.

<?php
  /* YouTube RSS Ausgabe */
  $query = 'select description from rss(5) where url=" »
     http://gdata.youtube.com/feeds/base/users/ »
     chrisheilmann/uploads?alt=rss&v=2 »
     &orderby=published&client=ytapi-youtube-profile";';

  /* Flickr Suche nach user id */
  $query .= 'select farm,id,owner,secret,server,title from »
     flickr.photos.search where user_id="11414938@N00";';

  /* Delicious RSS Ausgabe */
  $query .= 'select title,link from rss where url=" »

http://feeds.delicious.com/v2/rss/codepo8?count=10";';

  /* Blog RSS Ausgabe */
  $query .= 'select title,link from rss where url=" »

http://feeds.feedburner.com/wait-till-i/gwZf"';

  /* Der Datenendpunkt von YQL mit JSON als Ausgabeformat */
  $root = 'http://query.yahooapis.com/v1/public/yql »
     ?format=json »
     &env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';

  /* Zusammenfügung der Anfrage */
  $query = "select * from query.multi where  »
     queries='".$query."'";
  $url = $root . '&q=' . urlencode($query);

  /*
    Eine Anfrage mittels cURL ist genau das gleiche wie die
    Daten in einem Browser einzugeben. cURL lädt die
    Daten und gibt sie zurück.
  */
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  $output = curl_exec($ch);
  curl_close($ch);
  $data = json_decode($output);
  $results = $data->query->results->results;

  /* YouTube HTML */
  $youtube = '<ul id="youtube">';
  foreach($results[0]->item as $r){
    $cleanHTML = undoYouTubeMarkupCrimes($r->description);
    $youtube .= '<li>'.$cleanHTML.'</li>';
  }
  $youtube .= '</ul>';

  /* Flickr HTML */
  $flickr = '<ul id="flickr">';
  foreach($results[1]->photo as $r){
    $flickr .= '<li>'.
       '<a href="http://www.flickr.com/photos/codepo8/'.
       $r->id.'/">'.
       '<img src="http://farm' . $r->farm .
       '.static.flickr.com/' . $r->server . '/' .
       $r->id . '_' . $r->secret . '_s.jpg"
       alt="'.$r->title.'"></a></li>';
  }
  $flickr .= '</ul>';

  /* Delicious HTML */
  $delicious = '<ul id="delicious">';
  foreach($results[2]->item as $r){
    $delicious .= '<li><a href="'.$r->link.'">'.$r->title.'
       </a></li>';
  }
  $delicious .= '</ul>';

  /* Blog HTML */
  $blog = '<ul id="blog">';
  foreach($results[3]->item as $r){
    $blog .= '<li><a href="'.$r->link.'">'.$r->title.
       '</a></li>';
  }
  $blog .= '</ul>';

  /* Layout Tabellen in 2009? Echt, Google??? */
  function undoYouTubeMarkupCrimes($str){
    $cleaner = preg_replace('/555px/','100%',$str);
    $cleaner = preg_replace('/width="[^"]+"/','',$cleaner);
    $cleaner = preg_replace('/<tbody>/','<colgroup><col  »
       width="20%"><col width="50%"><col width="30%">  »
       </colgroup><tbody>',$cleaner);
    return $cleaner;
  }
?>

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:

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

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):

<ul id="hottopics"></ul>
<script type="text/javascript">
function hottopics(o){
  var res = o.query.results.Result,
      all = res.length,
      topics = {},
      out = [],
      html = '',
      i=0;
  /* create hash from topics to prevent repetition */
  for(i=0;i<all;i++){
    topics[res[i]] = res[i];
  };
  for(i in topics){
    out.push(i);
  };
  html = '<li>' + out.join('</li><li>') + '</li>';
  document.getElementById('hottopics').innerHTML = html;
};
</script>
<script type="text/javascript" src="  »
http://query.yahooapis.com/v1/public/yql?q=select  »
%20content%20from%20search.termextract%20where%20context  »
%20in%20(select%20content%20from%20html%20where%20url%3D  »
%22http%3A%2F%2Fnews.bbc.co.uk%22%20and%20xpath%3D%22%2F%2F  »
table%5B%40width%3D800%5D%2F%2Fa%22)&format=json&  »
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):

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

24 ways to impress your friendsDieser 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.

Zum Autor:

Autorenfoto: Christian HeilmannChristian Heilmann arbeitet als Developer Evangelist bei Yahoo! in London, England. Er trägt überall auf der Welt auf Konferenzen vor, und bloggt unter andere darüber. Zuletzt veröffentlichte er sein Handbuch für Developer Evangelists.

Info:
Webinhalte einfach vermischen mit YQL ist Beitrag Nr. 671
Autor:
Christian Heilmann am 17. Dezember 2009 um 07:00
Kategorie:
Adventskalender 2009

Kommentare

Bitte die Hausregeln beachten. Alle Kommentare werden auf werbliche Links/Nicknames geprüft und gegebenenfalls gelöscht.

  1. 1.

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

    Kommentar von domingos - 17. Dezember 2009 um 08:05

  2. 2.

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

    Kommentar von Alex B. - 17. Dezember 2009 um 10:03

  3. 3.

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

    Kommentar von Henry Zeitler - 17. Dezember 2009 um 10:05

  4. 4.

    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!"

    Kommentar von Julia - 17. Dezember 2009 um 12:37

  5. 5.

    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.

    Kommentar von Peter - 17. Dezember 2009 um 13:19

  6. 6.

    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.

    Kommentar von Peter - 17. Dezember 2009 um 14:31

  7. 7.

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

    Kommentar von Chris Heilmann - 17. Dezember 2009 um 18:30

  8. 8.

    Christian … Dafür liebe ich dich … Danke

    Kommentar von Stefan - 17. Dezember 2009 um 19:01

  9. 9.

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

    Kommentar von Peter - 17. Dezember 2009 um 20:10

  10. 10.

    @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

    Kommentar von Chris Heilmann - 18. Dezember 2009 um 08:57

  11. 11.

    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?

    Kommentar von Andreas Fritsch - 19. Dezember 2009 um 13:27

Kommentarfeed Kommentar-Feed für diesen Beitrag

Die Kommentarfunktion ist zur Zeit leider deaktiviert.

Anmelden | © Webkrauts 2005-2010 | powered by Wordpress