1. 程式人生 > 實用技巧 >Python網頁分析,分析網站的日誌資料

Python網頁分析,分析網站的日誌資料

前言

本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯絡我們以作處理。

以下文章來源於大話資料分析,作者:尚天強

網站的日誌資料記錄了所有Web對伺服器的訪問活動,本節通過Python第三方庫解析網站日誌,利用pandas對網站日誌資料進行預處理,並用視覺化技術,對於網站日誌資料進行分析。

PS:如有需要Python學習資料的小夥伴可以加下方的群去找免費管理員領取

可以免費領取原始碼、專案實戰視訊、PDF檔案等

資料來源

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import apache_log_parser        # 首先通過 pip install apache_log_parser 安裝庫
%matplotlib inline
fformat = '%V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %T'  # 建立解析器
p = apache_log_parser.make_parser(fformat)
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'
data = p(sample_string) #解析後的資料為字典結構
data

datas = open(r'H:\python資料分析\資料\apache_access_log').readlines()  #逐行讀取log資料
log_list = []  # 逐行讀取並解析為字典
for line in datas:
data = p(line)
data['time_received'] = data['time_received'][1:12]+' '+data['time_received'][13:21]+' '+data['time_received'][22:27] #時間資料整理
log_list.append(data)    #傳入列表
log = pd.DataFrame(log_list)   #構造DataFrame
log = log[['status','response_bytes_clf','remote_host','request_first_line','time_received']]   #提取感興趣的欄位
log.head()
#status 狀態碼 response_bytes_clf 返回的位元組數(流量)remote_host 遠端主機IP地址 request_first_line 請求內容t ime_received 時間資料

日誌資料清洗

log.isnull().sum() # 檢視缺失值

log['time_received'] = pd.to_datetime(log['time_received']) #把time_received欄位轉換為時間資料型別,並設定為索引
log = log.set_index('time_received')
log.head()

log.dtypes # 檢視型別

log['status'] = log['status'].astype('int') # 轉換為int型別
log['response_bytes_clf'].unique()
array(['26126', '10532', '1853', ..., '66386', '47413', '48212'], dtype=object)
log[log['response_bytes_clf'] == '-'].head() #對response_bytes_clf欄位進行轉換時報錯,查詢原因發現其中含有“-”

def dash2nan(x):    # 定義轉換函式,當為“-”字元時,將其替換為空格,並將位元組資料轉化為M資料
   if x == '-':
x = np.nan
   else:
x = float(x)/1048576
   return x
log['response_bytes_clf'] = log['response_bytes_clf'].map(dash2nan)
log.head()

log.dtypes

日誌資料分析

log['response_bytes_clf'].plot()

流量起伏不大,但有一個極大的峰值超過了20MB。

log[log['response_bytes_clf']>20] #檢視流量峰值

t_log = log['response_bytes_clf'].resample('30t').count()
t_log.plot()

對時間重取樣(30min),並計數 ,可看出每個時間段訪問的次數,早上8點訪問次數最多,其餘時間處於上下波動中。

h_log = log['response_bytes_clf'].resample('H').count()
h_log.plot()

當繼續轉換頻率到低頻率時,上下波動不明顯。

d_log = pd.DataFrame({'count':log['response_bytes_clf'].resample('10t').count(),'sum':log['response_bytes_clf'].resample('10t').sum()})    
d_log.head()

構造訪問次數和訪問流量的 DataFrame。

plt.figure(figsize=(10,6))   #設定圖表大小
ax1 = plt.subplot(111)    #一個subplot
ax2 = ax1.twinx()     #公用x軸
ax1.plot(d_log['count'],color='r',label='count')
ax1.legend(loc=2)
ax2.plot(d_log['sum'],label='sum')
ax2.legend(loc=0)

繪製折線圖,有圖可看出,訪問次數與訪問流量存在相關性。

IP地址分析

ip_count = log['remote_host'].value_counts()[0:10] #對remote_host計數,並取前10位
ip_count

ip_count.plot(kind='barh') #IP前十位柱狀圖

import pygeoip # pip install pygeoip 安裝庫
# 同時需要在網站上(http://dev.maxmind.com/geoip/legacy/geolite)下載DAT檔案才能解析IP地址
gi = pygeoip.GeoIP(r'H:\python資料分析\資料\GeoLiteCity.dat', pygeoip.MEMORY_CACHE)
info = gi.record_by_addr('64.233.161.99')
info #解析IP地址

ips = log.groupby('remote_host')['status'].agg(['count']) # 對IP地址分組統計
ips.head()

ips.drop('91.224.246.183',inplace=True)

ips['country'] = [gi.record_by_addr(i)['country_code3'] for i in ips.index] # 將IP解析的國家和經緯度寫入DataFrame
ips['latitude'] = [gi.record_by_addr(i)['latitude'] for i in ips.index]
ips['longitude'] = [gi.record_by_addr(i)['longitude'] for i in ips.index]

ips.head()

country = ips.groupby('country')['count'].sum() #對country欄位分組統計
country = country.sort_values(ascending=False)[0:10] # 篩選出前10位的國家
country

country.plot(kind='bar')

俄羅斯的訪問量最多,可推斷該網站來源於俄羅斯。

from mpl_toolkits.basemap import Basemap

plt.style.use('ggplot')
plt.figure(figsize=(10,6))

map1 = Basemap(projection='robin', lat_0=39.9, lon_0=116.3,
resolution = 'l', area_thresh = 1000.0)

map1.drawcoastlines()
map1.drawcountries()
map1.drawmapboundary()

map1.drawmeridians(np.arange(0, 360, 30))
map1.drawparallels(np.arange(-90, 90, 30))

size = 0.03
for lon, lat, mag in zip(list(ips['longitude']), list(ips['latitude']), list(ips['count'])):
x,y = map1(lon, lat)
msize = mag * size
map1.plot(x, y, 'ro', markersize=msize)