Justus Blümer

Google SERPs als XML abfragen

Update vom 20.8.2012:

Der weiter unten und vor langer Zeit beschriebene Code war ziemlich kompliziert. Während das Proxy-Prinzip aufgrund der Beschränkung von automatisierten Abfragen seitens Google nach wie vor Relevanz hat, würde ich so etwas heute so lösen und den Umweg über YQL auslassen:

<?php

$keyword = ‚kredit‘;
$url = ‚http://www.google.de/search?q=‘.$keyword;

$dom = new DOMDocument();
@$dom->loadHTMLFile($url);

$xpath = new DOMXPath($dom);
$nodes = $xpath->query(„//h3[@class=’r‘]/a/@href“);

foreach ($nodes as $node) {
$href = $node->nodeValue;

// Sonderfälle filtern
if (substr($href,0,5) == ‚/url?‘) {
$href = substr($href,7,strpos($href,’&sa=U‘)-7);
}

echo „$href<br/>“;
}

?>

Möchte man das dann als XML ausgeben, kann das über SimpleXMLElement recht einfach tun. Dieser Code filtern nur einen der vielen möglichen Sonderfälle heraus, nämlich wenn Google statt der echten eine Tracking-URL in das href-Attribut der Links einbaut.

Ursprünglicher Artikel

Für ein kleines SEO-Tool, das ich mir letztens programmiert habe, brauchte ich ein paar Daten, für die ich wiederum die Google-SERPs abfragen musste. Ganz kleines Ding und es sollte alles schnell gehen. Am schnellsten geht sowas natürlich mit einer API, die Google – anscheinend – auch anbietet. Eine einfache Schnittstelle, der man das Keyword liefert und von der man  die Ergebnisse als schön maschinenlesbares XML zurückbekommt, habe ich allerdings nicht gefunden, was auch Sinn macht, schließlich würde Google daran nicht verdienen und seine Daten verschenken.

Also bin ich den Umweg über die HTML-Suchergebnisse gegangen, wie man sie auch im Browser geliefert bekommt, wenn man eine Suche durchführt. Einziges Problem: HTML parsen, also so zu verarbeiten, dass man z.B. nur eine Liste mit den Top10 Ergebnissen hat, ist Krieg. Zum Glück gibt es dafür bereits eine Lösung, die ausgerechnet von Yahoo! kommt: YQL.

YQL sieht ähnlich aus wie die Datenbanksprache SQL und hat zum Ziel, das Internet zur Datenbank zu machen. Man kann eine HTML-Seite abfragen, genau definieren welchen Teil man daraus haben will und bekommt diese (nur diese) Daten als XML zurückgeliefert. Der Sinn dahinter ist, dass XML komplett maschinenlesbar ist und man so ohne Zwischenschritte z.B. in PHP damit arbeiten kann.

Was bringt das?

Damit hat man Zugriff auf eine ganze Menge Daten. Man kann damit ohne viel Aufwand seinen eigenen kleinen Ranking-Check programmieren und interessante statistische Informationen sammeln, mit denen man Studien zusammenstellen kann wie SISTRIX mit der kürzlich veröffentlichten Statistik über Keyworddomains. Oder wie wär’s mit einer kleinen Domainliste? Ein paar tausend wichtige Keywords abfragen, Domains aus den Ergebnissen speichern und damit Expired Domains finden…

Wie funktioniert das?

Trockenübungen für’s erste führt man am einfachsten mit der Konsole aus, in die man direkt sein YQL Statement eingeben kann: YQL Konsole. Ein ganz einfaches Beispiel für ein Query ist:

SELECT * FROM html WHERE url = „http://www.google.de“

Funktioniert, schön. Versucht man, mit solch einem Query aber die SERPs und nicht nur die Startseite abzufragen, schaut man in die Röhre, denn Google schließt von dort aus Crawler mittels der robots.txt aus und Yahoo! hält sich dran. Das bedeutet man muss jemanden dazwischenschalten, der sich für die robots.txt nicht interessiert. Am besten also man machts selbst. Dazu nimmt man einfach folgendes kurzes PHP-Skript:

<?php

// erzeuge einen neuen cURL-Handle
$ch = curl_init();

// setze die URL und andere Optionen
curl_setopt($ch, CURLOPT_URL, ‚http://www.google.de/search?q=‘.$_GET[‚q‘]);
curl_setopt($ch, CURLOPT_HEADER, 0);

// führe die Aktion aus und gebe die Daten an den Browser weiter
curl_exec($ch);

// schließe den cURL-Handle und gebe die Systemresourcen frei
curl_close($ch);

?>

Das ist ein Mini-Proxy, über den wir unsere Suchanfrage stellen. Der Server auf dem das Skript liegt fragt wie ein ganz normaler Internetnutzer an und schickt uns das Ergebnis weiter. Damit haben wir das HTML, das wir verarbeiten wollen. Damit ist die Vorbereitung komplett und folgendes Query liefert uns das was wir wollen: Ergebnisse.

SELECT href FROM html WHERE url = „http://www.justusbluemer.de/search.php?q=kredit“ AND xpath = „//a[@class=’l‘]“

Den Stern (*) habe ich durch href ersetzt, denn das Ziel-Attribut ist gerade das Einzige, was uns interessiert. Als URL wird natürlich unser selbstgebauter „Proxy“ eingesetzt, der uns das Suchergebnis weiterleitet. Hinter q steht das Keyword, dessen Suchergebnisse wir abfragen wollen. xpath ist ebenfalls ein wichtiger Teil, denn hier wird das Ergebnis auf das nötigste reduziert: Wir bekommen nur Links (<a>-Tags) zurückgeliefert, die mit dem class-Attribut l ausgestattet sind – und das sind nur die Links in den Suchergebnissen!

Das Ergebnis sieht so aus:

<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="13" yahoo:created="2009-10-27T07:36:46Z" yahoo:lang="en-US" yahoo:updated="2009-10-27T07:36:46Z" yahoo:uri="http://query.yahooapis.com/v1/yql?q=SELECT+href+FROM+html+WHERE+url+%3D+%22http%3A%2F%2Fwww.justusbluemer.de%2Fsearch.php%3Fq%3Dkredit%22+AND+xpath+%3D+%22%2F%2Fa%5B%40class%3D%27l%27%5D%22">
    <results>
        <a href="http://www.online-kredit-index.de/"/>
        <a href="http://www.schnell-kredit.info/"/>
        <a href="http://www.financescout24.de/kredite-finanzierung/kredit.aspx"/>
        <a href="http://www.finanzinform.de/"/>
        <a href="http://de.wikipedia.org/wiki/Kredit"/>
        <a href="http://www.kredit.org/"/>
        <a href="http://www.bon-kredit.de/"/>
        <a href="http://www.creditplus.de/"/>
        <a href="http://www.kredit-engel.de/"/>
        <a href="http://www.dkb.de/"/>
        <a href="http://www.zeit.de/newsticker/2009/10/26/iptc-bdt-20091026-517-22801658xml"/>
        <a href="http://www.handelsblatt.com/sparkassen-duerfen-kundenkredite-verkaufen;2474364"/>
        <a href="http://www.wienerzeitung.at/DesktopDefault.aspx?TabId=3926&amp;alias=wzo&amp;cob=446570"/>
    </results>
</query>

Dieses XML kann man nun mit zwei, drei Zeilen PHP in einer Datenbank speichern und immer und immer mehr Daten anhäufen, je mehr Anfragen man stellt. Genau da liegt allerdings auch die

Einschränkung

Wir fragen die normale Web-Suche ab. Damit bekommen wir authentische Ergebnisse wie jeder andere Internetnutzer auch, allerdings unterliegen wir auch den selben Restriktionen. Stellt man zu viele Anfragen in kurzer Zeit, blockt Google ab und lässt Suchen nur noch mit Captcha zu. Bei meinen Versuchen brauchte ich da schon ein paar tausend Anfragen, aber viel ist das immer noch nicht. Die einfachste, allerdings etwas aufwändige Methode, ist, unser „Proxy-Skript“ auf verschiedene Webhoster aufzuteilen. 10 dieser Skripte auf verschiedene IPs verteilt, die Pfade dazu in einen selbstgeschriebenen zentralen Quasi-Loadbalancer eintragen (auch recht einfach in PHP zu bewerkstelligen) und schon vervielfacht sich die Zahl der verfügbaren Anfragen. Mittlerweile hat ja anscheinend jeder Freehoster PHP im Angebot, das reicht ja im Prinzip auch vollkommen.

Roundup

Einen genialen Vorteil hat das Proxy-Prinzip: Je nach Serverstandort des „Proxy“ gibt es landesspezifische SERPs. Sprich man kommt sehr einfach an original ausländische SERPs, wenn man das will.

Im fertigen Programm nutzt man YQL am einfachsten über die Web Service URL. Vom Programm aus (in PHP auch einfach über cURL oder noch simpler ReadFile) aufrufen und man bekommt das Abfrageergebnis zurück. Irgendwann meckert Yahoo! dann allerdings. Wer bspw. für einen Webdienst eine größere Abfrageanzahl braucht, kann sich einen API-Key holen und hat dann einen größeren Verfügungsrahmen. Kostet auch nichts und geht zügig.

Über Kritik über Sinn und Unsinn dieser Methode und über Erfahrungen und Anwendungen würde ich mich sehr freuen!