Spark 分析Apache日志

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/taoyanqi8932/article/details/53385066

声明:没博客内容由本人经过实验楼整理而来

内容描述

在给定的日志文件是一个标准的Apache2 程序产生的access.log文件,根据业务需求,我们需要分析得到下面几方面的数据:

  1. 统计每日PV和独立IP
  2. 统计每种不同的HTTP状态对应的访问数
  3. 统计不同独立IP的访问量
  4. 统计不同页面的访问量

Apache日志格式

首先下载apache日志文件
wget http://labfile.oss.aliyuncs.com/courses/456/access.log

首先打开pyspark

// 读入数据
>>> logRDD=sc.textFile("access.log")

这里是一条 Apache日志

180.76.15.161 - - [06/Dec/2014:06:49:26 +0800] "GET / HTTP/1.1" 200 10604 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"

Apache日志内容从左到右依次是:

  1. 远程IP地址
  2. 客户端记录
  3. 浏览者记录
  4. 请求的时间,包括三项内容:

    • 日期
    • 时间
    • 时区
  5. 服务器收到的请求,包括三项内容:

    • METHOD:请求的方法,GET/POST等
    • RESOURCE:请求的目标链接地址
    • PROTOCOL:HTTP版本
  6. 状态代码,表示请求是否成功
  7. 发送的字节数
  8. 发出请求时所在的URL
  9. 客户端的详细信息:操作系统及浏览器等

这里我们提取的信息为:
1. 客户端的IP
2. 请求日期
3. 请求的URL
4. HTTP状态码(如200)

我们使用正则表达式来提取所要的信息。

pattern=r'^(\S+) (\S+) (\S+) \[([\w/]+)([\w:/]+)\s([+\-]\d{4})\] \"(\S+) (\S+) (\S+)\" (\d{3}) (\d+)'

关于正则表达式请参考:Python正则表达式
为了避免一些杂乱的无法解析的数据干扰,我们使用正则表达式做两件事情,一个是过滤掉无法解析的日志,一个是解析获得需要的数据元组

实现两个函数:

  1. filterWithParse:过滤无法解析的日志记录
  2. parseLog:解析日志记录,得到所需信息的元组
import re
pattern=r'^(\S+) (\S+) (\S+) \[([\w/]+)([\w:/]+)\s([+\-]\d{4})\] \"(\S+) (\S+) (\S+)\" (\d{3}) (\d+)'

def filterWithParse(s):
    m = re.match(pattern, s)
    if m:
        return True
    return False

def parseLog(s):
    m = re.match(pattern, s)
    clientIP = m.group(1)
    requestDate = m.group(4)
    requestURL = m.group(8)
    status = m.group(10)
    return (clientIP, requestDate, requestURL, status)

将上述代码复制到pyspark交互模式中。

解析文件

执行第一次map操作,获得解析后的(客户端IP,请求日期,请求URL和HTTP状态码)信息:

>>> logRDDv1 = logRDD.filter(filterWithParse).map(parseLog)

统计每日的PV

所谓的PV(page view),即每一天的页面访问量
首先查看一下总共有多少的访问量,这里用count()函数去统计。这些访问量包含了很多天的总和,因此我们需要对其进行处理。

// 统计总的访问量
>>> logRDDv1.count()
5122
>>>from operator import add
>>>logRDDv2 = logRDDv1.map(lambda x: (x[1], 1)).reduceByKey(add)
// 保存
>>>logRDDv2.sortByKey().saveAsTextFile('/tmp/DPV')

首先进行map操作,生成一个元组(日期,个数),这里要注意,x[1]代表的是日期,然后进行reduce操作对相同的key值进行相加。

打开/tmp/DPV中的文件可以看到,其进行了统计。

  1 (u'06/Dec/2014', 340)
  2 (u'07/Dec/2014', 778)
  3 (u'08/Dec/2014', 910)
  4 (u'09/Dec/2014', 1282)
  5 (u'10/Dec/2014', 526)

统计每日的独立IP

注意与PV的不同,PV中一个IP可能在同一天访问了多出此页面,而IP一天只记录此IP访问1次。这点很重要。

首先进行一次map操作,生成(日期,IP)的元组,对logRDDv3中的元素进行去重操作(使用distinct()函数),logRDDv4中每个元组都不相同,表示每天的一个独立IP访问:

>>> logRDDv3 = logRDDv1.map(lambda x: (x[1], x[0]))
>>> logRDDv4 = logRDDv3.distinct()

执行reduce操作,将日期相同的记录条数相加获得最终的每日独立IP数:

// 这里的x[0]是日期
>>> logRDDv5 = logRDDv4.map(lambda x: (x[0], 1)).reduceByKey(add)

// 这里进行交换是的显示,没有保存
>>> DIP = logRDDv5.collect()
>>> DIP
[(u'06/Dec/2014', 124), (u'13/Dec/2014', 46), (u'11/Dec/2014', 177), (u'08/Dec/2014', 174), (u'12/Dec/2014', 170), (u'07/Dec/2014', 166), (u'10/Dec/2014', 155), (u'09/Dec/2014', 148)]

可以看到每日独立的IP少于PV,这是因为同一个IP可能在一天内访问多次。

统计每种不同的HTTP状态对应的访问数

比较简单,直接给出代码。

>>> logRDDv6=logRDDv1.map(lambda x:(x[3],1)).reduceByKey(add)
>>> status=logRDDv6.sortByKey().collect()
>>> status
[(u'200', 3533), (u'206', 3), (u'301', 331), (u'304', 104), (u'400', 8), (u'403', 3), (u'404', 1134), (u'405', 6)]

统计不同页面的访问量

将其组成元组(requestIP,1)然后进行统计。注意进行排序是对第二个元素进行降序的排列。

logRDDv8 = logRDDv1.map(lambda x: (x[2], 1)).reduceByKey(add)
PagePV = logRDDv8.sortBy(lambda x: x[1], ascending=False).collect()

通过查看PagePV我们发现有大量的js文件的访问,这不是我们需要的内容,因此我们增加一个去除列表,凡是访问文件的后缀名属于列表则不过滤掉,重新实现上述算法:

stopList = ['jpg', 'ico', 'png', 'gif', 'css', 'txt', 'asp']

def filterWithStop(s):
    for c in stopList:
        if s.endswith('.'+c):
            return False
    return True
// 如果为False 不进行过滤,为True进行过滤
logRDDv9 = logRDDv1.filter(lambda x: filterWithStop(x[2]))

没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试

关闭