Webkrauts Logo

Webkrauts Webkrauts Schriftzug

- für mehr Qualität im Web

Suche mit alles und scharf, BOSS?

Wir haben noch nicht alle älteren Artikel nachbearbeitet. Das bezieht sich in der Regel nur auf die Codebeispiele, die noch nicht optimal dargestellt werden.

Suche mit alles und scharf, BOSS?

Hinter BOSS steckt ein kostenloser Service von Yahoo. Damit lassen sich Webseiten durchsuchen, die Ergebnisse mit anderen Daten mischen und beliebig darstellen. Chris Heilmann zeigt, wie es geht.

Als ich noch freiberuflich unterwegs war, war eines der meistgefragten Produkte von Kunden, doch bitte eine Suchmaschine für ihre Seite zu erstellen. Besucher sollten die Möglichkeit erhalten, weitere Inhalte zu finden, ohne dass der Seitenbetreiber Verweise auf »weitere Themen« in die Seite einbinden musste.

Damals war das alles nicht so einfach. Entweder schrieb man sein eigenes Skript, das sich durch die Seiten hangelte, nutzte ht://dig oder biss eben in den sauren Apfel und bezahlte Yahoo, Altavista und später Google gutes Geld, um deren Angebote zu nutzen.

Diese Zeiten sind nun vorbei und man kann den gleichen Service kostenlos erhalten. Am Einfachsten ist das mit „Build your Own Search Service“ oder kurz BOSS von Yahoo.

Dieser kostenlose Dienst erlaubt es jedem, das Web oder bestimmte Seiten nach Inhalten zu durchforsten und diese mit anderen Daten zu mischen. Dabei bleibt es einem vorbehalten, wie man die Suchergebnisse darstellen will. BOSS ist derzeit unbegrenzt kostenfrei. In Zukunft wird es eine Beschränkung der Zugriffe pro Tag geben, die entweder durch die Darstellung von Werbung (ein Anteil der Einahmen gehen an den Seitenbetreiber) oder durch Bezahlung erweitert werden kann.

Unabhängig davon ist eines der genialsten Dinge von BOSS die einfache Handhabung. Suchergebnisse sind mittels einer REST-API erreichbar, kommen als JSON, XML oder JSON-P zurück und sind somit sehr einfach innerhalb eines Browsers mittels JavaScript zu verarbeiten.

Am Anfang steht das HTML Formular

Um eine Suchmaske in eine Seite einzubinden, benötigen wir ein einfaches HTML Formular mit den passenden Formularfeldern. Die meisten Suchmaschinen erlauben es, nach bestimmten Seiten zu filtern. Um zum Beispiel Seiten in "wikipedia.de" nach "heilmann" mittels Yahoo zu suchen, reicht es das folgende Formular zu erstellen:

<form id="customsearch"
       action="http://de.search.yahoo.com/search">
  <div>
    <label for="term">Innerhalb der Seite suchen:
    <input type="text" name="p" id="term"/>
    <input type="hidden" name="vs" id="site"
           value="de.wikipedia.org"/>
    <input type="submit" value="Ab daf&uuml;r"/>
  </label></div>
</form>

Genauso einfach ist das mit Google:

<form id="customsearch"
       action="http://www.google.de/search">
  <div>
    <abel for="term">Innerhalb der Seite suchen:
    <input type="text" name="as_q" id="term"/>
    <input type="hidden" name="as_sitesearch" id="site"
	       value="de.wikipedia.org"/>
    <input type="submit" value="Ab daf&uuml;r"/>
  </abel></div>
</form>

Unabhängig davon welche Suchmaschine Ergebnisse anzeigen soll wenn denn kein JavaScript vorhanden ist, verwenden wir die IDs term für den Suchbegriff und site für die Seite. Diese werden später im Javascript ausgelesen. Eine ID mit dem Namen customsearch auf dem Formularelement macht es uns außerdem einfacher, die Javascript-Funktionalität an das richtige Formular zu binden.

Um BOSS zu verwenden, benötigt man einen Developer-API-Key. Bitte holt euch einen Key und ersetzt den im Democode dieses Artikels durch euren.

So funktioniert BOSS

BOSS ist eine REST API, was bedeutet, dass man mit einem einfachen HTTP request oder sogar innerhalb eines Browsers mittels einer URL und verschiedenen Parametern die richtigen Informationen erhalten kann. Um zum Beispiel Wikipedia nach "heilmann" zu durchsuchen, genügt folgender Link (Leerzeichen der Lesbarkeit wegen eingefügt — die Redaktion):

http://boss.yahooapis.com/ysearch/web/v1/heilmann? sites=de.wikipedia.org&region=de&lang=de &format=xml&appid=DEINE_APPLIKATIONS_ID

Probiert es einmal selbst aus: klickt den Link und die Suchergebnisse werden in XML angezeigt. Wenn man den format=xml Parameter weglässt werden die Daten als JSON-Objekt zurückgegeben:

http://boss.yahooapis.com/ysearch/web/v1/heilmann? sites=de.wikipedia.org&region=de&lang=de &appid=DEINE_APPLIKATIONS_ID

JSON macht am meisten Sinn, wenn man das Objekt direkt an eine JavaScript Funktion übergibt. Um das zu erreichen, genügt es einen callback-Parameter anzugeben. Wenn wir zum Beispiel SITESEARCH.found() aufrufen wollen, sobald die Daten zur Verfügung stehen, geht das so:

http://boss.yahooapis.com/ysearch/web/v1/heilmann? sites=de.wikipedia.org&region=de&lang=de& callback=SITESEARCH.found&appid=DEINE_APPLIKATIONS_ID

Man kann diese URL direkt in einem script-Knoten nutzen. Das folgende Beispiel sucht heilmann auf de.wikipedia.org und gibt die Anzahl von Suchergebnissen als Meldung zurück.

<script type="text/javascript">
  var SITESEARCH = {};
  SITESEARCH.found = function(o){
    alert(o.ysearchresponse.totalhits);
  }
</script>
<script type="text/javascript"
src="http://boss.yahooapis.com/ysearch/web/v1/heilmann?
sites=de.wikipedia.org&amp;region=de&amp;lang=de&
callback=SITESEARCH.found&appid=Kzv_lcHV34HIybw0GjVkQNnw4AEXeyJ9Rb1gCZSGxSRNrcif_HdMT9qTE1y9LdI-">
</script>

Um allerdings unsere Suchformulare zu erweitern, brauchen wir etwas mehr Funktionalität.

Verbesserung des Suchformulars mit BOSS

Mit diesem Skript erweitern wir unser Suchformular.

SITESEARCH = function(){
  var config = {
    IDs:{
      searchForm:'customsearch',
      term:'term',
      site:'site'
    },
    loading:'Lade Ergebnisse...',
    noresults:'Keine Ergebnisse gefunden.',
    appID:'YOUR-APP-ID',
    results:20
  };
  var form;
  var out;
  function init(){

  if(config.appID === 'YOUR-APP-ID'){
    alert('Please get a real application ID!');
  } else {
    form = document.getElementById(config.IDs.searchForm);
    if(form){
      form.onsubmit = function(){
        var site = document.getElementById(config.IDs.site)
                   .value;
        var term = document.getElementById(config.IDs.term)
                   .value;
        if(typeof site === 'string' &&
           typeof term === 'string'){
          if(typeof out !== 'undefined'){
            out.parentNode.removeChild(out);
          }
          out = document.createElement('p');
          out.appendChild(document
                          .createTextNode(config.loading));
          form.appendChild(out);
          var APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' +
                       term + '?callback=SITESEARCH.found&amp;sites=' +
                       site + '&amp;count=' + config.results +
                       '&amp;appid=' + config.appID;
          var s = document.createElement('script');
          s.setAttribute('src',APIurl);
          s.setAttribute('type','text/javascript');
          document.getElementsByTagName('head')[0].appendChild(s);
          return false;
        }
      };
    }
  }
  };
  function found(o){
    var list = document.createElement('ul');
    var results = o.ysearchresponse.resultset_web;
    if(results){
      var item,link,description;
      for(var i=0,j=results.length;i<j ;i++){
        item = document.createElement('li');
        link = document.createElement('a');
        link.setAttribute('href',results[i].clickurl);
        link.innerHTML = results[i].title;
        item.appendChild(link);
        description = document.createElement('p');
        description.innerHTML = results[i]['abstract'];
        item.appendChild(description);
        list.appendChild(item);
      }
    } else {
      list = document.createElement('p');
      list.appendChild(document.
        createTextNode(config.noresults));
    }
    form.replaceChild(list,out);
    out = list;
  };
  return{
    config:config,
    init:init,
    found:found
  };
}();

Wow, so viel Code! OK, gehen wir Schritt für Schritt durch das Skript.

Wir starten mit einem Modul mit dem Namen SITESEARCH and geben dem Modul ein Konfigurationsobjekt:

SITESEARCH = function(){
  var config = {
    IDs:{
      searchForm:'customsearch',
      term:'term',
      site:'site'
    },
    loading:'Lade Ergebnisse...',
    noresults:'Keine Ergebnisse gefunden.',
    appID:'YOUR-APP-ID',
    results:20
  }

Konfigurationsobjekte sind eine sehr gute Idee um es Nutzern zu erlauben, das Skript einfach zu konfigurieren und zu ändern ohne das Skript umzuschreiben. In diesem Beispiel definieren wir die verwendeten IDs, eine Nachricht, die eingeblendet wird während die Dateien laden und eine, die angezeigt wird, falls keine Ergebnisse gefunden werden konnten. Weiterhin definieren wir eine Applikations-ID, die überschrieben werden muss, und erlauben es, die Anzahl der angezeigten Ergebnisse abzuändern.

Warnung: Die hier definierte Applikations ID ist nur ein Platzhalter und "YOUR-APP-ID" muss durch eine echte ID ersetzt werden, ansonsten wird das Skript nicht ausgeführt!

  var form;
  var out;
  function init(){
    if(config.appID === 'YOUR-APP-ID'){
      alert('Please get a real application ID!');
    } else {

Wir definieren form und out als Variablen, um sicherzustellen, dass alle Methoden in dem Modul Zugriff auf diese haben. Weiterhin überprüfen wir die Applikations ID und geben eine Fehlermeldung aus, wenn der Platzhalter nicht überschrieben wurde.

      form = document.getElementById(config.IDs.searchForm);
      if(form){
        form.onsubmit = function(){
          var site = document.getElementById(config.IDs.site)
                     .value;
          var term = document.getElementById(config.IDs.term)
                     .value;
          if(typeof site === 'string' &&
             typeof term === 'string'){

Wenn die Applikations ID definiert ist, überprüfen wir, ob das Formular mit der richtigen ID vorhanden ist und überschreiben das submit-Event des Formulars. In diesem Event prüfen wir die Werte der anderen Felder. Wenn die Seite, in der wir planen zu suchen, und der Suchbegriff definiert und Zeichenketten sind, kann es weiter gehen.

            if(typeof out !== 'undefined'){
              out.parentNode.removeChild(out);
            }
            out = document.createElement('p');
            out.appendChild(document
                            .createTextNode(config.loading));
            form.appendChild(out);

Als nächsten Schritt testen wir, ob out definiert ist. Falls das der Fall ist, löschen wir den Knoten, der in out gespeichert ist. Der Grund ist, dass die out-Variable später die Ladenachricht und im letzten Schritt die Suchergebisse beinhalten wird. Daher müssen wir alte Ergebnisse löschen, bevor die neuen angezeigt werden. Wir erstellen einen neuen Paragraphenknoten mit der Ladenachricht und fügen diesen dem Formular hinzu.

    var APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' +
              term + '?callback=SITESEARCH.found&sites=' +
              site + '&count=' + config.results +
              '&appid=' + config.appID;
            var s = document.createElement('script');
            s.setAttribute('src',APIurl);
            s.setAttribute('type','text/javascript');
            document.getElementsByTagName('head')[0]
                    .appendChild(s);
            return false;
          }
        };
      }
    }
  };

Jetzt ist es an der Zeit die BOSS-API aufzurufen, indem wir die passende URL erstellen, und als src Attribut eines neuen script Knotens dem Seitenkopf hinzuzufügen. Wir geben dem Event false als Rückgabewert, um nicht den Browser auf die nächste Seite zu schicken.

Wir definierten SITESEARCH.found in der API URL als Rückgabemethode, die die Ergebnisdaten weiterverarbeitet. Daher müssen wir diese erstellen.

  function found(o){
    var list = document.createElement('ul');
    var results = o.ysearchresponse.resultset_web;
    if(results){
      var item,link,description;

Wir erstellen einen neuen Listenknoten und lesen das resultset_web-Array aus dem Datensatz, der von der API zurückgegeben wurde. Falls keine Suchergebnisse gefunden wurden, ist dieses Array undefiniert, wir müssen also testen, ob es vorhanden ist. Falls das Array definiert ist, erstellen wir drei neue Variablen, die später die Daten eines jeden einzelnen Datensatzes als Werte erhalten werden: Den Titel der Seite, den Verweis und die Beschreibung.

      for(var i=0,j=results.length;i<j ;i++){
        item = document.createElement('li');
        link = document.createElement('a');
        link.setAttribute('href',results[i].clickurl);
        link.innerHTML = results[i].title;
        item.appendChild(link);
        description = document.createElement('p');
        description.innerHTML = results[i]['abstract'];
        item.appendChild(description);
        list.appendChild(item);
      }

Wir erstellen eine Schleife, in der der Listenknoten um neue Listenelemente mit Verweisen und Paragraphen mit Verweisbeschreibungen erweitert wird.

    } else {
      list = document.createElement('p');
      list.appendChild(document
          .createTextNode(config.noresults));
    }
    form.replaceChild(list,out);
    out = list;
  };

Falls keine Suchergebnisse gefunden werden konnten, erstellen wir einen neuen Absatz mit einer Fehlermeldung. Wir ersetzen die Ladenachricht entweder mit den Suchergebnissen oder mit diesem Absatz und definieren out neu.

  return{
    config:config,
    init:init,
    found:found
  };
}();

Was jetzt noch fehlt, ist zu definieren, welche Methoden und Variablen global erreichbar sein müssen. In diesem Fall brauchen wir found, da diese von der API aufgerufen wird, init um das Formular zu verbessern und config um es Nutzern zu erlauben, die Konfiguration zu überschreiben.

Nutzung des Skripts

Um das Skript zu nutzen, muss es nur nach dem Formular in das Dokument eingebunden, ein API Key definiert sein und die init() Methode aufgerufen werden.

<form id="customsearch" action="http://search.yahoo.com/search">
  <div>
    <label for="p">Innerhalb der Seite suchen:</label>
    <input type="text" name="p" id="term"/>
    <input type="hidden" name="vs" id="site" value="bbc.co.uk"/>
    <input type="submit" value="Ab daf&uuml;r"/>
  </div>
</form>
<script type="text/javascript" src="boss-site-search.js">
</script>
<script type="text/javascript">
  SITESEARCH.config.appID = 'dein API key';
  SITESEARCH.init();
</script>

Wie geht's weiter?

Was wir hier erstellt haben ist nur einfaches Beispiel für das, was man mit BOSS erstellen kann. Man kann in anderen Sprachen und Regionen suchen, Bilder und Nachrichten erhalten und die Ergebnisse mit anderen Informationsquellen mischen. Eine weitere Möglichkeit ist es, mittels dem view=keyterms-Parameters Schlüsselworte aus den einzelnen Seiten zu extrahieren und es damit ermöglichen, die Suche zu verfeinern. Ein Beispiel dafür in PHP ist im YDN Blog nachzulesen (in Englisch). Für JavaScript ist ausserdem eine Bibliothek mit dem Namem yboss erhältlich die diesen Vorgang erheblich vereinfacht.

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.

Kommentare

Stefan Walter (Webkraut)
am 04.12.2008 - 12:17

Super-Artikel, vielen Dank dafür an Christian

Permanenter Link

Herr Voß
am 04.12.2008 - 12:43

Wow. Cooler Tipp! Danke für den Artikel

Permanenter Link

leo
am 04.12.2008 - 18:18

Sehr fein, dein Javascript ist so selbsterklärend...lovely :)
Vielen Dank!

(Die Links zu dem html-Beispiel und der Javascript-Dateien klappen nicht...)

Permanenter Link

Jens Grochtdreis
am 05.12.2008 - 14:09

@leo: Danke für den Hinweis. Ich habe es korrigiert.

Permanenter Link

Claus
am 05.12.2008 - 20:13

Wow, das ist genau das was ich gesucht habe aber selbst nicht wirklich auf die Reihe bringe. Danke!

Permanenter Link

Natinka
am 06.12.2008 - 11:46

Schöne Sache und danke für den Hinweis. Ich denke dass Yahoo in diesem Bereich ein ganzes Stückchen weiter ist als Google. Ich bin mir auch ziemlich sicher, dass dies der richtige Weg ist - User bestimmte Services anzubieten - um an Google näher ran zu kommen.
Grüße

Permanenter Link

brigitte
am 10.12.2008 - 17:11

@Christian Heilmann

Hilfreich und gut erklärt!

Schöne Weihnachten und ein gutes Neues Jahr
wünscht
Brigitte Weber-Frowein

Permanenter Link

Ell
am 12.12.2008 - 10:03

Tja, liest sich ganz gut. Ist aber alles JavaScript - was ist denn, wenn der Besucher JavaScript deaktiviert hat?

Dann muß man die Suchanfrage doch auf seinem Server verarbeiten?

Permanenter Link
Eric Eggert

Eric Eggert (Webkraut)
am 12.12.2008 - 10:26

@Ell: Dann wird das Formular ganz normal abgeschickt und der Besucher landet bei einer Yahoo!- oder Google-Suche.

Permanenter Link

Die Kommentare sind geschlossen.