Jeder Web-Server, der eine Anfrage erhält, protokolliert ein paar
Informationen über den Besucher, wie den User-Agent,
die IP-Adresse, et cetera. Was leider fehlt ist die Angabe aus welchem Land die Anfrage kommt,
obwohl diese Information gerade bei international ausgelegten Web-Sites von
Interesse ist, gerade in Bezug auf das Marketing, wenn man den
ein solches betreibt. Mit dem Wissen aus welchem Land die überwiegende
Anzahl der Besucher kommt, lassen sich z.B. Werbeaktionen wesentlich
effektiver einsetzen.
Der einzige sichere Anhaltspunkt zu ermitteln aus welchem Land eine
Seitenanfrage kommt, ist die übermittelte IP-Adresse. Nachfolgend drei
Alternativen, wie man dies hinbekommt.
Alternative 1
Mit der IP-Adresse lässt sich im ersten Schritt über das Domain
Name System (DNS) schon einmal der Host-Name der
Anfrage ermitteln. Wie das funktioniert habe ich u.a. im Artikel
Mit der IP-Adresse den Host-Namen auflösen beschrieben.
So wird z.B. aus der IP-Adresse 213.39.164.xxx der
Hostname xxx.adsl.hansenet.de. Extrahiert man nun z.B. per
ASP aus dem Host-Namen die Top-Level-Domain (TLD), also
die letzten Zeichen nach dem letzten Punkt, so kann man für unser Beispiel
sagen, das der Seitenaufruf von einem deutschen Server stammte. Genauer: von
einem Kunden des deutschen Providers Hansenet. Gelegen kommt uns dabei die
Tatsache, dass die Codes der Länder-TLD's mit den standardisierten ISO-3166-Länderkennungen
übereinstimmen.
'IP auslesen
strIP = Request.ServerVariables("REMOTE_ADDR")
'Hostname ermitteln (siehe zerbit-Artikel Nr.40 und 41)
strHost = GetHostName(strIP)
'Hostname an den Punkten in Array zerlegen
arr = Split(strHostname, ".")
'Letztes Array-Element enthält TLD
strTLD = arr(UBound(arr))
Sammeln kann man diese Information nun z.B. in einer Datenbanktabelle mit
folgender Struktur:
| TLD |
Anzahl |
| de |
1023 |
| at |
345 |
| ch |
123 |
Bei jedem Zugriff kann man nun die TLD ermitteln und die Anzahl in der
Tabelle um 1 erhöhen.
Problem
Problematisch beim Einsatz dieser Variante sind all jene TLD's, die keine
Länderkennung tragen: COM, NET, ORG, EDU, et cetera. Man könnte nun hingehen
und automatisch davon ausgehen, dass diese Server in den USA stehen, aber
das würde das Bild extrem verfälschen, denn z.B. die TLD's COM und NET sind
auch außerhalb der USA sehr beliebt.
Weiterhin kann es sein, dass ein Server zwar eine Länderkennung
trägt, aber dem Land gar nicht zuzuordnen werden kann. Beispiel hierfür ist die
Top-Level-Domain TV, die zwar dem Inselstaat Tuvalu gehört, aber gerade bei
Fernsehsendern sehr beliebt ist. Die Regierung von Tuvalu hat schlicht die
eigene TLD verkauft.
Alternative 2
Dem Problem, die TLD's COM, NET, et cetera aufzulösen, kommen wir
nur bei, wenn wir uns externer Daten bedienen. Man muss dazu wissen, dass
der gesamte IP-Adressbereich nach gewissen Regeln weltweit aufgeteilt ist.
Man kann also, wenn man über die aktuellen Aufteilungsdaten verfügt, aus
einer IP-Adresse direkt das Land des Servers ableiten.
Es gibt inzwischen einige kommerzielle Dienste, die die Zuordnung einer
IP zu einem Land über Web-Dienste ermöglichen. Meist erwirbt man sich dabei
ein Zugriffskontingent, d.h. für die erfolgreiche Bestimmung von 10.000
IP-Adressen muss man dann Betrag X berappen.
Man kann heutzutage jedoch davon ausgehen, dass es für jede Art von
Internet-Dienst auch ein kostenloses Pendant aus dem Open-Source-Bereich
gibt. So auch hier. Bei der Recherche nach Diensten, die IP-Adressen in
Länderkennungen auflösen, stieß ich auf hostip.info,
einem Dienst unter der Common-Public-License (CPL). Die Datenbasis von
hostip.info bilden eigene Robots, die unablässig IP-Adressen per
Traceroute auflösen. Benutzer des Service sind jedoch aufgefordert
fehlende bzw. falsche Einträge zu korrigieren, was mit der Zeit zu einem recht
umfangreichen Datenbestand führte und führt.
hostip.info bietet für die automatisierte Abfrage eine API.
So kann man sich die Daten, neben einem Text-Feed, auch in einer XML-Datei liefern lassen.
Grundlage ist wie so oft das XMLHTTP-Objekt.
Beispiel für eine ASP-Prozedur zur Abfrage:
Private Sub GetCountry_hostip(strIP, strCode, strName)
strURL = "http://api.hostip.info/?ip=" & strIP
Set objXmlHttp = CreateObject("MSXML2.ServerXMLHTTP")
objXmlHttp.open "GET", strURL, False
objXmlHttp.send
strCode = objXmlHttp.ResponseXml.DocumentElement._
GetElementsByTagName("countryAbbrev").Item(0).Text
strName = objXmlHttp.ResponseXml.DocumentElement. _
GetElementsByTagName("countryName").Item(0).Text
Set objXmlHttp = nothing
End Sub
Wie im Beispiel dargestellt, bekommt man zwei Informationen zurück: die
ISO-Länderkennung (z.b. DE) und den englischen Namen des Landes (z.B.
GERMANY). Über den Text-Feed erhält man zusätzlich noch die Koordinaten des
Servers, sofern sie vorliegen.
Problem
Um eine lückenlose Statistik zu erhalten, muss man jeden ersten Zugriff
auf eine Web-Site auf diese Art und Weise protokollieren. Im Test reagierte
hostip.info jedoch zum Teil etwas bockig. Mehr als einmal
lief ich in einen Timeout, was natürlich dazu führt, dass der Seitenaufbau
der eigenen Seite sich extrem verzögert. Und das nur wegen einer
Länderstatistik?
Alternative 3
Die indische Firma Directi bot über das Portal webhosting.info bis vor Kurzem ebenfalls einen
Länderabfragedienst an. Er wurde jedoch eingestellt, da man den
aufkommenden Traffic nicht mehr vernünftig bewältigen konnte und sich das Ganze
wohl nicht mehr
rechnete. Einzig die Datenbasis blieb bestehen und wird auch weiter
gepflegt. Jeder interessierte Webmaster kann sich die Daten der IP-To-Country-Database (zur Zeit ca.
63.000 Datensätze) in Form einer CSV-Datei gepackt als ZIP herunterladen und
weiterverarbeiten.
Die Daten liegen in folgendem Format vor:
IP-From IP-To Country (2-Letter-Code, 3-Letter-Code, Name)
======= ===== ==== ===== =================================
"33996344","33996351","GB","GBR","UNITED KINGDOM"
"50331648","69956103","US","USA","UNITED STATES"
"69956104","69956111","BM","BMU","BERMUDA"
...
"264482816","264486911","DE","DEU","GERMANY"
Jeder Datensatz repräsentiert einen IP-Bereich und ist einem Land
zugeordnet. Die IP-Adressen liegen der besseren Vergleichbarkeit halber als
Ganzzahlen vor.
Vor dem Einsatz der Daten, müssen sie zunächst in eine Datenbank
importiert werden. In meinem Beispiel kommt eine Access-Datenbank zum
Einsatz, da man eine solche Datei bei einem der regelmäßigen Updates der
IP-To-Country-Daten einfach nur erneut erstellen und über die alte kopieren
braucht und sich CSV-Dateien zudem sehr leicht über die eingebauten Assistenten in eine Access-MDB pumpen
lassen. Beachten sollte man beim Import der CSV-Datei über ein deutsches
Access, dass als Feld-Trennzeichen ein Komma verwendet wurde und dies in
Access als Dezimaltrennzeichen gewertet wird.
Da der Import regelmäßig stattfinden sollte, verändern wir die
Standardeinstellungen des Import-Assistenten in Bezug auf den Namen der
neuen Tabelle nicht. Sie heißt nachher ebenso wie die CSV-Datei:
Ip-to-country. Die Feldnamen werden nicht geändert. Die von Access
vorgeschlagene fortlaufende Nummerierung (Feld1, Feld2,...) genügt. Die
Access-Datenbank benennen wir ip2country.mdb.
Zum Vergleich einer IP-Adresse mit den Daten der Tabelle, muss diese
zunächst ebenfalls in eine Ganzzahl umgerechnet werden:
Public Function IP2Number(strIP)
arr = Split(strIP, ".")
intConvert = _
(arr(0) * (256*256*256)) + _
(arr(1) * (256*256)) + _
(arr(2) * 256) + _
(arr(3))
IP2Number = intConvert
End Function
Mit dieser Zahl fragen wir dann die Access-Tabelle ab:
Public Sub GetCountry_LocalDB(intIP, strCode, strName)
'Connection-String erzeugen
strConString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source="
strConString = strConString & Server.MapPath("/database/ip2country.mdb")
'Verbindung zur Datenbank aufbauen
Set connIP = Server.CreateObject("ADODB.Connection")
connIP.Open strConString
'Recordset erzeugen und Daten abfragen
Set rsLocIP = Server.CreateObject("ADODB.Recordset")
strSQL = "SELECT * FROM [Ip-to-country] " & _
"WHERE Feld1 <= " & strIPNr & " AND Feld2 >= " & strIPNr
rsLocIP.Open strSQL, connIP
'gefundenen Datensatz auswerten
If Not(rsLocIP.EOF) OR Not(rsLocIP.BOF) Then
strCode = rsLocIP.Fields("Feld3")
strName = rsLocIP.Fields("Feld5")
Else
strCode = ""
strName = ""
End if
'Recordset und Verbindung wieder schließen
rsLocIP.Close
connIP.Close
Set rsLocIP = nothing
Set connIP = nothing
End Sub
Fazit
Es gibt bei der kostenfreien Ermittlung der Länderkennung einer
IP-Adresse keine Lösung die vollends überzeugt. Durch den geschickten
Einsatz aller drei hier vorgestellten Ansätze, lässt sich jedoch eine recht
saubere Statistik erzeugen, die wohl ziemlich nahe an der Wirklichkeit
liegt.
Wer eine solche Statistik mit etwas Farbe aufpeppen möchte, dem lege ich
meine 222 Länder-Icons in der Größe 20 x 13 Pixeln im GIF-Format ans Herz.
Downloads