Inkognito

Seit einiger Zeit sind Web Services zwar im Gespräch, praktische Anwendungen jedoch noch rar. Die bekannte Suchmaschine Google hat jetzt die Schnittstelle für einen Dienst veröffentlicht, mit deren Hilfe sich interessante Anwendungen programmieren lassen.

In Pocket speichern vorlesen Druckansicht 14 Kommentare lesen
Lesezeit: 11 Min.
Von
  • Jörg Krause
Inhaltsverzeichnis

Google stellt seit einiger Zeit - derzeit noch im Testbetrieb - einen Web Service zur Verfügung, der die Abfrage der Suchmaschine per Software erlaubt. Wer Google auf der eigenen Website einsetzt, war bislang auf die vorgegebene HTML-Schnittstelle festgelegt. Die Aufnahme der Suchergebnisse in ein eigenes Programm wäre bestenfalls ein schlechter Hack.

Eine solche Schnittstelle tatsächlich verwenden zu können, ist bedeutend für die junge Welt der Web Services. Funktionierende Dienste sind derzeit so selten, dass es schwer fällt, den Sinn dahinter zu erkennen. Da ist es wichtig, dass ein bekannter Anbieter wie Google ein solches Angebot macht. Es beinhaltet für viele Sprachen vorgefertigte Skriptmodule, die den Einsatz ermöglichen.

Web Services sind Anwendungen, die auf Webservern laufen und über eine standardisierte Schnittstelle (öffentlich) verfügbar sind. Zwischen Client und Server kann sich eine durchaus umfassende Kommunikation abspielen, die über den Aufruf dynamischer Webseiten weit hinausgeht. Als Protokoll dient HTTP, was die Nutzung in vielen Umgebungen erleichtert.

Übertragen werden spezielle XML-Daten, die nach SOAP, dem Simple Object Access Protocol kodiert sind (siehe [1]). Letztlich stecken SOAP-Nachrichten im Körper einer HTTP-Nachricht. Es gehört aber mehr dazu, als einen URL aufzurufen. Der Client muss in der Lage sein, SOAP-Nachrichten zu generieren und die Antworten zu verarbeiten. SOAP dient vor allem der Server-Server-Kommunikation, wobei einer der beiden Server die Kommunikation als Client startet. Das erschwert anfänglich das Verständnis und die Suche nach Einsatzgebieten, denn das heutige Web ist fast ausschließlich Browser-zentriert. Wie diese Kommunikation praktisch aussieht, zeigt Listing 1, wo der Körper der SOAP-Nachricht, der so genannte SOAP-Envelope, zu sehen ist. Die Antwort ist ähnlich strukturiert. Da SOAP auf XML basiert, ist die Auswertung mit XML-Werkzeugen relativ einfach.

Mehr Infos

Listing 1: SOAP-Google-Beispiel

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:si="http://soapinterop.org/xsd"
xmlns:ns6="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns6:doGoogleSearch>
<key xsi:type="xsd:string">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</key>
<q xsi:type="xsd:string">site:php.comzept.de XML</q>
<start xsi:type="xsd:int">0</start>
<maxresults xsi:type="xsd:int">5</maxresults>
<filter xsi:type="xsd:boolean">false</filter>
<restrict xsi:type="xsd:string"></restrict>
<safeSearch xsi:type="xsd:boolean">false</safeSearch>
<lr xsi:type="xsd:string"></lr>
<ie xsi:type="xsd:string"></ie>
<oe xsi:type="xsd:string"></oe>
</ns6:doGoogleSearch>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Komplex wird es dennoch, weil zur Nutzung von Programmen mehr Informationen gehören als zum Verschicken statischer Daten. Zu diesem Zweck wurde das XML-basierte WSDL entwickelt - die Web Services Description Language. Computer können aus einem WSDL-Datenpaket die Leistungen eines Web Service entnehmen. Damit können Entwickler den Prozess automatisieren. Es ist denkbar, dass sich ein Programm selbstständig auf die Suche nach geeigneten Web Services begibt, Angebote vergleicht und den besten Dienst nutzt. Für die ersten Schritte ist es jedoch nicht zwingend, auf eine WSDL-Datei zurückzugreifen.

Es ist jedoch recht abstrakt, auf diese Weise sofort zu einer vernünftigen Anwendung zu gelangen. Google hat es geschafft, mit einer relativ einfachen Schnittstelle Web Services in das Bewusstsein vieler Entwickler zu rücken. Der Dienst bietet an, die Suchfunktionen per Programm zu nutzen und in die eigene Homepage zu integrieren. Die Kommunikation spielt sich zwischen dem eigenen Webserver (als Client) und dem Google-Server ab.

Als Basis für die Ansprache Googles soll hier PHP dienen, derzeit eine der beliebten Skriptsprache zur Programmierung von Webservern. Zwei Dinge sind dazu notwendig: den Zugriff auf Google organisieren und PHP SOAP lernen lassen. Die praktische Nutzung der SOAP-API erfordert einen Zugriffsschlüssel von Google. Diesen bekommen Interessierte - bis 1000 Abfragen pro Tag kostenlos - unter www.google.com/apis/. Folgt man den Instruktionen, kommt der Schlüssel per E-Mail ins Haus.

Der Webinstaller aus dem PEAR (PHP Extension and Application Repository) besorgt das für SOAP nötige Modul (Abb. 1).

PHP lässt sich standardmäßig nicht als SOAP-Client einsetzen. Eine diesbezügliche Erweiterung steht nur im CVS-Zweig der PEAR-Website zur Verfügung (nicht leicht zu finden). PEAR ist das PHP Extension and Application Repository - ein Verzeichnis normierter Erweiterungen für PHP, geschrieben in PHP oder in C. Leider gehört der SOAP-Client bei der aktuellen PHP-Version nicht dazu. Programmierer müssen deshalb die notwendigen Dateien auf einem anderen Weg beschaffen - unter cvs.php.net/cvs.php/pear/SOAP.

Bestandteil der gelieferten PEAR-Dateien ist der PEAR::Webinstaller, der die Arbeit vereinfacht. Vor allem unterscheidet sich der Zugriff zwischen Windows und Linux kaum noch. Den Anfang bildet das Skript getsoap.php (Listing 2). Die Variable $pear_path ist so anzupassen, dass sie auf das Verzeichnis pear der eigenen PHP-Installation zeigt.

Mehr Infos

Listing 2: getsoap.php

<?php
$pear_path = "/usr/local/lib/php/PEAR/";
ini_set("include_path", $pear_path);
require("PEAR/WebInstaller.php");
$installer = new PEAR_WebInstaller("", "http://php.chregu.tv/pear/");
$installer->start();
?>

Beim Start von getsoap.php erscheint eine Website, die alle aktuellen PEAR-Pakete zur Installation anbietet. Diese Liste enthält das Paket SOAP. Beim Ausführen des Skripts wird das Paket in das Stammverzeichnis von php4/pear installiert. Gegebenenfalls ist es in das schon existierende PEAR-Verzeichnis zu kopieren, wenn das eigene System anders konfiguriert ist. Die Nutzung des Paketes in PHP ist einfach. Zuerst ist der SOAP-Client einzubinden:

include ("SOAP/Client.php");

Anschließend wird eine Verbindung zu Google hergestellt - derzeit zur Beta-Testsite:

$google = new SOAP_Client("http://api.google.com/search/beta2");

$google enthält das SOAP-Objekt, das die Anfrage ausführen kann. Zuvor sind die nötigen Parameter zu übergeben. Was hier möglich ist, findet sich auszugsweise in der Tabelle.

Parameter für die Standardsuche
Parameter Bedeutung
key Lizenzschlüssel
q Abfrage
start Index des ersten Ergebnisses
maxResults Anzahl Ergebnisse (maximal 10)
filter Filteranweisung
restrict Einschränkung der Suche
safeSearch TRUE, wenn die Suchergebnisse auch für Kinder geeignet sein sollen
lr Einschränkung der Sprache

Wichtig ist der Lizenzschlüssel key, ohne den Google die Anfrage weit von sich weist. Der Parameter q enthält die Anfrage. Für deren Aufbau lohnt sich ein Blick in die Anleitung von Google; auszugsweise zeigt Tabelle oben die wichtigen Funktionen.

Auswahl wichtiger Suchoptionen
Suchform Beschreibung
+Wort Wort muss vorkommen
-Wort Wort darf nicht vorkommen
‘Eine Phrase’ Wörter müssen exakt so enthalten sein
Wort OR Wort2 ODER-Verknüpfung (UND: standardmäßig verwendet)
site: Beschränkung auf eine bestimmte URL

Im Übrigen entspricht die Abfrage exakt dem, was Google über seine Website bietet. Im ersten Versuch soll das Skript nur die eigene Website durchsuchen. Statt einer lokalen Suchmaschine arbeitet Google in diesem Fall im Hintergrund. Dies ist dank der Option site: schnell programmiert. Mit den fertigen Parametern, im Array $parameters startet die Abfrage:

$result = $google->call("doGoogleSearch", $parameters, 'urn:GoogleSearch');

Übergeben wird eines der von Google erlaubten Kommandos aus Tabelle 3, hier doGoogleSearch. $parameters enthält die Parameter des Kommandos als Array. Zuletzt ist noch der Namespace anzugeben, der der Anfrage zugrunde liegt. Das Ergebnis wird als Array $result zurückgegeben - falls kein Fehler aufgetreten ist. Das Programm getgoogle.php (Listing 3) enthält eine kleine Fehlerauswertung, die PEAR- und SOAP-Fehler abfängt und anzeigt.

Googles Suchfunktionen
Kommando Nutzen
doGoogleSearch Standardsuche, benötigt die in Tabelle 1 gezeigten Parameter
doSpellingSuggestion Korrekturvorschlag für Schreibfehler anfordern. Parameter: key und phrase
doGetCachedPage Suche im Google-Cache. Parameter: key und url
Mehr Infos

Listing 3: getgoogle.php

<?php
$pear_path = "C:\WINNT\system32\inetsrv\pear";
ini_set ("include_path", $pear_path);
include ("SOAP/Client.php");
$togoogle = "site:php.comzept.de ";
$togoogle .= $HTTP_POST_VARS['search'];
$google = new SOAP_Client("http://api.google.com/search/beta2");
echo "Ihre Anfrage: $togoogle";
// Hier den Google-Key eintragen !!
$parameters = array('key' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
'q' => $togoogle,
'start' => 0,
'maxResults' => 5,
'filter'=> FALSE,
'restrict'=>'',
'safeSearch'=>FALSE,
'lr'=>'',
'ie'=>'',
'oe'=>'');
$result = $google->call("doGoogleSearch", $parameters, 'urn:GoogleSearch');
if (PEAR::isError($result) || $google->fault)
{
$search_result = "Ein Fehler trat auf: " . $result->message . " SOAP: ";
$search_result .= $google->faultstring;
} else {
$num_result = $result['estimatedTotalResultCounts'];
$elements = $result['resultElements'];
$time = $result['searchTime'];
$search_result = '';
if (is_array($elements))
{
$search_result = "Es wurden $num_result Ergebnisse in $time Sekunden gefunden:<br/>";
foreach($elements as $item)
{
$size = $item['cachedSize'];
$title = utf8_decode($item['title']);
$url = $item['URL'];
$text = utf8_decode($item['snippet']);
$search_result.="<h3>$title ($size Byte)</h3>$text<br/><a href=\"$url\">$url</a>";
}
} else {
$search_result = "Es wurden keine Ergebnisse gefunden.";
}
}
?>
<form method="POST" action="<?=$PHP_SELF?>">
<input type="text" name="search" value="<?=$search?>"/>
<input type="submit" value="Suchen"/>
</form>
<?=$search_result?>

Einfaches Formular und erste Suchergebnisse, ohne im Web Google aufsuchen zu müssen (Abb. 2).

Wer mehr Daten auslesen möchte, sollte einen Blick in die WSDL-Datei werfen, die den Web Service beschreibt. Für die praktische Suche ergeben sich durch die Verwendung von WSDL viele Freiheitsgrade, die aus der umfangreichen Gestaltung der Schnittstelle resultieren. Die Beschreibung ergibt sich direkt aus der WSDL-Datei. Im API-Paket ist die Datei als GoogleSearch.wsdl zu finden. Es ist sinnvoll, immer die aktuelle Version zu verwenden und sein Programm notfalls nach der Dienstbeschreibung zu modifizieren. Ein Blick in GoogleSearch.wsdl zeigt eine Zusammenfassung der Dienste im Zweig portType, wo derzeit drei Elemente operation existieren, die für die Nachrichten die Ein- und Ausgabefunktionen definieren. Hier ein Ausschnitt:

<portType name="GoogleSearchPort">
<operation name="doGetCachedPage">
<input message="typens:doGetCachedPage"/>
<output message="typens:doGetCachedPageResponse"/>
</operation>
<!- ... ->
</portType>

Die korrespondierenden Elemente input/output enthalten wiederum die Anweisung, wie die Nachricht aufzubauen ist. Für die im PHP-Listing verwendete doGoogleSearch sieht dies folgendermaßen aus:

<message name="doGoogleSearch">
<part name="key" type="xsd:string"/>
<part name="q" type="xsd:string"/>
<part name="start" type="xsd:int"/>
<part name="maxResults" type="xsd:int"/>
<part name="filter" type="xsd:boolean"/>
<part name="restrict" type="xsd:string"/>
<part name="safeSearch" type="xsd:boolean"/>
<part name="lr" type="xsd:string"/>
<part name="ie" type="xsd:string"/>
<part name="oe" type="xsd:string"/>
</message>

Definiert werden die Namen der Parameter und deren Datentyp. key kommt in allen Abfragen vor und enthält den von Google übermittelten Lizenzschlüssel. Die Definition der Rückgabe erfolgt ähnlich, denn der Transport der Daten vom Server zum Client läuft ebenfalls via SOAP:

<message name="doGoogleSearchResponse">
<part name="return" type="typens:GoogleSearchResult"/>
</message>

Der Attributwert typens:GoogleSearchResult deutet auf einen eigenen Datentyp hin, da die Rückgabewerte komplex sein können. Im Abschnitt types der WSDL-Datei sind diese Typen definiert.

Es ist einiges Knowhow nötig, um damit tatsächlich universelle SOAP-Clients zu erstellen. Die verfügbare Technik reicht dazu aber vollkommen aus. So wäre es denkbar, den Google-Client so zu gestalten, dass immer alle Funktionen verfügbar sind, gleichgültig wann und in welchem Umfang die WSDL-Datei sich ändert. Dazu bietet die SOAP-Implementierung der PEAR-Klasse schon jetzt gute Voraussetzungen. Sie überführt die WSDL-Datei in ein Array, das PHP leicht verarbeiten kann.

Nach dieser Idee entstand supergoogle.php (Listing 4). Es bietet alle in der WSDL-Datei definierten Dienste an und erzeugt passend dazu die Eingabefelder. Es wertet das Ergebnis aus und gibt es vollständig aus. Bei Letzterem ist zu beachten, dass die WSDL-Datei verschiedene Datentypen für die Ergebnisse definiert, beispielsweise Seiten aus dem Google-Cache Base64-kodiert. Der Name dieses Typs ist in XML-Schema definiert: base64Binary. In PHP dekodiert dies die Funktion base64_decode(). Eher trivial ist dagegen der Umgang mit Typen wie string oder int. Der Aufruf des SOAP-Clients beginnt diesmal mit der Angabe der WSDL-Datei:

$google = new SOAP_Client("./GoogleSearch.wsdl", TRUE, "GoogleSearchPort");
Mehr Infos

Listing 4: supergoogle.php

<?php

function print_a( $TheArray )
{
echo "<table border=\"0\">\n";
$Keys = array_keys( $TheArray );
foreach( $Keys as $OneKey )
{
echo "<tr>\n";
echo "<td bgcolor=\"#727450\" valign=\"top\">";
echo "<b>$OneKey</b>";
echo "</td>\n";
echo "<td bgcolor=\"#C4C2A6\" valign=\"top\">";
if ( is_array($TheArray[$OneKey]) )
print_a ($TheArray[$OneKey]);
else
echo utf8_decode ($TheArray[$OneKey]);
echo "</td></tr>";
}
echo "</table>\n";
}

function setInput($fieldname, $fieldvalue,
$fieldtype, $fieldsize = 0)
{
if (empty($fieldvalue))
{
if ($fieldname == 'key')
// Hier Google-Key eintragen !!
$fieldvalue = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
else
$fieldvalue = $_POST[$fieldname];
}
if ($fieldname == 'key') $fieldtype = 'password';
if ($fieldsize != 0) $fieldsize = "size=\"$fieldsize\"";
echo "<input type=\"$fieldtype\"",
" name=\"$fieldname\"",
" value=\"$fieldvalue\" $fieldsize/>";
}

$pear_path = "C:\WINNT\system32\inetsrv\pear";
ini_set ("include_path", $pear_path);
include ("SOAP/Client.php");

// SOAP-Client erstellen
$google = new SOAP_Client("./GoogleSearch.wsdl",
TRUE, "GoogleSearchPort");

$wsdl = &$google->wsdl; // WSDL
$port = $wsdl->currentPortType; // Port

echo "<table border=\"2\"><tr><td valign=\"top\">";
// Durchlaufen aller definierten Methoden des Webservices
foreach ($wsdl->portTypes[$port] as $localPort => $localPortParameters)
{
echo "<form method=\"post\" action=\"$PHP_SELF\">";
echo "<table>";
echo "<tr><th colspan=\"2\" bgcolor=\"#dddddd\">Dienst: $localPort </th></tr>";
$input = $localPortParameters['input']['message']; // Name der Abfrage
$output = $localPortParameters['output']['message']; // Name des Ergebnisses
// Versteckte Felder für die Abfrage erzeugen
setInput('input', $input, 'hidden');
setInput('output', $output, 'hidden');
foreach ($wsdl->messages[$input] as $parameter => $xsd)
{
echo "<tr><td width=\"100\"><b>$parameter:</b></td><td>";
switch ($xsd)
{
case 'xsd:string':
setInput ($parameter, '', 'text', 30);
break;
case 'xsd:int':
setInput ($parameter, '', 'text', 5);
break;
case 'xsd:boolean':
setInput ($parameter, '1', 'checkbox');
break;
}
echo "</td></tr>";
}
echo "<tr><td></td><td><input type=\"submit\" value=\"Suchen\"/>";
echo "</td></tr></table>";
echo "</form>";

}
echo "</td><td valign=\"top\">";
// Auswertung des Formulars
if ($REQUEST_METHOD == 'POST')
{
$input = $_POST['input'];
$namespace = $wsdl->bindings['GoogleSearchBinding']['operations'][$input]['input']['namespace'];
// fill parameters from form
foreach ($wsdl->messages[$input] as $parameter => $xsd)
{
switch ($xsd)
{
case 'xsd:string':
$value = (empty($_POST[$parameter])) ? '' : (string) $_POST[$parameter];
break;
case 'xsd:int':
$value = (empty($_POST[$parameter])) ? 0 : (integer) $_POST[$parameter];
break;
case 'xsd:boolean':
$value = (empty($_POST[$parameter])) ? FALSE : (boolean) $_POST[$parameter];
break;
}

$parameters[$parameter] = $value;
}
// SOAP-Envelope an Google senden
$result = $google->call($input, $parameters, $namespace);
if (PEAR::isError($result) || $google->fault)
{
// Fehler ausgeben
$search_result = "PEAR-FEHLER: $result->message <br/>";
$search_result .= "SOAP-FEHLER: $google->faultstring <br>";
} else {
// Ergebnisse abholen
$output = $_POST['output'];
$search_result = "Alle Ergebnisse der Abfrage für Methode <b>$output</b><p/>";
echo "<table>";
// Datentyp der Rückgabe
$return_type = $wsdl->messages[$output]['return'];
echo $search_result;
switch ($return_type)
{
case 'xsd:base64Binary':
$result = base64_decode($result);
echo $result;
break;
case 'xsd:string':
$result = (string) $result;
echo "<p style=\"background-color:#C4C2A6\">" . $result . "</p>";
break;
case 'xsd:boolean':
$result = ($result) ? 'JA' : 'NEIN';
echo "<p style=\"background-color:#C4C2A6\">" . $result . "</p>";
break;
default:
if (is_array($result)) print_a($result);
break;
}
echo "</table>";
}
}
echo "</td></tr></table>";
?>

Ein Zugriff auf die analysierten WSDL-Daten ist über das Objekt $google->wsdl möglich. Über die gesamte Struktur kann man alles Wichtige mit print_r($google->wsdl); erfahren.

supergoogle.php erzeugt für jede Funktion ein eigenes Formular, das zwei versteckte Felder enthält. Eins bestimmt die Eingabemethode, beispielsweise doGoogleSearch, das andere den Namen des Ergebnisses. Damit kann beim Empfang des Formulars die richtige Methode gesendet und die Antwort passend ausgewertet werden. Die konkrete Gestaltung der SOAP-Nachricht an Google basiert demnach auf der Auswertung der WSDL-Datei. Ändert Google die, muss man das Formular dementsprechend modifizieren, sodass der Abruf der Daten weiterhin funktioniert, ohne das jedesmal ein direkter Eingriff in den Code erforderlich wäre.

Was hier einfach programmiert ist, beschreibt die Erstellung eines so genannten Proxy, einer Schnittstelle zwischen Web Service und lokalem System, basierend auf der Beschreibung in WSDL. Die direkte Ausgabe ist weniger für die eigene Website geeignet, sondern dient eher der automatischen Verarbeitung. Sie zeigt aber, wo die Reise hingeht. Das ist die eigentliche Botschaft - Computer fangen an, sich auf Basis normierter und beherrschbarer Verfahren zu ‘unterhalten’ und komplexe Daten auszutauschen. Unabhängig vom Betriebssystem ...

Jörg Krause
ist als Fachbuchautor, Dozent und freier Softwareentwickler tätig. Er hat Bücher zu PHP (Hanser) und ASP/ASP.net (Addison-Wesley) verfasst.

[1] Michael Stal; Verteilte Systeme; Prägnante Post; Entfernte Methodenaufrufe à la XML; iX 5/2000, S. 118

Mehr Infos

iX-TRACT

  • Web Services erlauben XML-basierte Anwendungen, bei denen Rechner Daten über HTTP austauschen.
  • Google erprobt eine Schnittstelle, die es erlaubt, statt über die Webseiten über einen mit Google kommunizierenden Dienst Daten direkt bei der Suchmaschine anzufragen.
  • Über die Google-API kann ein PHP-Skript Fragen verschicken und die Antworten verarbeiten.

(hb)