태터툴즈 레퍼러 분석기 2.

@codemaru · December 18, 2006 · 6 min read

지난번에 올렸던 걸 조금 수정한 것 입니다.
검색되는 사이트가 좀 늘었고, 코드가 조금 깔끔해졌습니다.
무엇에 쓰는 물건인지는 아래 글을 참고하세요.
http://www.jiniya.net/tt/370

만들다보니 이상한게 하나있더군요.
query=%uB178%uD2B8%uBD81%20%uB7A8%201%uAE30%uAC00%20%uAC00%uACA9
위와같은 url입니다. query 부분이 이상하죠. 유니코드는 맞는데 저렇게 쓰는게 표준인지 모르겠네요. 검색해봐도 잘 나오지도 않고, 네이버랑 네이트만 되더군요. 구글같은데 넣으면 %uB... 이런식으로 그대로 나옵니다.
그냥 대응대는 유니코드로 변경하니 되는군요. 아래는 쿼리 스트링의 유니코드를 변경하는 부분입니다.

r = re.compile("%u(....)")  
qstr = r.sub(lambda m: unichr(int(m.group(1), 16)), qstr)  
if type(qstr) == unicode:  
    qstr = qstr.encode("utf8")

소스보기...

#!/usr/local/bin/python  
#-\*- coding: utf8 -\*-  
 
import re  
import MySQLdb  
import urllib  
import cgi  
 
MYSQL\_HOST = "호스트"  
MYSQL\_USERID = "아이디"  
MYSQL\_PASSWD = "패스워드"  
MYSQL\_DB = "디비명"  
MYSQL\_TABLE = "테이블명\_ReferLogs"  
 
EUC\_KR = 0  
UTF8 = 1  
 
PT\_SITE = 0  
PT\_SE = 1  
 
class RefItem(object):  
  def \_\_init\_\_(self, name="", urls=[], type=PT\_SE, count=1):  
       self.name = name  
       self.count = count  
       self.urls = urls  
       self.type = type  
 
  def \_\_cmp\_\_(self, other):  
       if self.name == other.name and self.type == other.type:  
           return 0  
 
       r = self.count - other.count  
       if r == 0:  
           return 1  
       return r  
 
  def AddUrl(self, url):  
       for u in self.urls:  
           if u[1]== url[1]:  
               return  
 
       self.urls.append(url)  
 
  def Add(self, item):  
       self.count = self.count + item.count  
       for url in item.urls:  
           self.AddUrl(url)  
 
class RefItems(object):  
  def \_\_init\_\_(self, items=[]):  
       self.items = items  
 
  def Add(self, item):  
       added = False  
       for it in self.items:  
           if it == item:  
               it.Add(item)  
               added = True  
 
       if not added:  
           self.items.append(item)  
 
 
class Pattern(object):  
  def \_\_init\_\_(self, name="", pattern="", ptype=PT\_SE, utype=EUC\_KR, gno=1):  
       self.pattern = pattern  
       self.utype = utype  
       self.name = name  
       self.gno = gno  
       self.ptype = ptype  
 
  def GetRefItem(self, url):  
       r = re.compile(self.pattern)  
       m = r.search(url)  
       if m:  
           if self.ptype == PT\_SITE:  
               return RefItem(self.name, [(url, m.group(self.gno))], self.ptype)  
 
           q = urllib.unquote(urllib.unquote\_plus(m.group(self.gno)))  
           if self.utype == EUC\_KR:  
               try:  
                   qstr = unicode(q, "euc\_kr").encode("utf8")  
               except UnicodeDecodeError:  
                   qstr = q  
           else:  
               qstr = q  
 
          r = re.compile("%u(....)")  
          qstr = r.sub(lambda m: unichr(int(m.group(1), 16)), qstr)  
          if type(qstr) == unicode:  
               qstr = qstr.encode("utf8")  
 
 
           return RefItem(qstr, [(url, self.name)], self.ptype)  
 
def GetRefItem(url):  
  patterns = [ Pattern("구글", ".\*\.google\..\*/search?.\*=(EUC-KR|euc-kr).\*q=([^&]\*)", PT\_SE, EUC\_KR, 2)  
           , Pattern("구글", ".\*\.google\..\*/search?.\*q=([^&]\*)", PT\_SE, UTF8)  
           , Pattern("구글", ".\*\.google\..\*/custom?.\*q=([^&]\*)", PT\_SE, EUC\_KR)   
           , Pattern("네이트", ".\*searchplus\.nate\.com/searchplus/search\.plus?.\*query=([^&]\*)")  
           , Pattern("다음",".\*search\.daum\.net/cgi-bin/nsp/search\.cgi?.\*q=([^&]\*)")  
           , Pattern("엠에쎈", ".\*search\.msn\.co\.kr/(sp|)results\.aspx?.\*q=([^&]\*)", PT\_SE, EUC\_KR, 2)  
           , Pattern("야후", ".\*search.yahoo.com/search?(.\*&|)p=([^&]\*)", PT\_SE, EUC\_KR, 2)  
           , Pattern("파란", "http://search.paran.com/search/index.php?.\*KeyWord=([^&]\*)")  
           , Pattern("파란", "^http://.\*paran.com/.\*nlia=([^&]\*)")  
           , Pattern("네이버", "http://search.naver.com/search.naver?.\*query=([^&]\*)")  
           , Pattern("라이브닷컴", "http://search.live.com/results.aspx?.\*q=([^&]\*)")  
           , Pattern("올블로그", "http://www.allblog.net/GoPage/.\*\.html?.\*orignalUrl=([^&]\*)", PT\_SITE, 1)  
           , Pattern("이올린", "^http://.\*(\eolin\.com)/.\*", PT\_SITE)  
           , Pattern("구글이미지", ".\*images\.google\..\*/imgres?.\*imgurl=([^&]\*)", PT\_SITE)  
           , Pattern("넷피아", "^http://.\*netpia\.com/.\*nlia=([^&]\*)", PT\_SE, EUC\_KR)  
           , Pattern("블로그라인스", "^http://.\*(bloglines.com)", PT\_SITE)  
           , Pattern("데브피아", "^http://.\*devpia\.com/[Ff]orum/BoardView\.aspx?.\*forumname=([^&]\*)", PT\_SITE)  
           , Pattern("기타", "^http://([^/]\*)", PT\_SITE)]  
 
  for pat in patterns:  
       ri = pat.GetRefItem(url)  
       if ri:  
           return ri  
 
  return  
 
 
def GetRefererLogs():  
  db = MySQLdb.connect(MYSQL\_HOST, MYSQL\_USERID, MYSQL\_PASSWD, MYSQL\_DB)  
  cursor = db.cursor()  
  cursor.execute("select \* from %s" % (MYSQL\_TABLE))  
  result = cursor.fetchall()  
 
  urls = []  
  for r in result:  
       urls.append(r[2])  
 
  return urls  
 
def Main():  
  urls = GetRefererLogs()  
 
  refs = RefItems()  
  for url in urls:  
       ref = GetRefItem(url)  
       if ref:  
           refs.Add(ref)  
 
  tableHtmlSE = "<table width=100% border=0 cellpadding=0 cellspacing=0 style='font-size:9pt;'>"  
  tableHtmlSite = "<table width=100% border=0 cellpadding=0 cellspacing=0 style='font-size:9pt;'>"  
  for ref in refs.items:  
       buf = ""  
       for url in ref.urls:  
           buf += """<a href="%s">%s</a><br/> """ % (url[0], url[1])  
 
       if ref.type == PT\_SE:  

         tableHtmlSE += "<tr><td
width=200>%s</td><td>%d</td><td>%s</td></tr>"
% (ref.name, ref.count, buf)  
       else:  
          
tableHtmlSite +=
"<tr><td>%s</td><td>%d</td><td>%s</td></tr>"
% (ref.name, ref.count, buf)  
 
  tableHtmlSE += "</table>"  
  tableHtmlSite += "</table>"  
  print "Content-type: text/html\n"  
  print """<html><head>  
       <meta htt-equiv="Content-type" content="text/html; charset=utf-8" />  
       </head><body>%s<br/><br/>\n\n%s</body></html>""" % (tableHtmlSite, tableHtmlSE)  
 
Main()

그리고 태터툴즈 레퍼러 로그를 좀 더 장기간 수집하고 싶으신 분들은 태터 소스의 blog/index.php 파일을 수정하시면됩니다. 해당 파일에서 아래 문자열을 찾아서 604800을 더 큰 숫자로 변경하면 됩니다. 숫자는 초단위입니다. 따라서 기본값 604800은 7일 동안 로그를 보관한다는 이야기죠.

mysql_query("delete from {$database['prefix']}RefererLogs where referred < UNIX_TIMESTAMP() - 604800");

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중