#IT明星不是梦#利用Python进行网站日志分析

网站的访问日志是一个非常重要的文件,通过分析访问日志,能够挖掘出很多有价值的信息。本文介绍如何利用Python对一个真实网站的访问日志进行分析,文中将综合运用Python文件操作、字符串处理、列表、集合、字典等相关知识点。本文所用的访问日志access_log来自我个人的云服务器,大家可以从文末的附件中下载。

1.提取指定日期的日志

下面是一条典型的网站访问日志,客户端访问网站中的每个资源都会产生一条日志。

193.112.9.107 - - [25/Jan/2020:06:32:58 +0800] "GET /robots.txt HTTP/1.1" 404 208 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0"

每条日志都由空格分隔为九部分,其中比较重要的是:

  • 第1部分,193.112.9.107 ,客户端的IP地址。
  • 第4部分,[25/Jan/2020:06:32:58 +0800],用户访问请求发生的时间。
  • 第5部分,GET /robots.txt HTTP/1.1,客户端发来的HTTP请求报文首部的第一行信息。这部分采用“请求方法 请求资源 请求协议”的格式表示,是日志中最重要的部分。“GET /robots.txt HTTP/1.1”表示客户端以GET方法请求访问服务器的/robots.txt文件,所使用的HTTP协议版本为HTTP/1.1。
  • 第6部分, “404”,HTTP响应状态码。状态码用于表示用户的请求是否成功,如果该值为200,则表示用户的访问成功,否则就可能存在问题。一般来说,以2开头的状态码均可以表示用户的访问成功,以3开头的状态码表示用户的请求被页面重新定向到了其它位置,以4开头的状态码表示客户端遇到了错误,以5开头的状态码表示服务器遇到了错误。
  • 第7部分,“208”,响应报文的大小,单位字节,这个数值不包括响应报文的首部。把日志记录中的这些值加起来就可以得知服务器在一定时间内发送了多少数据。
  • 第9部分, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0",表示客户端发来的HTTP请求报文中首部“User-Agent”的值,即发出请求的应用程序,通常都是浏览器。

一个日志文件中会包含很多天的日志记录,而我们通常都是针对某一天进行日志分析,所以首先需要从日志文件中把我们要分析的那一天的日志提取出来。
比如要提取1月25日产生的日志,可以执行下面的代码:

>>> with open(‘access_log‘,‘r‘) as f1, open(‘access_log-0125‘,‘w‘) as f2:
...     for line in f1:
...             if ‘25/Jan/2020‘ in line:
...                     f2.write(line)

在这段代码中,以r读取模式打开日志文件access_log,作为文件对象f1。以w写入模式创建文件access_log-0125,作为文件对象f2。
然后遍历f1中的每一行,并判断是否包含关键字“25/Jan/2020”,如果有的话,就将这行写入到f2中。
这样就提取出了1月25日的所有日志记录,并保存到了文件access_log-0125中。下面我们就针对文件access_log-0125进行分析。

2.统计PV和UV

PV是指PageView,网站的访问请求数。用户每次对网站中的一个页面的请求或访问均被记录为1个PV,例如某个用户访问了网站中的4个页面,那么PV就+4。而且用户对同一页面的多次访问,PV也是累计的。
UV是指UniqueView,网站的独立访客数,访问网站的一个IP被视为一个访客,在同一天内相同的IP只被计算一次。
因而,我们只要取出每条日志中的IP并统计数量,那么就可以得到PV,将IP去重,就可以得到UV。
执行下面的代码,将每条日志的IP提取出来,并存放到列表ips中。

>>> ips = []
>>> with open(‘access_log-0125‘,‘r‘) as f:
...     for line in f:
...             ips.append(line.split()[0])

在这段代码中,首先定义了一个空列表ips,然后打开文件access_log-0125并对其进行遍历,每遍历一行,就将该行以空格作为分隔符分割成一个列表,并取出列表中的第一个元素(也就是IP地址),再追加到列表ips中。
下面我们只要统计列表ips的长度就是PV,将列表元素去重之后,再统计长度就是UV。去重这里采用了set()函数,将列表转换为集合,利用Python集合本身的特性,简单高效的完成去重操作。

>>> pv = len(ips)
>>> uv = len(set(ips))
>>> print(pv,uv)
1011 48

3.统计网站出错页面比例

网站的出错比例是很重要的一份数据,直接关系到网站的用户体验。要统计用户访问出错的比例,可以通过统计每个请求的HTTP状态码得到,状态码为2xx或3xx的,视为访问正确,状态码为4xx或5xx,则视为访问出错。
首先可以提取所有页面的状态码,并保存到列表中。

>>> codes = []
>>> with open(‘access_log-0125‘,‘r‘) as f:
...     for line in f:
...             codes.append(line.split()[8])

再统计出每种状态码的出现次数,保存到字典中:

>>> ret = {}
>>> for i in codes:
...     if i not in ret:
...             ret[i] = codes.count(i)
...
>>>
>>> ret
{‘200‘: 192, ‘404‘: 796, ‘"-"‘: 4, ‘400‘: 13, ‘403‘: 3, ‘401‘: 2, ‘405‘: 1}

上面这段代码用到了字典,这里是对存放状态码的列表codes进行遍历,从中取出状态码作为字典的键,并统计这种状态码在列表codes中出现的次数,作为字典的值。
如果要统计404页面的比例,可以执行下面的代码:

>>> ret[‘404‘]/sum(ret.values())
0.7873392680514342

在这段代码中,ret[‘404‘]表示从字典ret中取出键为‘404’的元素的值,也就是404状态码的个数。ret.values()表示取出字典中所有元素的值,再用sum()函数求和,得到所有状态码的总数量。两者的比值也就是错误页面的比例了。
从结果中可以看出,我这个网站的页面出错比例特别高,竟然达到了78.7%,如果是一个正常网站,这肯定是有问题的。但我这并不是一个公开网站,也没有什么有价值的页面,因而大部分访问日志其实都是由一些漏洞扫描软件产生的,这也提醒我们,随时都有人在对我们线上的网站进行着各种扫描测试。

4.统计网站热门资源

下面我们继续统计出每个页面的用户访问量,并进行排序。
首先仍然是遍历日志文件,取出用户访问的所有页面,并保存到列表中:

>>> webs = []
>>> with open(‘access_log-0125‘,‘r‘) as f:
...     for line in f:
...             webs.append(line.split()[6])

接着再统计出每个页面的访问次数,并存放到字典中:

>>> counts = {}
>>> for i in webs:
...     if i not in counts:
...             counts[i] = webs.count(i)
...

按页面的访问量降序排序:

>>> sorted(counts.items(),key=lambda x:x[1],reverse=True)
[(‘/‘, 175), (‘/robots.txt‘, 25), (‘/phpinfo.php‘, 6), (‘/Admin13790d6a/Login.php‘, 4),
……

为了更好地理解上面这个sorted()函数的用法,下面举例说明。比如我们定义一个名叫services的字典,如果直接用sorted()函数对这个字典排序,默认是按照键进行升序排序。为了显示字典中的所有内容,可以使用items()方法,此时,字典中的每个键值对会被组合成一个元组,并且默认是按照元组中的第一个元素,也就是字典的键进行排序的。

>>> services = {‘http‘:80,‘ftp‘:21,‘https‘:443,‘ssh‘:22}
>>> sorted(services)
[‘ftp‘, ‘http‘, ‘https‘, ‘ssh‘]
>>> sorted(services.items())
[(‘ftp‘, 21), (‘http‘, 80), (‘https‘, 443), (‘ssh‘, 22)]

如果希望按照字典中的值进行排序,也就是要按照元组中的第二个元素排序,可以用key参数指定一个lambda表达式,以每个元组中的第二个元素作为关键字。

>>> sorted(services.items(),key=lambda x:x[1])
[(‘ftp‘, 21), (‘ssh‘, 22), (‘http‘, 80), (‘https‘, 443)]

所以这也就解释了之前那个sorted()函数的含义。至于lambda表达式,其实就是一个根据需要可以随时定义使用的小函数,“lambda x:x[1]”,冒号左侧的x是函数要处理的参数,冒号右侧的表达式是函数要执行的操作,最后再将这个表达式的结果返回。

本文属于“Python安全与运维”系列课程的一部分,该系列课程目前已更新到第二部,感兴趣的朋友可以参考:
第一部 Python基本语法 https://edu.51cto.com/sd/53aa7
第二部 Python编程基础 https://edu.51cto.com/sd/d100c

原文地址:https://blog.51cto.com/yttitan/2469575

时间: 2024-10-12 22:26:16

#IT明星不是梦#利用Python进行网站日志分析的相关文章

linux下利用elk+redis 搭建日志分析平台教程

linux下利用elk+redis 搭建日志分析平台教程 http://www.alliedjeep.com/18084.htm elk 日志分析+redis数据库可以创建一个不错的日志分析平台了,下面我们来看一篇在linux下利用elk+redis 搭建日志分析平台教程,希望例子对各位有帮助. 这个是最新的elk+redis搭建日志分析平台,今年时间是2015年9月11日. Elk分别为 elasticsearch,logstash, kibana 官网为:https://www.elasti

python 经典语句日志分析

#!/usr/bin/python import re def buffer_line(): buf = open("/etc/sae/buffer_1").read() if not buf: return 0 else: return int(re.findall("^\d*", buf)[0]) def set_last_pos(pos): open("/etc/sae/buffer_1", "w").write(str

Python写WEB日志分析程序的一些思路

1.背景 刚到一家公司需要写一个实时分析tshark捕捉到的数据,tshark一直往文本里面写数据,写一个程序要实时获取到添加的数据并进行分析处理最后入库.此时思绪狂飞,想了一些比较挫的方法. 本人想到的方法: 1.每隔一定时间去查看下文件的mtime,如果有改动则读取数据,并记录读取的行数.下次再去读这个文件的数据则上次记录的行数开始继续读.当文件行数太大的时候这个程序的效率就很慢了,也可以记录上次读取的字节数,然后使用linux下的open系统系统中的seek从指定位置处读取.但是要是用C语

利用Python入库性能日志到MySQL

1. Windows 下Python代码 import MySQLdb 报错 import MySQLdb ImportError: No module named MySQLdb 2.Python 连接数据库,注意要指定字符集 import MySQLdb db = MySQLdb.connect(host = '192.168.1.101',user = 'user',passwd = 'password',db='PERFDB',charset='utf8' ) cursor = db.c

利用Python实现扫描日志关键字!Python真的无所不能!

我们在压力测试过程会收集到很多log,怎样快速从中找到有用信息呢?让python脚本帮我们做这部分工作吧! 废话不说,上代码 环境:win10 + python2.7.14 countTime.py 关键字及被扫描的日志路径信息,记录到文件中,以逗号+空格隔开,如,", "日志路径信息放到最后.格式如下: anr, dalvikvm: Could not find class 'android.app.usage., panic, C:\Users\BHJ\logcat1.log 执行

python 写的日志分析

#coding=utf-8 #!/usr/bin/python import string import re import sys file =  sys.argv[1] f = open(file, 'r') ip_url = [] ip = [] url_url = [] while True: line = f.readline() if not line:break line1 = line.split() clientIP = line1[0] status = line1[8] u

Python葵花宝典-mysql日志分析

#!/usr/bin/python # -*- coding:utf-8 -*- import re import sys import time import MySQLdb def create_table(): db=MySQLdb.connect(host="localhost", user="root", passwd="mysql", db="slow_log") cursor=db.cursor() cursor

Python葵花宝典-nginx日志分析

#!/usr/bin/python # -*- coding:utf-8 -*- __author__ = 'lvnian' #!/usr/bin env python # coding: utf-8 import MySQLdb as mysql import sys,os,re db = mysql.connect(user="root",passwd="mysql",db="nginx_log",host="192.168.11.

python分析apahce网站日志的例子

有关python实现apahce网站日志分析的方法. 应用到:shell与python数据交互.数据抓取,编码转换 #coding:utf-8 #!/usr/bin/python'''程序说明:apache access.log日志分析 分析访问网站IP 来源情况 日期:2014-01-06 17:01 author:gyh9711 程序说明:应用到:shell与python数据交互.数据抓取,编码转换'''import osimport jsonimport httplibimport cod