Browser und Bots am User-Agent-String erkennen

Testergebnisse

Wir haben bei MGVmedia so einige Webprojekte angehäuft. Viele von denen versuchen herauszufinden, wer oder was ein Besucher ist: Bot oder Browser? Welcher genau? Welche Version? Welches Betriebssystem? Vor allem bei Besucherstatistiken muss man es genau wissen. Aus dem User-Agent-String des HTTP-Headers lässt sich das feststellen. Da aber jede Software selbst entscheidet, was genau dort drin steht, ist das ein kompliziertes Verfahren, welches man mit der Zeit immer wieder anpassen muss. Bisher haben wir Lösungen tief in die Projekte integriert, wodurch diese nur sehr schwierig wartbar sind. Zeit sich eine fundiertere Lösung zu überlegen.

Ein JSON-Web-Service

Um eine nachhaltige Lösung zu erreichen, sind drei wesentliche Komponenten geplant:

  1. Ein Server, dem man mittels Get-Request einen User-Agent-String sendet. Dieser antwortet im JSON-Format, ob der String bekannt ist, und, wenn ja, welcher Bot oder Browser sich dahinter verbirgt.
  2. Eine Client-Bibliothek, welche die Netzwerkkommunikation mit dem Server übernimmt und fertige Browser- oder Bot-Objekte zurückliefert.
  3. Ein Testprogramm, welches mit aktuellen User-Agents gefüttert wird und die Strings ausgibt, welche nicht erkannt werden konnten. Zudem kann es unbekannte Anfragen des Servers sichern und regelmäßig per Mail darum bitten, die neuen Strings zuzuordnen.

Der Server

Das Datenmodell

Erbt von Klasse Attribute
Agent String identifier (der User-Agent-String)
Agent Bot String name (menschenlesbarer Name des Bots)
Bot EIBot String substring (markanter Teil des UA-Strings)
Agent Browser String name (menschenlesbarer Name des Browsers), String version (Version des Browsers)
Browser EIBrowser String substring (markanter Teil des UA-Strings)

Der „Schnelltest“

Jeder bekannte Bot bekommt ein Objekt, in dem sein lesbarer Name steht:

$known_bots = array(
    new EIBot('Googlebot', 'Googlebot'),
    new EIBot('Google Feedfetcher', 'Feedfetcher-Google'),
    new EIBot('Bing Bot', 'http://www.bing.com/bingbot.htm'),
    // ...
);

Wie jeder Agent hat ein Bot eine Methode match, welche einen UA-String als Argument nimmt und entscheidet, ob der User-Agent-String zu dem Objekt passt oder nicht. So kann bei einer Anfrage jedes bekannte Bot-Objekt gefragt werden. Passt keines, handelt es sich um keinen bekannten Bot.

EI steht für „easily identifiable“: Der EIBot-Konstruktor nimmt den lesbaren Namen des Bots und einen markanten Teil des User-Agent-Strings, welcher den Bot definitiv identifiziert. In der match-Methode kann etwa in PHP mit dem effizienten strpos entschieden werden, ob der Substring enthalten ist und der String „matcht“.

public function match($userAgentString) {
    return (strpos($userAgentString, $this->substring) !== false);
}

Mit den Browsern funktioniert es genauso: Viele sollen mittels EI-Objekten schnell gefunden werden. Ob man aufgrund schnell wechselnder Versionsnummer noch einen RegexBrowser ergänzt, muss die Erfahrung zeigen.

Bei Browsern zeigt der „Schnelltest“ oft ein Problem auf: Bots tarnen sich gern als Browser, und so lässt sich von „Firefox/3.6“ im UA-String nicht zwangsweise auf Firefox schließen. In aller Regel ist aber zusätzlich eine Internet-Adresse oder Bot-Kennung erhalten, welche diesen Bot „verrät“. Bei der Frage, ob es sich um einen Browser handelt, sollte also geprüft werden, ob der UA-String einen Browser repräsentiert und ob er keinen Bot repräsentiert.

function query_browser($user_agent_string) {
    // Lots of bots look like browsers - let's check that first
    if (query_bot($user_agent_string)) return null;
    // ...

Die Client-Bibliothek

Die Client-Bibliothek verfügt über das selbe Model. Allerdings geht diese nur von Bot bzw. Browser aus. Ob es sich um einen EIBot oder eine andere Spezialisierung handelt, ist an dieser Stelle uninteressant. Zudem bietet der Client zwei Funktionen: query_bot($ua_string) und query_browser($ua_string). Beide geben, wenn verfügbar, das entsprechende Objekt zurück. Ansonsten ist die Rückgabe null.

Der Test

Eine erste Umsetzung zeigt das Testskript, welches ein Array mit User-Agents nimmt, versucht diese zu erkennen und ensprechende Rückmeldung gibt:

Testergebnisse

Testwerte lassen sich einfach aus PHP-My-Admin exportieren. Hierfür einfach die entsprechende Spalte selektieren und das Ergebnis als PHP-Array exportieren.

Weitere Entwicklung

Die oben skizzierte Idee war schnell umgesetzt. Sicher fehlt es noch an Feinschliff, aber es scheint zu funktionieren und sehr schnell zu sein (der Testfall, welcher bereits die JSON-Kommunikation nutzt, braucht für 1000 User-Agents circa drei Sekunden). Folgende Punkte sind noch offen:

  • Browser-Versionsnummern sollten irgendwie automatisch erkannt werden
  • Betriebssystemerkennung sollte hinzu
  • Nicht erkannte Strings sollten gespeichert werden

Vielleicht greift mir ja Georg unter die Arme. Dann sollte schon bald eine erste Version bereitstehen.

6 Kommentare

  1. I had got a desire to start my business, however I did not have enough of money to do this. Thank heaven my close fellow suggested to utilize the loans. Thus I took the short term loan and realized my desire.

  2. Jo, ist ein bisschen doof. Aber gut, passiert ja jetzt nicht täglich. Frage mich, wie die das machen? Captcha geknackt oder JS ausgeführt?

    Warte mal bis ich mit meiner Masterarbeit fertig bin, da geht das gespamme erstmal los 😛

  3. Ich habe auch keine Idee, wie das passieren kann. Aber wenn es döller wird, kann man ja mal eine Logging mit einbauen.

  4. Ihr Post ist ja bereits etwas älter. Wurde Ihr Tool weiterentwickelt bzw. fertiggestellt? Ich bin auf der Suche nach einem Tool, mit dem ich feststellen kann, welche Bots auf unserer Seite waren, um bestimmte Bots über die robots.txt zu blocken…

    Über eine Antwort, gern als PM, würde ich mich sehr freuen.

  5. Nein, das Projekt hat es bei uns nicht in den Produktiveinsatz geschafft und ist dementsprechend wie hier beschrieben stehen geblieben. Eigentlich schade drum.

Kommentare sind geschlossen.