Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Besucherverfolgung für Fortgeschrittene

Geschrieben von: Stefan Mayer
Kategorie: ASP Tricks

This printed page brought to you by AlphaSierraPapa

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" Version

In 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 Datenbank

Die 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_Session

Diese 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_Action

Diese 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.asa

Die 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.asp

Makelog.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-Datei

In 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 10

Mit 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 - Listendarstellung

Im 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 Anpassungen

Auf 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ßbemerkung

Die 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.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20020121.zip

Verwandte Artikel

Benutzerverfolgung in ASP
http:/www.aspheute.com/artikel/20001206.htm

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.