本科毕设选题为“基于Web日志的网站优化技术研究”,本次毕设的核心任务为:对Web日志进行数据挖掘,寻找出网站的频繁模式(用户频繁访问路径),并根据频繁模式优化原有网站结构,使得用户的平均访问代价减少。
该系列文章将详细记录我毕设各个工作阶段,希望能给以后研究相关方向的人一些参考同时也激励自己学习、创作。
本次研究采用的数据集为Charles University SIS Access Log Dataset
该数据集合采用ZPAQ压缩,有需要的同学安装ZPAQ CLI进行解压即可,文件数据量非常大,如有需要请中止解压过程
数据分析主要采用Python
及其数据分析库Pandas
实现。为方便调试,请使用jupyter
一般的我们通过pandas
库中的read_xxx
函数来读取我们的文件即可,我们的文件扩展名为txt
,这里通过read_table
来读取Web日志。
import os;
'''
os.path.join: 拼接路径
注意如果所有的参数中存在绝对路径的话,那么之前的参数将会被抛弃
e.g.
os.path.join('a', '/', 'b') === '/b'
os.path.join('/', 'a', 'b') === '/a/b'
'''
# os.sep: 获取当前OS的文件分隔符
# os.path.exists: 确认目标文件是否存在
# 获取文件地址
currentDirectory = os.getcwd()
logPath = os.path.join(currentDirectory, 'log', 'sis-log-201805-anonymous.txt')
# 确认文件是否存在
os.path.exists(logPath)
# 读取数据
pd.read_table(logPath, header=None, iterator=True);
读取大文件:分chunk读取
chunkSize = 100000; file_read = pd.read_table(logPath, header=None, iterator=True); chunks = file_read.get_chunk(chunkSize);
当前服务器普遍使用的日志有:Common log format
以及Combined log format
。我们使用的Web日志为Combined log format
,具体格式如下
<IP address> - <user ID> <[timestamp]> "METHOD <path> <protocol>" <status code> <response size> "<referrer>" "<user agent>"
首先让我们看看日志的每条记录都长什么样
244.74.123.51 - - [23/May/2018:04:32:03 +0200] "GET /studium/term_st2/index.php?id=c14c1c27f8e0c1776fd8e40e83c4d836&tid=&do=xzapsat&ztid=543318&povinn=D8384858&typ=K&sem=2&rl=-3&ret=ZG14emFwc0F8JnR4cD3tbnAmcG40X8Z4YnJhbnk4JnBvdl4uZXNwbG4lbmVbXT3EMDEwNTM8MCZ8ZXJtdWNpdD8mZmFrdWx8YT8xMTEzMCZ3c8Rhdj8xMy8zMjMmcG40aW4uX03vZGU4dGV5dCZwb8Zpbm54RDAxMDUwMzgmdWNpdD8mYnVkb8VjaT8xJnZvbG4lPTAmcG4jZXQ4NTAmYnRuX0hsZWRhdD3IbGVkYXQ= HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36"
import re;
reg = re.compile(r'(?P<IP>.*) - - \[(?P<Time>.*)\] \"(?P<Method>\w*) (?P<Url>.*) HTTP.*\" (?P<Status>\d{3}) (?P<Size>\d+) \"(?P<Reference>.*)\" \"(?P<Proxy>.*)\"')
def getSpecificField():
def getValue(data):
return reg.search(data).groupdict()
return getValue
chunks[0] = chunks[0].map(getSpecificField())
chunks[0][0:10000].apply(pd.Series, index=['IP', 'Time', 'Method', 'Url', 'Status', 'Size', 'Reference', 'Proxy'])
由于数据量过大,同学们可以通过分chunk加载来提高效率
本文由 Frank采用 署名 4.0 国际 (CC BY 4.0)许可
Made with ❤ and at Hangzhou.