python代码分析nginx访问日志
本人网站使用内网穿透,分析结结果IP都是内网地址。
===== 统计结果 =====
总访问量:641805
独立IP数:14
最活跃IP:192.168.1.29(访问492948次)
访问高峰时段:16时(59997次)
图表已保存至:C:/Users/czliu/Downloads/nginx_analysis.png
- 代码
importreimportpandasaspdimportmatplotlib.pyplotaspltfromcollectionsimportCounterfromdatetimeimportdatetime# ===================== 配置项(你的日志路径) =====================LOG_PATH=r"C:\Users\czliu\Downloads\access.log"# ==================================================================# 辅助函数:清理字符串中的无效字符defclean_string(s):ifisinstance(s,str):# 移除非打印字符和二进制数据return''.join(cforcinsifc.isprintable())returns# 1. Nginx日志正则表达式(通用格式)# 匹配格式:IP - - [时间] "请求" 状态码 大小 "来源" "UA"log_pattern=re.compile(r'(\d+\.\d+\.\d+\.\d+)\s+-\s+-\s+\[(.*?)\]\s+"(.*?)"\s+(\d+)\s+(\d+|-)')# 2. 解析日志parsed_data=[]withopen(LOG_PATH,'r',encoding='utf-8',errors='ignore')asf:forlineinf:# 清理日志行中的无效字符clean_line=clean_string(line)match=log_pattern.match(clean_line.strip())ifmatch:ip,time_str,request,status,size=match.groups()# 清理各个字段ip=clean_string(ip)time_str=clean_string(time_str)request=clean_string(request)status=clean_string(status)size=clean_string(size)# 处理时间dt=Nonetry:# 日志时间格式:03/Jan/2025:12:34:56 +0800dt=datetime.strptime(time_str,'%d/%b/%Y:%H:%M:%S %z')hour=dt.hour# 按小时统计except:hour=-1# 提取请求方法和URLreq_parts=request.split()method=req_parts[0]iflen(req_parts)>0else'UNKNOWN'url=req_parts[1]iflen(req_parts)>1else'/'# 再次清理方法和URLmethod=clean_string(method)url=clean_string(url)parsed_data.append({'ip':ip,'time':dt,'hour':hour,'method':method,'url':url,'status':int(status),'size':int(size)ifsize!='-'else0})# 转为DataFrame方便分析df=pd.DataFrame(parsed_data)print(f"日志解析完成,总访问量:{len(df)}条")# 清理数据iflen(df)>0:df['ip']=df['ip'].apply(clean_string)df['method']=df['method'].apply(clean_string)df['url']=df['url'].apply(clean_string)# 3. 分析核心数据# 3.1 访问量TOP10 IPip_top10=Counter(df['ip']).most_common(10)# 3.2 按小时访问趋势hour_counts=df[df['hour']!=-1]['hour'].value_counts().sort_index()# 3.3 HTTP状态码分布status_counts=df['status'].value_counts()# 3.4 请求方法分布method_counts=df['method'].value_counts()# 4. 绘制综合图表(2x2子图)iflen(df)>0:plt.rcParams['font.sans-serif']=['SimHei']# 解决中文乱码plt.rcParams['axes.unicode_minus']=Falseplt.rcParams['text.usetex']=False# 禁用LaTeXplt.rcParams['text.parse_math']=False# 禁用mathtext解析,防止反斜杠被误解析fig,((ax1,ax2),(ax3,ax4))=plt.subplots(2,2,figsize=(16,10))fig.suptitle('Nginx访问日志分析报告',fontsize=18,fontweight='bold')# 子图1:TOP10访问IPifip_top10:# 清理IP地址中的特殊字符并限制长度clean_ips=[]forip,_inip_top10:clean_ip=clean_string(ip)# 限制IP显示长度,避免过长iflen(clean_ip)>15:clean_ip=clean_ip[:15]+'...'clean_ips.append(clean_ip)ax1.barh(clean_ips,[cntfor_,cntinip_top10],color='#1f77b4')ax1.set_title('TOP10 访问IP',fontsize=14)ax1.set_xlabel('访问次数')else:ax1.set_title('TOP10 访问IP',fontsize=14)ax1.text(0.5,0.5,'无数据',ha='center',va='center')# 子图2:小时访问趋势ifnothour_counts.empty:ax2.plot(hour_counts.index,hour_counts.values,marker='o',color='#ff7f0e',linewidth=2)ax2.set_title('24小时访问趋势',fontsize=14)ax2.set_xlabel('小时')ax2.set_ylabel('访问量')ax2.grid(alpha=0.3)else:ax2.set_title('24小时访问趋势',fontsize=14)ax2.text(0.5,0.5,'无数据',ha='center',va='center')# 子图3:HTTP状态码分布ifnotstatus_counts.empty:colors=['#2ca02c','#d62728','#9467bd','#8c564b']# 确保标签是字符串且干净labels=[str(label)forlabelinstatus_counts.index]ax3.pie(status_counts.values,labels=labels,autopct='%1.1f%%',colors=colors[:len(status_counts)])ax3.set_title('HTTP状态码分布',fontsize=14)else:ax3.set_title('HTTP状态码分布',fontsize=14)ax3.text(0.5,0.5,'无数据',ha='center',va='center')# 子图4:请求方法分布ifnotmethod_counts.empty:# 清理请求方法中的特殊字符并过滤掉无效方法clean_methods=[]clean_values=[]formethod,cntinmethod_counts.items():clean_method=clean_string(method)# 只保留有效的HTTP方法ifclean_methodin['GET','POST','PUT','DELETE','HEAD','OPTIONS']orcnt>10:clean_methods.append(clean_method)clean_values.append(cnt)ifclean_methods:ax4.bar(clean_methods,clean_values,color='#e377c2')ax4.set_title('请求方法分布',fontsize=14)ax4.set_ylabel('次数')else:ax4.set_title('请求方法分布',fontsize=14)ax4.text(0.5,0.5,'无数据',ha='center',va='center')else:ax4.set_title('请求方法分布',fontsize=14)ax4.text(0.5,0.5,'无数据',ha='center',va='center')plt.tight_layout()plt.savefig(r'C:\Users\czliu\Downloads\nginx_analysis.png',dpi=300,bbox_inches='tight')plt.close()# 关闭图表,避免在非交互式环境中出现问题# 5. 打印关键统计print("\n===== 统计结果 =====")print(f"总访问量:{len(df)}")print(f"独立IP数:{df['ip'].nunique()}")ifip_top10:print(f"最活跃IP:{ip_top10[0][0]}(访问{ip_top10[0][1]}次)")else:print("最活跃IP:无数据")ifnothour_counts.empty:print(f"访问高峰时段:{hour_counts.idxmax()}时({hour_counts.max()}次)")else:print("访问高峰时段:无数据")iflen(df)>0:print(f"图表已保存至:C:/Users/czliu/Downloads/nginx_analysis.png")else:print("图表:无数据,未生成")