基于python实现cdn日志文件导入mysql进行分析
作者:??梦想橡皮擦???? 发布时间:2024-01-29 07:37:55
一、本文需求背景
周六日出现CDN大量请求,现需要分析其请求频次与来源,查询是否存在被攻击问题。
本文以阿里云CDN日志作为辅助查询数据,其它云平台大同小异。
系统提供的离线日志如下所示:
二、需求落地如下
日志实例如下所示:
[9/Jun/2015:01:58:09 +0800] 10.10.10.10 - 1542 "-" "GET http://www.aliyun.com/index.html" 200 191 2830 MISS "Mozilla/5.0 (compatible; AhrefsBot/5.0; +http://example.com/robot/)" "text/html"
其中相关字段的解释如下:
[9/Jun/2015:01:58:09 +0800]
:日志开始时间。10.10.10.10
:访问IP。-
: * 。1542
:请求响应时间,单位为毫秒。"-"
: HTTP请求头中的Referer。GET
:请求方法。http://www.aliyun.com/index.html
:用户请求的URL链接。200
:HTTP状态码。191
:请求大小,单位为字节。2830
:请求返回大小,单位为字节。MISS
:命中信息。HIT
:用户请求命中了CDN边缘节点上的资源(不需要回源)。MISS
:用户请求的内容没有在CDN边缘节点上缓存,需要向上游获取资源(上游可能是CDN L2节点,也可能是源站)。Mozilla/5.0(compatible; AhrefsBot/5.0; +http://example.com/robot/)
:User-Agent请求头信息。text/html
:文件类型。
按照上述字段说明创建一个 MySQL 表,用于后续通过 Python 导入 MySQL 数据,字段可以任意定义
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for ll
-- ----------------------------
DROP TABLE IF EXISTS `ll`;
CREATE TABLE `ll` (
`id` int(11) NOT NULL,
`s_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`pro_ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`dura_time` int(11) NULL DEFAULT NULL,
`referer` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`code` int(255) NULL DEFAULT NULL,
`size` double NULL DEFAULT NULL,
`res_size` double NULL DEFAULT NULL,
`miss` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`ua` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`html_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
下载全部日志之后,使用 Python 批量导入数据库中,解析代码如下,在提前开始前需要先看一下待提取的每行数据内容。
[11/Mar/2022:00:34:17 +0800] 118.181.139.215 - 1961 "http://xx.baidu.cn/" "GET https://cdn.baidu.com/video/1111111111.mp4" 206 66 3739981 HIT "Mozilla/5.0 (iPad; CPU OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 SP-engine/2.43.0 main%2F1.0 baiduboxapp/13.5.0.10 (Baidu; P2 15.1) NABar/1.0" "video/mp4"
初看之下,我们会使用空格进行切片,例如下述代码:
import os
# 获取文件名
my_path = r"C:日志目录"
file_names = os.listdir(my_path)
file_list = [os.path.join(my_path, file) for file in file_names]
for file in file_list:
with open(file, 'r', encoding='utf-8') as f:
lines = f.readlines()
for i in lines:
item_list = i.split(' ')
s_time = item_list[0]+' '+item_list[1]
ip = item_list[2],
pro_ip =item_list[3],
dura_time =item_list[4],
referer =item_list[5],
method =item_list[6],
url = item_list[7],
code =item_list[8],
size =item_list[9],
res_size =item_list[10],
miss =item_list[11],
html_type =item_list[12]
print(s_time,ip,pro_ip,dura_time,referer,method,url,code,size,res_size,miss,html_type)
运行之后,会发现里面的开始时间位置,UA位置都存在空格,所以该方案舍弃,接下来使用正则表达式提取。
参考待提取的模板编写正则表达式如下所示:
\[(?<time>.*?)\] (?<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (?<pro_ip>.*?) (?<dura_time>\d+) \"(?<referer>.*?)\" \"(?<method>.*?) (?<url>.*?)\" (?<code>\d+) (?<size>\d+) (?<res_size>\d+) (?<miss>.*?) \"(?<ua>.*?)\" \"(?<html_type>.*?)\"
接下来进行循环读取数据,然后进行提取:
import os
import re
import pymysql
# 获取文件名
my_path = r"C:日志文件夹"
file_names = os.listdir(my_path)
file_list = [os.path.join(my_path, file) for file in file_names]
wait_list = []
for file in file_list:
with open(file, 'r', encoding='utf-8') as f:
lines = f.readlines()
for i in lines:
pattern = re.compile(
'\[(?P<time>.*?)\] (?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) (?P<pro_ip>.*?) (?P<dura_time>\d+) \"(?P<referer>.*?)\" \"(?P<method>.*?) (?P<url>.*?)\" (?P<code>\d+) (?P<size>\d+) (?P<res_size>\d+) (?P<miss>.*?) \"(?P<ua>.*?)\" \"(?P<html_type>.*?)\"')
gs = pattern.findall(i)
item_list = gs[0]
s_time = item_list[0]
ip = item_list[1]
pro_ip = item_list[2]
dura_time = item_list[3]
referer = item_list[4]
method = item_list[5]
url = item_list[6]
code = item_list[7]
size = item_list[8]
res_size = item_list[9]
miss = item_list[10]
ua = item_list[11]
html_type = item_list[12]
values_str = f"('{s_time}', '{ip}', '{pro_ip}', {int(dura_time)}, '{referer}', '{method}', '{url}', {int(code)}, {int(size)}, {int(res_size)}, '{miss}', '{ua}','{html_type}')"
wait_list.append(values_str)
读取到数据存储到 wait_list
列表中,然后操作列表,写入MySQL,该操作为了防止SQL语句过长,所以每次间隔1000元素进行插入。
def insert_data():
for i in range(0,int(len(wait_list)/1000+1)):
items = wait_list[i * 1000:i * 1000 + 1000]
item_str = ",".join(items)
inser_sql = f"INSERT INTO ll(s_time, ip, pro_ip, dura_time, referer, method, url,code, size, res_size, miss, ua,html_type) VALUES {item_str}"
db = pymysql.connect(host='localhost',
user='root',
password='root',
database='logs')
cursor = db.cursor()
try:
cursor.execute(inser_sql)
db.commit()
except Exception as e:
# print(content)
print(e)
db.rollback()
最终的结果如下所示:
导入MySQL之后,就可以按照自己的需求进行排序与查询了。
三、自定义查询
可以通过 refer 计算请求次数:
select count(id) num,referer from ll GROUP BY referer ORDER BY num desc
来源:https://juejin.cn/post/7076248160330317861


猜你喜欢
- 成功解决ValueError: Supported target types are: ('binary', 'mu
- asp中利用XMLhttp对象获取远程的数据,然后用二进制输出到客户浏览器,让客户下载数据,此例从某一远程服务器获取一个压缩包,并且输出到浏
- 前言最近有朋友在做投票的项目,里面有用到一个倒计时的组件,还想要个动画效果。cv * 浸染多年的我,首先想到的是直接找个现有的组件。通过一通搜
- 为什么要使用缓存?一个 * 站的基本权衡点就是,它是动态的。 每次用户请求页面,服务器会重新计算。从开销处理的角度来看,这比你读取一个现成的
- 前言本文参考PyTorch官网的教程,分为五个基本模块来介绍PyTorch。为了避免文章过长,这五个模块分别在五篇博文中介绍。Part3:使
- ASP中RegExp是什么 '名字字符检验Public Function CheckName(Str) &nbs
- json文件格式这是yolov4模型跑出来的检测结果result.json下面是截取的一张图的检测结果{ "frame_id&qu
- 写这个文章绝对是偶然的偶然的机会,前年等一回的 元旦节,和 老婆上街 溜达,猛然想起买上一张福利彩票,结果屁都没有中上,开春第一
- python爬取淘宝商品销量的程序,运行程序,输入想要爬取的商品关键词,在代码中的‘###'可以进一步约束商品的属性,比如某某作者的
- 问题背景用户反馈说当与外部客户端进行 FTP 传输时,可以成功登录,但无法传输任何数据。总之 FTP 传输失败,需要来弄清楚到底发生了什么。
- 1,效果图 2,实现方法const columns = [ { title: '序号',  
- 前段时间在开发雨哲树网程序的时候,遇到需要转换地址中的参数,需要用到简单可逆运算的加密功能。在网上找了很多都不理想。因为我需要的这个可逆运算
- 一、问题实现对文本的分句,大致来说主要是以中文的句号、感叹、问号等符号进行分句。难点在于直接分句可能会造成人物说话的语句也被分开!二、步骤分
- 字符串Go语言中的字符串以原生数据类型出现。 Go 语言里的字符串的内部实现使用UTF-8编码。 字符串的值为双引号(")中的内容
- 数组新的shape属性应该要与原来的配套,如果等于-1的话,那么Numpy会根据剩下的维度计算出数组的另外一个shape属性值。举个例子:x
- 本文实例讲述了Golang最大递减数算法问题。分享给大家供大家参考,具体如下:给出一个非负整数,找到这个非负整数中包含的最大递减数。一个数字
- 前言没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。希望:所以说,树倒了,没
- 实验目的:用socket 模拟一个微型的web服务器,当py脚本run起后,实微型web server架起了,然后用本地浏览器访问
- 阅读《YUI学习笔记(1)》YAHOO.lang.dump 与 YAHOO.lang.substitute。1.&nbs
- From Python正则表达式re.match(pattern, string, flags=0)尝试从字符串起始位置匹配一个模式;如果不