作者:小啊小二饼(iconfont)

🌑

Spaghetti.ink

Appreciation, Modesty, Persistence


【毕设专题-1】数据加载

poster

前言

本科毕设选题为“基于Web日志的网站优化技术研究”,本次毕设的核心任务为:对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'])

结果

result

由于数据量过大,同学们可以通过分chunk加载来提高效率

本文由 Frank采用 署名 4.0 国际 (CC BY 4.0)许可

, — 2021年3月24日

本文总阅读量

数据分析

本站总访问量