python ide 选择_Python - 网站访问日志分析作业

需求

Python3.6.8

站长之家的正则在线测试

基本需求

统计日志文件的总pv、uv

列出全天每小时的pv、uv

列出top10 uv的IP地址,以及每个IP的pv点击数

列出top10访问量最多的页面及每个页面的访问量

列出访问来源设备列表及每个设备的访问量

说明

pv:page visit,页面访问量,一次请求就是一次pv

uv:uservisit,独立用户,一个IP就算一个独立的用户

注意:没有IP的日志在这里认为是异常日志,不在统计范围之内。

需求分析

首先要了解日志的意思:

# 正常日志

27.10.109.31 - - [15/Apr/2019:00:45:23 +0800] "GET /api/v1/enroll/degrees/ HTTP/1.1" 200 270 "https://www.luffycity.com/study/degree" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15"

# 访问IP:27.10.109.31

# 访问时间:15/Apr/2019:00:45:23 +0800

# 访问的URL:/api/v1/enroll/degrees/

# 访问设备:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15

# 异常日志

ee/2/ HTTP/1.1" 200 1055 "https://www.luffycity.com/study/degree" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36"

- - - [15/Apr/2019:00:32:54 +0800] "\x16\x03\x01\x00\x9A\x01\x00\x00\x96\x03\x03g\xAE%\xCF\xCA\xC8v\x191\x90\xAA\xAD9\xBC\xFE\x9AJ]\xFC\xB8\xB4\x83\xF6\xF7\xB3+\xA3

- - - [15/Apr/2019:01:05:45 +0800] "HEAD / HTTP/1.1" 499 0 "-" "-"

首先要把异常日志排除掉。

然后再针对性实现每个需求。

统计日志文件的总pv、uv

-- 循环每条正常的日志,使用正则查找当前行的 ip

- pv = 每一个可以重复的 ip 的和

- uv = 每一个不可重复的 ip 的和

列出全天每小时的pv、uv

-- 循环每条正常的日志,使用正则查找当前行的 ip

-- 以小时为分割,然后统计每个小时的pv和uv

- pv = 每一个可以重复的 ip 的和

- uv = 每一个不可重复的 ip 的和

-- 难点:

- 从日志中读取的日期时间,如何处理为可用的时间格式(格式化后的字符串/时间戳)

- 如何组织数据结

列出top10 uv的IP地址,以及每个IP的pv点击数

-- 循环每条正常的日志,使用正则查找当前行的 ip

- 循环读取所有ip,取出每一个ip

- 统计每个不重复的ip,以及统计该ip重复出现的次数

- 最后进行降序排序,然后取最高的top1

列出top10访问量最多的页面及每个页面的访问量

-- 循环每条正常的日志,使用正则查找当前行的 page

- 循环读取所有page,取出每一个page

- 统计每个不重复的page,以及统计该page重复出现的次数

- 最后进行降序排序,然后取最高的top10 的page

列出访问来源设备列表及每个设备的访问量

-- 循环每条正常的日志,使用正则查找当前行的设备

- 统计每个不重复的设备,以及统计该设备重复出现的次数

- 虽然需求是列出所有的设备,但我的代码中只展示了前20条数据

-- 注意,设备有多种:

- Mozilla

- Mozilla/5.0 Mozilla/4.0 Mozilla/3.0

- Python-urllib/2.7

- Go-http-client/1.1

- - # 是的,只有一个 - ,我认为是未知的设备,我代码中没有处理

- curl/7.19.7

- Sogou web

- Xiaomi_MCT1_TD-LTE/V1

示例代码:

import datetime

import re

from prettytable import PrettyTable

LOG_INFO = './网站访问日志.log'

# ----- 正则规则 -----

MATCH_STARTSWITH = MATCH_IP = re.compile(

"(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)")

MATCH_DATETIME = re.compile(

"(?P((25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d))).*?\[(?P.*?)\s\+0800\]")

MATCH_EQUIPMENT = re.compile("\"\s\"(?P.*?)\"")

MATCH_PAGE = re.compile("\"[A-Z]{3,}\s(?P.*?)\sHTTP/1.1")

FILE_LIST = []

def init():

""" 过滤复合条件的日志,存储在列表中 """

with open(LOG_INFO, 'r', encoding='UTF-8') as f:

for line in f:

res = MATCH_STARTSWITH.match(line)

if res:

FILE_LIST.append(line)

def total_pv_uv():

""" 统计本日志文件的总pv、uv """

tmp_dict = {"pv": [], "uv": set(), }

print('waiting.....')

for i in FILE_LIST:

res = MATCH_IP.search(i)

if res:

res = res.group()

tmp_dict['pv'].append(res)

tmp_dict['uv'].add(res)

table = PrettyTable(['总PV', '总UV'])

table.add_row([len(tmp_dict['pv']), len(tmp_dict['uv'])])

print(table)

def total_24hour_pv_uv():

""" 列出全天每小时的pv、uv数 """

tmp_dict = {}

print("waiting.....")

for i in FILE_LIST:

res = MATCH_DATETIME.search(i)

if res:

ip, dt = res.group("ip"), res.group("dt")

date_time_str = datetime.datetime.strptime(dt, '%d/%b/%Y:%H:%M:%S')

date_time_day = date_time_str.strftime("%Y-%m-%d")

date_time_hour = date_time_str.strftime("%Y-%m-%d %H")

if not tmp_dict.get(date_time_day, False):

tmp_dict[date_time_day] = {}

# 创建当天的24小时

for hour in range(0, 24):

# 必须用zfill在个位数之前填充0,不然生成的 key 是这样的 2019-04-14 1,和 date_time_hour生成的key 2019-04-14 01 不一致,会出问题

tmp_key = "{} ".format(date_time_day) + "{}".format(hour).zfill(2)

if tmp_key not in tmp_dict[date_time_day]:

tmp_dict[date_time_day][tmp_key] = {"pv": [], "uv": set()}

tmp_dict[date_time_day][date_time_hour]['uv'].add(ip)

tmp_dict[date_time_day][date_time_hour]['pv'].append(ip)

# print(tmp_dict)

for k in tmp_dict:

print('[{}]日的每小时的pv和uv数统计如下: '.format(k))

table = PrettyTable(["时间", '每个小时的pv数', '每个小时的uv数'])

for j, v in tmp_dict[k].items():

table.add_row([j, len(v['pv']), len(v['uv'])])

print(table)

def total_top10_uv():

""" 列出top 10 uv的IP地址,以及每个ip的pv点击数 """

tmp_dict = {}

print("waiting.....")

for i in FILE_LIST:

res = MATCH_IP.search(i)

if res:

res = res.group()

if res in tmp_dict:

tmp_dict[res] += 1

else:

tmp_dict[res] = 1

table = PrettyTable(['top10 uv的IP', 'top10 uv的ip的pv'])

table.align['top10 uv的IP'] = 'l'

tmp_list = sorted(tmp_dict.items(), key=lambda x: x[1], reverse=True)[

0:10] # tmp_dict.items() --> ("113.89.97.191", 13)

for n1, n2 in tmp_list:

table.add_row([n1, n2])

print(table)

def total_top10_page():

""" 列出top 10 访问量最多的页面及每个页面的访问量 """

print("waiting.....")

tmp_dict = {}

for i in FILE_LIST:

res = MATCH_PAGE.search(i)

if res:

page = res.group("page")

if page in tmp_dict:

tmp_dict[page].append(page)

else:

tmp_dict[page] = [page]

table = PrettyTable(['访问量是top10的页面URL', '访问量'])

table.align['访问量是top10的页面URL'] = 'l'

tmp_list = sorted(tmp_dict.items(), key=lambda x: len(x[1]), reverse=True)[0:10]

for n1, n2 in tmp_list:

table.add_row([n1, len(n2)])

print(table)

def total_equipment_list():

""" 列出访问来源的设备列表及每个设备的访问量 """

print("waiting.....")

tmp_dict = {}

for i in FILE_LIST:

res = MATCH_EQUIPMENT.search(i)

if res:

equipment = res.group("equipment")

if equipment in tmp_dict:

tmp_dict[equipment].append(equipment)

else:

tmp_dict[equipment] = [equipment]

table = PrettyTable(['设备来源', '访问量'])

table.align['设备来源'] = 'l'

# 这里仅展示前20条,你可以取消分片,展示所有

# tmp_list = sorted(tmp_dict.items(), key=lambda x: len(x[1]), reverse=True)

tmp_list = sorted(tmp_dict.items(), key=lambda x: len(x[1]), reverse=True)[0:20]

for n1, n2 in tmp_list:

table.add_row([n1, len(n2)])

print(table)

def q():

""" 退出 """

exit('再来呦')

def handler():

tmp_dict = {

"1": ["统计本日志文件的总pv、uv", total_pv_uv],

"2": ["列出全天每小时的pv、uv数", total_24hour_pv_uv],

"3": ["列出top 10 uv的IP地址,以及每个ip的pv点击数", total_top10_uv],

"4": ["列出top 10 访问量最多的页面及每个页面的访问量", total_top10_page],

"5": ["列出访问来源的设备列表及每个设备的访问量", total_equipment_list],

"6": ["退出", q]

}

while True:

print('欢迎使用网站访问数据分析系统'.center(40, '*'))

for k, v in tmp_dict.items():

print(k, v[0])

cmd = input("输入序号选择对应的操作: ").strip()

if cmd in tmp_dict:

tmp_dict[cmd][-1]()

else:

print('输入不合法')

if __name__ == "__main__":

init()

handler()

演示结果,注意,由于原日志文件的内容差异、代码逻辑不通、正则规则不同,大家的结果可能存在误差。

*************欢迎使用网站访问数据分析系统*************

1 统计本日志文件的总pv、uv

2 列出全天每小时的pv、uv数

3 列出top 10 uv的IP地址,以及每个ip的pv点击数

4 列出top 10 访问量最多的页面及每个页面的访问量

5 列出访问来源的设备列表及每个设备的访问量

6 退出

输入序号选择对应的操作: 1

waiting.....

+-------+------+

| 总PV | 总UV |

+-------+------+

| 31288 | 1683 |

+-------+------+

*************欢迎使用网站访问数据分析系统*************

1 统计本日志文件的总pv、uv

2 列出全天每小时的pv、uv数

3 列出top 10 uv的IP地址,以及每个ip的pv点击数

4 列出top 10 访问量最多的页面及每个页面的访问量

5 列出访问来源的设备列表及每个设备的访问量

6 退出

输入序号选择对应的操作: 2

waiting.....

[2019-04-15]日的每小时的pv和uv数统计如下:

+---------------+----------------+----------------+

| 时间 | 每个小时的pv数 | 每个小时的uv数 |

+---------------+----------------+----------------+

| 2019-04-15 00 | 397 | 49 |

| 2019-04-15 01 | 102 | 23 |

| 2019-04-15 02 | 38 | 10 |

| 2019-04-15 03 | 48 | 16 |

| 2019-04-15 04 | 37 | 15 |

| 2019-04-15 05 | 17 | 10 |

| 2019-04-15 06 | 180 | 14 |

| 2019-04-15 07 | 305 | 39 |

| 2019-04-15 08 | 978 | 109 |

| 2019-04-15 09 | 2329 | 170 |

| 2019-04-15 10 | 2317 | 202 |

| 2019-04-15 11 | 2111 | 163 |

| 2019-04-15 12 | 1148 | 122 |

| 2019-04-15 13 | 1585 | 185 |

| 2019-04-15 14 | 2376 | 259 |

| 2019-04-15 15 | 2555 | 215 |

| 2019-04-15 16 | 2047 | 210 |

| 2019-04-15 17 | 2394 | 212 |

| 2019-04-15 18 | 1493 | 138 |

| 2019-04-15 19 | 1593 | 165 |

| 2019-04-15 20 | 2016 | 191 |

| 2019-04-15 21 | 2141 | 205 |

| 2019-04-15 22 | 1888 | 201 |

| 2019-04-15 23 | 1193 | 141 |

+---------------+----------------+----------------+

*************欢迎使用网站访问数据分析系统*************

1 统计本日志文件的总pv、uv

2 列出全天每小时的pv、uv数

3 列出top 10 uv的IP地址,以及每个ip的pv点击数

4 列出top 10 访问量最多的页面及每个页面的访问量

5 列出访问来源的设备列表及每个设备的访问量

6 退出

输入序号选择对应的操作: 3

waiting.....

+-----------------+------------------+

| top10 uv的IP | top10 uv的ip的pv |

+-----------------+------------------+

| 221.218.214.8 | 4018 |

| 122.71.67.110 | 855 |

| 118.113.14.162 | 357 |

| 47.95.112.89 | 299 |

| 113.246.241.131 | 244 |

| 117.25.109.180 | 219 |

| 106.44.6.54 | 209 |

| 116.18.244.11 | 203 |

| 58.45.45.183 | 198 |

| 60.247.104.68 | 195 |

+-----------------+------------------+

*************欢迎使用网站访问数据分析系统*************

1 统计本日志文件的总pv、uv

2 列出全天每小时的pv、uv数

3 列出top 10 uv的IP地址,以及每个ip的pv点击数

4 列出top 10 访问量最多的页面及每个页面的访问量

5 列出访问来源的设备列表及每个设备的访问量

6 退出

输入序号选择对应的操作: 4

waiting.....

+-------------------------------------------+--------+

| 访问量是top10的页面URL | 访问量 |

+-------------------------------------------+--------+

| /api/v1/enroll/degrees/ | 2047 |

| /api/v1/banners/ | 1088 |

| /api/v1/course_sub/category/list/ | 1050 |

| /api/v1/courses/?sub_category=0&ordering= | 1028 |

| /api/v1/enroll/info/?degree_id=1 | 651 |

| /api/v1/learndata/?degree_id=1 | 622 |

| /api/v1/account/login/ | 579 |

| /api/v1/enroll/degree/1/ | 511 |

| /api/v1/captcha_check/ | 436 |

| /mentor/ | 279 |

+-------------------------------------------+--------+

*************欢迎使用网站访问数据分析系统*************

1 统计本日志文件的总pv、uv

2 列出全天每小时的pv、uv数

3 列出top 10 uv的IP地址,以及每个ip的pv点击数

4 列出top 10 访问量最多的页面及每个页面的访问量

5 列出访问来源的设备列表及每个设备的访问量

6 退出

输入序号选择对应的操作: 5

waiting.....

+-----------------------------------------------------------------------------------------------------------------------------------------+--------+

| 设备来源 | 访问量 |

+-----------------------------------------------------------------------------------------------------------------------------------------+--------+

| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 | 2934 |

| Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0 | 1268 |

| Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 | 1085 |

| Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 | 1048 |

| Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 | 1008 |

| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36 | 974 |

| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 | 930 |

| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36 | 894 |

| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134 | 735 |

| Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 | 677 |

| Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0 | 434 |

| Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 | 425 |

| Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 | 414 |

| Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 | 406 |

| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763 | 381 |

| Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 | 336 |

| Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 | 331 |

| Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 | 328 |

| Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 | 327 |

| Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1 | 326 |

+-----------------------------------------------------------------------------------------------------------------------------------------+--------+

*************欢迎使用网站访问数据分析系统*************

1 统计本日志文件的总pv、uv

2 列出全天每小时的pv、uv数

3 列出top 10 uv的IP地址,以及每个ip的pv点击数

4 列出top 10 访问量最多的页面及每个页面的访问量

5 列出访问来源的设备列表及每个设备的访问量

6 退出

输入序号选择对应的操作: 6

再来呦

that's all

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

Ashley K

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值