日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

使用 Pandas 分析 Apache 日志

發(fā)布時(shí)間:2023/11/29 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用 Pandas 分析 Apache 日志 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文的作者是 Nikolay Koldunov,本文原文是
Apache log analysis with Pandas

注本文的圖有問題,沒法引用,還是去原文看下,這里作為一個(gè)引子。

%pylab inline

歡迎來到 pylab,一個(gè)基于 matplotlib 的 Python 環(huán)境【backend: module://IPython.kernel.zmq.pylab.backend_inline】。想要了解更多信息,請(qǐng)鍵入 'help(pylab)'。

在這個(gè)筆記中,我們將展示一個(gè)使用 pandas 分析 Apache 訪問日志的簡(jiǎn)單示例。這是我第一次使用 pandas,并且我確定會(huì)有更好以及更有效率的方式來做這里展示的事情。所以評(píng)論,建議和修正我的蹩腳英語(yǔ)是非常歡迎的。你可以給我發(fā)送郵件或者是為這個(gè)筆記的 github 創(chuàng)建一個(gè) PR。

加載和解析數(shù)據(jù)

我們將需要 apachelog 模塊,用來解析日志。我們也需要知道設(shè)置在 Apache 配置中的日志格式。在我的案例中,我沒有訪問 Apache 配置,但是主機(jī)托管服務(wù)提供商在他的幫助頁(yè)提供了日志格式的描述。下面是它自己的格式以及每個(gè)元素的簡(jiǎn)單描述:

format = r'%V %h %l %u %t \"%r\" %>s %b \"%i\" \"%{User-Agent}i\" %T'

這里(大部分拷貝自這個(gè) SO 文章):

%V - 根據(jù) UseCanonicalName 設(shè)置的服務(wù)器名字 %h - 遠(yuǎn)程主機(jī)(客戶端 IP) %l - identity of the user determined by identd (not usually used since not reliable) %u - 由 HTTP authentication 決定的 user name %t - 服務(wù)器完成處理這個(gè)請(qǐng)求的時(shí)間 %r - 來自客戶端的請(qǐng)求行。 ("GET / HTTP/1.0") %>s - 服務(wù)器端返回給客戶端的狀態(tài)碼(200, 404 等等。) %b - 響應(yīng)給客戶端的響應(yīng)報(bào)文大小 (in bytes) \"%i\" - Referer is the page that linked to this URL. User-agent - the browser identification string %T - Apache 請(qǐng)求時(shí)間 In [3]:import apachelog, sys

設(shè)置格式:

In [4]:fformat = r'%V %h %l %u %t \"%r\" %>s %b \"%i\" \"%{User-Agent}i\" %T'

創(chuàng)建一個(gè)解析器:

In [5]:p = apachelog.parser(fformat)

簡(jiǎn)單字符串:

koldunov.net 85.26.235.202 - - [16/Mar/2013:00:19:43 +0400] "GET /?p=364 HTTP/1.0" 200 65237 "http://koldunov.net/?p=364" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11" 0 In [6]:sample_string = 'koldunov.net 85.26.235.202 - - [16/Mar/2013:00:19:43 +0400] "GET /?p=364 HTTP/1.0" 200 65237 "http://koldunov.net/?p=364" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11" 0' In [7]:data = p.parse(sample_string) In [8]:data Out[8]: {'%>s': '200','%T': '0','%V': 'koldunov.net','%b': '65237','%h': '85.26.235.202','%i': 'http://koldunov.net/?p=364','%l': '-','%r': 'GET /?p=364 HTTP/1.0','%t': '[16/Mar/2013:00:19:43 +0400]','%u': '-','%{User-Agent}i': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'}

這就是解釋器的工作。現(xiàn)在讓我們加載真實(shí)世界的數(shù)據(jù)(示例文件位于這里和這里):

In [9]:log = open('access_log_for_pandas').readlines()

解析每一行,并且創(chuàng)建一個(gè)字典列表:

In [10]: log_list = [] for line in log:try:data = p.parse(line)except:sys.stderr.write("Unable to parse %s" % line)data['%t'] = data['%t'][1:12]+' '+data['%t'][13:21]+' '+data['%t'][22:27]log_list.append(data)

我們不得不調(diào)整時(shí)間格式位,否則的話 pandas 將不能解析它。

創(chuàng)建和調(diào)整數(shù)據(jù)幀

這將創(chuàng)建一個(gè)字典列表,可以轉(zhuǎn)化到一個(gè)數(shù)據(jù)幀:

import pandas as pd import numpy as np from pandas import Series, DataFrame, Panel df = DataFrame(log_list)

展示數(shù)據(jù)幀的前兩行:

df[0:2] -%>s%T%V%b%h%i%l%r%t%u%{User-Agent}i
02000www.oceanographers.ru26126109.165.31.156--GET /index.php?option=com_content&task=section...16/Mar/2013 08:00:25 +0400-Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20...
12000www.oceanographers.ru10532109.165.31.156 http://www.oceanographers.ru/index.php?option=...-GET /templates/ja_procyon/css/template_css.css...16/Mar/2013 08:00:25 +0400-Mozilla/5.0 (Windows NT 6.1; rv:19.0) Gecko/20...

我們不準(zhǔn)備使用所有的數(shù)據(jù),因此讓我們刪除一些列:

del df['%T']; del df['%V']; del df['%i']; del df['%l']; del df['%u']; del df['%{User-Agent}i']

并且把這些列重命名成人類可理解的格式:

df = df.rename(columns={'%>s': 'Status', '%b':'b', '%h':'IP', '%r':'Request', '%t': 'Time'})

結(jié)果數(shù)據(jù)幀的前 5 行:

df.head() -StatusbIPRequestTime
020026126109.165.31.156GET /index.php?option=com_content&task=section...16/Mar/2013 08:00:25 +0400
120010532109.165.31.156GET /templates/ja_procyon/css/template_css.css...16/Mar/2013 08:00:25 +0400
22001853109.165.31.156GET /templates/ja_procyon/switcher.js HTTP/1.016/Mar/2013 08:00:25 +0400
320037153109.165.31.156GET /includes/js/overlib_mini.js HTTP/1.016/Mar/2013 08:00:25 +0400
42003978109.165.31.156GET /modules/ja_transmenu/transmenuh.css HTTP/1.016/Mar/2013 08:00:25 +0400

轉(zhuǎn)換時(shí)間列成 datetime 格式并做一個(gè)索引出來(pop 將丟棄原始的 Time 列):

df.index = pd.to_datetime(df.pop('Time'))

Status 變量是一個(gè) string 類型,因此我們需要把它轉(zhuǎn)換成 int:

df['Status'] = df['Status'].astype('int')

一些 b 列的行包含 '-' 字符,我們需要使用 astype 轉(zhuǎn)換它們:

df['b'][93] Out[19]: '-'

我們可以為該列使用一個(gè)通用的函數(shù),它們將把所有的破折號(hào)轉(zhuǎn)換成 NaN,并且剩余的轉(zhuǎn)換成 floats,另外把 bytes 轉(zhuǎn)換成 megabytes:

def dash2nan(x):if x == '-':x = np.nanelse:x = float(x)/1048576.return x df['b'] = df['b'].apply(dash2nan)

我相信有一個(gè)更優(yōu)雅的方式來做到這一點(diǎn)。

流量分析

首先,最簡(jiǎn)單的散點(diǎn):從該網(wǎng)站的出口流量:

df['b'].plot() <matplotlib.axes.AxesSubplot at 0xbf7574c>

看起來在早上 9 點(diǎn)左右有人從網(wǎng)站下載了一些大的東西。

但是實(shí)際上你想知道的第一件事是你的網(wǎng)站有多少的訪問量,以及它們的時(shí)間分布。我們從 b 變量的 5 分鐘間隔重新取樣,并計(jì)算每個(gè)時(shí)間跨度的請(qǐng)求數(shù)。實(shí)際上,在這個(gè)示例中不管我們使用哪個(gè)變量,這些數(shù)字將表明有多少次請(qǐng)求該網(wǎng)站的信息請(qǐng)求。

df_s = df['b'].resample('5t', how='count') df_s.plot() Out[23]: <matplotlib.axes.AxesSubplot at 0xc14588c>

![此處輸入圖片的描述][8]

我們不僅僅計(jì)算每個(gè)時(shí)間的請(qǐng)求數(shù),也計(jì)算每個(gè)時(shí)間段的總流量:

df_b = df['b'].resample('10t', how=['count','sum']) df_b['count'].plot( color='r') legend() df_b['sum'].plot(secondary_y=True) Out[24]: <matplotlib.axes.AxesSubplot at 0xc2d53ac>

![此處輸入圖片的描述][9]

正如你所看到的,服務(wù)器請(qǐng)求數(shù)和流量是不一致的,相關(guān)性其實(shí)并不是非常高:

df_b.corr()

|-| count| sum
|count| 1.000000| 0.512629
|sum| 0.512629| 1.000000

我們可以仔細(xì)看下早高峰:

df_b['2013-03-16 6:00':'2013-03-16 10:00']['sum'].plot() Out[26]: <matplotlib.axes.AxesSubplot at 0xc3f5dac>

![此處輸入圖片的描述][10]

看起來流量峰值是由一個(gè)請(qǐng)求引起的。讓我們找出這個(gè)請(qǐng)求。選擇所有響應(yīng)大于 20 Mb 的請(qǐng)求:

df[df['b']>20] -StatusbIPRequest
Time
2013-03-16 09:02:5920021.36570177.50.248.20GET /books/Bondarenko.pdf HTTP/1.0

這是一本書的 pdf 文件,這就解釋了在 2013-03-16 09:02:59 的流量出口峰值。

接近 20 Mb 是一個(gè)大的請(qǐng)求(至少對(duì)于我們網(wǎng)站),但是服務(wù)器響應(yīng)的典型大小是?響應(yīng)大小(小于 20Mb)的立方圖看起來像這樣:

cc = df[df['b']<20] cc.b.hist(bins=10) Out[28]: <matplotlib.axes.AxesSubplot at 0xc52374c>

![此處輸入圖片的描述][11]

因此,大部分的文件是小于 0.5 Mb。實(shí)際上它們甚至更小:

cc = df[df['b']<0.3] cc.b.hist(bins=100) Out[29]: <matplotlib.axes.AxesSubplot at 0xc5760ec>

![此處輸入圖片的描述][12]

總結(jié)

以上是生活随笔為你收集整理的使用 Pandas 分析 Apache 日志的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。