Besucherverfolgung für Fortgeschrittene
Geschrieben von: Stefan Mayer In meinem Artikel Benutzerverfolgung in ASP habe ich eine recht einfache Methode beschrieben, wie man ein aussagekräftiges Logfile erstellen kann. In meinem heutigen Artikel möchte ich eine Anleitung geben, wie auf Basis des vorangegangenen die Besuche noch besser verfolgt werden können. Vorweg möchte ich wieder betonen, daß es hier nicht darum gehen soll, die Besucher der WebSite auszuspionieren, sondern darum, um Rückschlüße auf Interessen der Besucher ziehen zu können, um das Online-Angebot optimieren zu können. Ich selbst setze dieses hilfreiche Tool in einer Community ein, um die Mitglieder optimal informieren zu können. Funktionale Unterschiede zur "alten" VersionIn der ersten Version (Benutzerverfolgung in ASP) werden Seitenaufrufe in eine Datenbank eingetragen, und zwar jedes Mal, wenn dies gewünscht wurde - sei es auf der Startseite, sei es auf bestimmten Seiten. Dadurch ist es nicht immer möglich, nachzuvollziehen, welche Informationen sich ein Besucher angesehen hat und welche nicht; oft war es auch nicht möglich, genau zu sagen, wieviele Besucher nun wieviele Seiten angesehen haben. In dieser zweiten Version enthält die Datenbank zwei Tabellen - die erste Tabelle enthält die Session-ID und speichert die "Herkunft" des Besuchers, die zweite Tabelle enthält nur die Informationen, was sich der Besucher ansieht. Damit das auch funktioniert, sind Anpassungen an der Global.asa notwendig - und natürlich auch, daß diese vom Server verarbeitet werden kann - das Web muß also eine eigenständige Applikation sein. Nicht viel geändert hat sich an der Include-Datei, die die Seitenzugriffe protokolliert. Neu hingegen ist die Funktionalität daß die "Verweildauer" ausgerechnet wird - natürlich nur soweit das möglich ist. Version 2 setzt voraus, daß der Browser des Besuchers Cookies annimmt, da die Identifizierung über eine Session-Variable erfolgt. Die DatenbankDie Datenbank "elog.mdb" enthält zwei Tabellen - diese können problemlos in eine andere Datenbank kopiert werden oder auf einen SQL-Server. Es muß lediglich der Connection-String adaptiert werden. Die Tabelle log_SessionDiese Tabelle enthält die Daten, die wir über unseren Besucher wissen wollen. Das ist in erster Linie die ID (die übrigens auch als Zugriffszähler ausgewertet werden kann), aber auch IP-Adresse und Host - sowie die Infos, über welche Seite der Besucher eingestiegen ist und woher der Verweis kam. ID Nummer der Session (Autowert) Start Enthält das Datum & Zeit des Zugriffs Ende Enthält das Datum & Zeit des Verlassens UID Enthält optional eine User-ID IP IP des Besuchers HOST Hostname (aufgelöst) des Besuchers StartPage Name der Einstiegsseite BrowserTXT Browser-Identifikation Referrer Zugriffsverweis (gekommen von) BTyp Browser-Name BVer Browser-Versionsnummer Dauer Verweildauer in s auf der WebSite Ebenfalls neu in der Tabelle ist die User-ID. Über dieses Feld könnte zu einem späteren Zeitpunkt die ID eines angemeldeten Besuchers, der in einer anderen Tabelle verwaltet wird, verknüpft werden. So läßt sich dann eindeutig zuordnen, WER der Besucher war und was er genau gesehen hat - um beispielsweise beim nächsten Besuch ungesehene Information vorzureihen - oder um eigene Zugriffe aus der Statistik ausblenden zu können. Die Ausgabe der Daten, wie sie weiter unter beschrieben ist, verwendet diese Information jedoch nicht. Mit Daten befüllt wird diese Tabelle in der Global.asa - eine Beschreibung dieses Vorgangs folgt etwas weiter unten. Die Tabelle log_ActionDiese Tabelle enthält Daten darüber, was unser Besucher genau gemacht hat - und wann. AID Primärschlüssel/Autowert SID Session-Nummer Start Datum & Zeit des Eintrages Art Art des Ereignisses Txt Protokollierter Text Zahl Protokollierte Zahl Dauer Zeit bis zur nächsten Aktion in s Neu hier ist die "Art" der Aktion. Hier können beliebig viele Aktionsarten (z.b. Aufruf einer Seite, Verwendung eines Formulars, Klicken auf einen Link, etc.) verwendet werden. Zusätzlich kann ein Text (z.b. Inhalt eines Suchformulars oder eines Titels) oder eine Zahl (Zugriff auf Information Nummer x) eingetragen werden. Diese Tabelle wird über eine Funktion ("makelog") mit Daten befüllt. Die Global.asaDie Global.asa ist ein Script, das Prozeduren enthält, die vom Server - für den Besucher unsichtbar - bei bestimmten Ereignissen ausgeführt werden. Wir benötigen die Prozeduren, die bei Beginn und bei Ende einer Session ausgeführt werden - und zuvor definieren wir den Connection-String als Applikations-Variable, was auch den Vorteil hat, daß bei Änderungen von Name oder Speicherort der Datenbank nicht jedes Script durchsucht und gegebenenfalls geändert werden muß. Sub Application_OnStart Application("strConn") = "Driver={Microsoft Access Driver (*.mdb)};DriverID=25;DBQ=" & Server.MapPath("elog.mdb") & ";FIL=MS Access;MaxBufferSize=512;PageTimeout=5;" END Sub Sub Session_OnStart on error resume next Es ist zwar nie gut, Fehler zu übergehen, aber ein Fehler an dieser Stelle verhindert, daß irgendetwas von der Website angezeigt wird. Mögliche Fehlerursachen sind in der Regel schreibgeschützte Datenbanken oder volle Datenträger. REM Hier wird der verwendete Browser ermittelt Set BC = Server.CreateObject("MSWC.BrowserType") txtBro = bc.browser if txtBro = "" Then txtBro = "-" txtVer = bc.Version if txtVer = "" Then txtVer = "-" Set BC = Nothing Hier wird der verwendete Browser ermittelt... REM Daten ermitteln: IP-Adresse und Host-Name txtIP = Request.ServerVariables("REMOTE_ADDR") REM Hier wird unter Verwendung der Komponente "ASPDNS" der zughörige Name des Hosts ermittelt REM verwendet man eine andere Komponente, so muß der Aufruf entsprechend geändert werden REM will (oder kann) man keine DNS-Auflösung machen, muß man einfach txtHost = "-" eintragen Set DNS = Server.CreateObject("AspDNS.Lookup") txtHost = DNS.ReverseDNSLookup(Request.ServerVariables("REMOTE_ADDR")) Set DNS = Nothing … Und hier die IP-Adresse und auf Wunsch der dazugehörige Host-Name. REM andere Daten ermitteln txtAgent = Request.ServerVariables("HTTP_USER_AGENT") if txtAgent = "" Then txtAgent = "-" txtRefer = Request.ServerVariables("HTTP_REFERER") if txtRefer = "" Then txtRefer = "-" txtScript = Request.Servervariables("SCRIPT_NAME") if txtScript = "" Then txtScript = "-" Auch hier muß wohl nicht viel dazugesagt werden - es gibt auch kaum Änderungen zur ersten Version. REM Datenbank öffnen Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open Application("strConn") Hier sollte der Datenbankpfad geändert werden - oder der Name. Ideal ist natürlich ein eigener Datenbankordner. Set RS = Server.CreateObject("ADODB.Recordset") RS.Cursortype = 1 RS.LockType = 3 RS.Open "SELECT * FROM log_Session WHERE 1=0", Conn RS.AddNew RS.Fields("Start").Value = Now RS.Fields("IP").Value = txtIP RS.Fields("Host").Value = txtHost RS.Fields("StartPage").Value = txtScript RS.Fields("Referrer").Value = txtRefer RS.Fields("BrowserTxt").Value = txtAgent RS.Fields("BTyp").Value = txtBro RS.Fields("BVer").Value = txtVer RS.Update Die Daten werden in die Tabelle geschrieben. Session("ID") = RS.Fields("ID").Value Das hier ist neu - hier wird nach dem Schreiben der Daten die von Access erzeugte Besucher-ID in die Session-Variable namens "ID" eingetragen. Diese ist der Schlüssel für die Protokollierung der Ereignisse - und gleichzeitig ein Zugriffszähler. RS.Close Set RS = nothing Conn.Close Set Conn = Nothing End Sub Die Datenbank wird noch geschlossen, und wir räumen brav hinter uns auf. Als nächstes folgt die Protokollierung des Verlassens der Site: Sub Session_OnEnd If Session("ID") > 0 Then Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open Application("strConn") Set RS = Server.CreateObject("ADODB.Recordset") RS.Cursortype = 1 RS.LockType = 3 RS.Open "SELECT * FROM log_Session WHERE ID="&Session("ID"), Conn Die Datenbank wird geöffnet und der Datensatz mit zugehöriger Session-Nummer ausgewählt. if not rs.eof then SAlt = RS.Fields("Start").Value Rs.Fields("Dauer").Value = DATEDIFF("s", SAlt, now) RS.Fields("Ende").Value = Now RS.Update Existiert ein entsprechender Datensatz, so wird die Endzeit eingetragen sowie die Differenz zwischen Start und Ende in Sekunden. Es folgen dann nur noch die bekannten Aufräumarbeiten: RS.Close Set RS = nothing Conn.Close Set Conn = Nothing End If End Sub Makelog.aspMakelog.asp ist eine Include-Datei, die die Aktionen des Besuchers protokolliert. <% Function MakeLog(Art,Txt,Zahl) Set Conn = Server.CreateObject("ADODB.Connection") Conn.Open Application("strConn") Set RS = Server.CreateObject("ADODB.Recordset") RS.Cursortype = 1 RS.LockType = 3 RS.Open "SELECT Top 1 * FROM log_Action WHERE SID=" & Session("ID") &" ORDER BY START Desc", Conn Zuerst wird die Datenbank geöffnet und der jüngste Eintrag ausgewählt if not rs.eof then SAlt = RS.Fields("Start").value Rs.fields("Dauer1").value = DATEDIFF("s", SAlt, now) rs.update Existiert bereits ein Eintrag, so wird die seitdem vergangene Zeitspanne berechnet und eingetragen. end if RS.AddNew RS.Fields("Start").value = Now RS.Fields("SID").value = Session("ID") If Art = "" Then Art = "-" RS.Fields("Art").value = Art If Txt = "" Then Txt = "-" RS.Fields("Txt").value = Txt RS.Fields("Zahl").value = Zahl Anschließend wird ein neuer Datensatz angelegt... RS.Update RS.Close Conn.Close Set Conn=Nothing Set RS = Nothing ... und die Datenbank wieder geschlossen. MakeLog = 1 End Function %> Verwendung der Include-DateiIn diesem Beispiel wird der Aufruf des Impressums protokolliert <!-- #INCLUDE FILE="makelog.asp" --> <% Dummy = MakeStat("Info", "Impressum", 0) %> Und hier der Aufruf eines Links <!-- #INCLUDE FILE="makelog.asp" --> lt;% Dummy = MakeStat("Link", "http://www.aspheute.com/", 0) response.redirect "http://www.aspheute.com/" %gt; Sinnvollerweise sollte man die Links ebenfalls in einer Datenbank ablegen und hier nur deren Schlüssel eintragen - um's verständlicher zu machen, habe ich das hier im Klartext eingetragen. Auswertung, die Erste - die Top 10Mit einfachen SQL-Abfragen lässt sich nun eine Statistik erstellen, die auf einen Blick sagt, was die Besucher interessiert und woher sie kommen. Die dem Archiv beigefügte Auswertung ermittelt, woher die meisten Besucher kommen, über welchen Zugang sie ins Internet einsteigen, welches die erste aufgerufene Seite war und welche Seiten die Besucher am meisten interessieren. Und so funktioniert es (Codeauszüge): strSQL = "SELECT top 10 Referrer, COUNT(*) AS C FROM log_session GROUP BY Referrer ORDER BY Count(*) desc" Set rs = Server.CreateObject("ADODB.Recordset") rs.open strSQL, Application("strConn")%> Hier wird die erste Abfrage durchgeführt: Alle Einträge der Tabelle, wo die Sessions protokolliert werden, werden nach dem http-Referrer gruppiert und nach der Anzahl sortiert. Es werden die ersten 10 Datensätze genommen - ganz leicht läßt sich die Zahl auf jeden anderen Wert ändern. <% Count = 0 while not rs.eof count = count + 1 response.write "<tr><td>" response.write count response.write "</td><td>" response.write RS.Fields("C").Value response.write "</td><td>" response.write RS.Fields("Referrer").Value response.write "</td></tr>" rs.movenext wend rs.close set rs=Nothing %> Danach werden in 3 Spalten die Daten ausgegeben. <% strSQL = "SELECT top 10 StartPage, COUNT(*) AS C FROM log_session GROUP BY StartPage " & _ "ORDER BY Count(*) desc" Set rs = Server.CreateObject("ADODB.Recordset") rs.open strSQL, Application("strConn")%> Als nächstes folgt das Gleiche mit den Startseiten <% strSQL = "SELECT top 10 IP, Host, COUNT(*) AS C FROM log_session GROUP BY IP, Host " & _ "ORDER BY Count(*) desc" Set rs = Server.CreateObject("ADODB.Recordset") rs.open strSQL, Application("strConn")%> Etwas "komplizierter" ist die Sache bei IP-Adresse & Host, denn hier muß die Gruppierung auch nach dem Hostnamen erfolgen: <% strSQL = "SELECT top 10 Item, COUNT(*) AS C FROM q_log_action GROUP BY Item " & _ "ORDER BY Count(*) desc" Set rs = Server.CreateObject("ADODB.Recordset") rs.open strSQL, Application("strConn")%> Zum Schluß wird eine Abfrage - q_log_action - verwendet. In dieser Abfrage werden Art, Zahl & Text zu einem String zusammengefaßt. In der Abfrage kann beispielsweise die Zahl oder der Text weggelassen werden, um den Output den persönlichen Bedürfnissen anzupassen. Auswertung, die Zweite - ListendarstellungIm Gegensatz zur ersten Version der Besucherverfolgung hat die Listenausgabe dieser Version ein Such- und Sortierformular dazubekommen. In einem Frameset sind 2 Scripts eingebettet. Das Suchformular selbst möchte ich nicht näher erklären - es ist ein simples Formular, das die eingegebene Werte wieder als Default einträgt. Die Frameseite (d.asp) sieht so aus: <html> <head> <title>Statistik</title> </head> <% Such = Replace(Replace(Request("Such"),"%","*"),"'","''") STyp = Request("STyp") Top = Request("TOP") if top = "" Then TOP ="10" If STyp = "" Then STyp = "IP" ParamStr = "Such=" & Such & "&STyp=" & STyp & "&OrderBy="&Request ("OrderBy")& "&top="& Top%> Hier wird einfach ein Parameterstring zusammengebaut. Dabei wird das Jokerzeichen "*" durch "%" ersetzt - und einfache Hochkommata ersetzt. <frameset cols="*,165" framespacing="0" border="0" frameborder="0"> <frame name="TextOut" marginwidth="0" marginheight="0" scrolling="auto" noresize src="liste.asp?<%=ParamStr%>"> <frame name="Suchform" marginwidth="0" marginheight="0" scrolling="yes" noresize src="suchform.asp?<%=ParamStr%>"> <noframes> <body> <p>Diese Seite verwendet Frames. Frames werden von Ihrem Browser aber nicht unterstützt.</p> </body> </noframes> </frameset> </html> Und jetzt kommt das Interessante - die Listenausgabe (liste.asp): <% Such = Request("Such") STyp = Request("STyp") strSQL = "SELECT top "&Request("top")&" * FROM log_Session WHERE " & Request("STyp") & _ " like '%"&Request("Such")&"%' ORDER BY Start DESC" if request("OderBy") <> "" Then strSQL = Replace(strSQL,"Start DESC",Request("OrderBy")) Set rs = Server.CreateObject("ADODB.Recordset") rs.open strSQL, Application("strConn") %> Der SQL-String wird zusammengebaut und die Datenbank zum Lesen geöffnet. <html> <head> <title>Logfile</title> <%=Application("CSS")%> <base target="_blank"> </head> <body topmargin="0" leftmargin="0" bgcolor="#D5FFD5"> <table border="0" cellpadding="2" cellspacing="10"><tr><td> es folgt eine Tabelle <% Count = 0 while not rs.eof response.write ("<tr><td>" & count & " - <b>" & RS.Fields("ID").Value &"</b></td>") response.write ("<td>" & RS.Fields("Start").Value & "</td>") response.write ("<td>" & RS.Fields("Host").Value & " (" & RS.Fields("IP").Value &")</td>") txtRef = RS.Fields("Referrer").Value If txtRef <> "-" Then response.write ("<td><a href=" & CHR(34) & txtRef & CHR(34) &">" & txtRef & "</a></td></tr>") end If Zuerst werden die Session-Daten ausgegeben response.write ("<tr><td></td><td colspan=""2"">") response.write replace(replace(RS("BrowserTxt"),"Mozilla/4.0 (compatible; ",""),")","") response.write ("</td>") response.write ("<td>" & RS.Fields("StartPage").Value & "</td></tr>") response.write ("<tr><td></td><td colspan=""3""><table>") <% strSQL = "SELECT * FROM log_Action WHERE SID="&RS("ID")&" ORDER BY Start" Set rs1 = Server.CreateObject("ADODB.Recordset") rs1.open strSQL, Application("strSQL") Danach wird Tabelle Nummer zwei geöffnet und alle Datensätze, die die gleiche Session-ID haben, werden ausgegeben: while not rs1.eof response.write("<tr><td>") s = RS1.Fields("Start").Value) p = instr(s," ") response.write mid(s,p+1) response.write ("</td><td>") response.write (RS1.Fields("Art").Value & " - " & RS1.Fields("Txt").Value &" - " & _ RS1.Fields("Zahl").Value & "</td>") d = RS1.Fields("Dauer1").Value response.write ("<td>") if d > 0 then response.write (d & " Sekunden") response.write ("</td>") rs1.movenext response.write("</tr>") wend rs1.close response.write ("</table></td></tr><tr><td colspan=""4"" bgcolor=""#000000"" height=""1""></td></tr>") count = count + 1 rs.movenext wend rs.close set rs=Nothing %> </table> </table> </body> </html> Und das war's auch schon wieder! Notwendige AnpassungenAuf jeden Fall sollte der Pfad der Datenbank geändert werden - die Änderungen sind in allen Scripts incl. der global.asa durchzuführen. Die global.asa muß im Root-Verzeichnis der Webapplikation gespeichert werden. Es ist darauf zu achten, daß eine bestehende Datei dabei nicht überschrieben wird. Gegebenenfalls sind die Inhalte der Prozeduren mit den in der bestehenden global.asa zusammenzuführen. Es empfiehlt sich weiters, die Dateien umzubenennen. Oder zumindest in einen Bereich zu legen, in dem normale Besucherkeine Zugriffsrechte besitzen. In der Datei global.asa wird der Host-Name mittels Komponente abgefragt - hier muß die Syntax auf die verwendete Komponente angepasst werden. Hat man keine, so kann man entweder über www.aspin.com eine herunterladen und installieren - oder man verzichtet auf die Hostauswertung (was auch schneller ist). SchlußbemerkungDie vorgestellten Scripts sind voll lauffähig, es sind nur geringfügige Anpassungen nötig. Auf jeden Fall gilt: Abfragen und die Daten dürfen nicht in falsche Hände geraten. Download des CodesKlicken Sie hier, um den Download zu starten. Verwandte ArtikelWenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |