Python3分析Web访问日志

1.日志格式

tail -1 access_log
172.20.0.10 - - [11/Sep/2019:11:44:41 +0800] "POST /zabbix.php?sid=86618997b1ae279a&action=widget.svggraph.view HTTP/1.1" 200 4257 "http://172.20.0.149/zabbix.php?action=dashboard.view&ddreset=1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0"

根绝格式看出

1. 远程ip 2.- - 3.请求时间 4.时区 5.请求方法 6.访问资源 7.协议 8.状态码 9.发送字节

分析
• 按天统计
o 每天日志行数
o 每天浏览每个 IP 的访问次数
o 每天访问者数量 = 每天出现 IP 组成集合的数量
o 每天状态码出现次数
o 每天流量总数
• 总统计
o 总日志行数 = 每天日志行数之和
o 总访问者数量 = 所有出现 IP 组成的集合数量
• 地域分布
o 所有出现 IP 的访问次数 排序取 TOP20
o 根据 IP 查找地理位置

效果图

Python3分析Web访问日志_第1张图片

上代码

Python版本

# python -V
Python 2.7.5
#!/usr/bin/python
# _*_ coding: utf-8 _*_

#统计每天信息

from datetime import datetime
stat_days = {}

#统计每天数据
fhandler = open('access_log', 'rt')
for line in fhandler:
    try:
        _nodes = line.split()
        # 跳过可能错误的数据行,小于8个字段就认为是错误,跳转到下一行数据
        if len(_nodes) < 8:
            continue
        # ip   datetime  method   url  status   bytes
        #print(_nodes[0], _nodes[3][1:], _nodes[5][:1], _nodes[6], _nodes[8], _nodes[9])
        _day = datetime.strptime(_nodes[3][1:], '%d/%b/%Y:%H:%M:%S').strftime('%Y-%m-%d')
        # 设置每天的默认值
        stat_days.setdefault(_day, {'hits' : 0, 'visitors' : {}, 'status' : {}, 'bytes' : 0})
        # 设置每天出现的IP的访问次数默认为0
        stat_days[_day]['visitors'].setdefault(_nodes[0], 0)
        # 设置每天出现的状态码默认值为0
        stat_days[_day]['status'].setdefault(_nodes[8], 0)
        # 统计数
        stat_days[_day]['hits'] += 1
        stat_days[_day]['visitors'][_nodes[0]] += 1
        stat_days[_day]['status'][_nodes[8]] += 1
        stat_days[_day]['bytes'] += int(_nodes[9]) if _nodes[9].isdigit() else 0
    except BaseException as e:
        print('log error: %s' % line)
fhandler.close()

#统计总数据
stat_all = {'hits' : 0, 'visitors' : {}, 'status' : {}, 'bytes' : 0, 'city' : {}}
for _day,_stat in stat_days.items():
    stat_all['hits'] += _stat['hits']
    stat_all['bytes'] += _stat['bytes']
    for _ip, _cnt in _stat['visitors'].items():
        stat_all['visitors'].setdefault(_ip, 0)
        stat_all['visitors'][_ip] += _cnt
    
    for _status, _cnt in _stat['status'].items():
        stat_all['status'].setdefault(_status, 0)
        stat_all['status'][_status] += _cnt
# 统计区域数据(需安装geoip2,使用命令 pip install geoip2)
# 数据库下载
# wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz 
from geoip2.database import Reader

geoip2_reader = Reader('GeoLite2-City.mmdb')
for _ip, _cnt in stat_all['visitors'].items():
    _city_name = 'unknow'
    try:
        _city = geoip2_reader.city(_ip)
        _city_name = '{}/{}'.format(_city.country.names.get('en', ''), _city.city.names.get('en', ''))
    except BaseException as e:
       print(e)
       pass
    stat_all['city'].setdefault(_city_name, 0)
    stat_all['city'][_city_name] += _cnt
geoip2_reader.close

# 打印结果
# ('^'表示居中, '>'表示右对齐, '<'表示左对齐)
print("\033[1;32;40m")
print('=' * 70)
print('|1.概览{:>61}|'.format(''))
print('-' * 70)
print('| 总点击量 | {hits: ^8d} | 总访问量 | {visitors: ^10d} | 总流量 | {fbytes: ^15d} | '.format(hits=stat_all['hits'], visitors=len(stat_all['visitors']), fbytes=stat_all['bytes']))
print('=' * 70)
print('|2. 状态码分布{:>55} | '.format(''))
print('-' * 70)
for _status, _cnt, in sorted(stat_all['status'].items(), key=lambda x: x[1], reverse=True):
    print('|{status:>20s} | {count:^47d} |'.format(status=_status, count=_cnt))
print('=' * 70)
print('|3. 每天的点击量{:>53} |'.format(''))
print('-' * 70)
for _day, _stat in sorted(stat_days.items(), key=lambda x: x[0], reverse=True):
    print('|{day:>15} | {hits: ^52d} | '.format(day=_day, hits=stat_all['hits']))
print('=' * 70)
print('|4. 每天的访问量{:>51} |'.format(''))
print('-' * 70)
for _day, _stat in sorted(stat_days.items(), key=lambda x: x[0], reverse=True):
    print('|{day:>15} | {visitors: ^25d} | '.format(day=_day, visitors=len(_stat['visitors'])))
print('=' * 70)
print('|5. 每天的流量{:>55} |'.format(''))
print('-' * 70)
for _day, _stat in sorted(stat_days.items(), key=lambda x: x[0], reverse=True):
    print('|{day:>15} | {fbytes: ^52d} | '.format(day=_day, fbytes=_stat['bytes']))
print('=' * 70)
print('|6. 访问者来源{:57} |'.format(''))
print('-' * 70)
for _city, _cnt in sorted(stat_all['city'].items(), key=lambda x: x[1], reverse=True)[:21]:
    print('|{city:>47} | {count: ^20d} | '.format(city=_city, count= _cnt))
print('=' * 70)
print("\033[0m")

参考地址:https://blog.51cto.com/2290153/2124517

你可能感兴趣的:(python)