init 全新仓库,清除全部历史
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import poplib
|
||||
import ssl
|
||||
import email
|
||||
from email.header import decode_header
|
||||
import time
|
||||
import pymysql
|
||||
|
||||
# 关闭SSL校验,解决老Python握手重置
|
||||
#ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
# ========== 邮箱配置 自行修改 ==========
|
||||
MAIL_HOST = "pop.163.com"
|
||||
MAIL_PORT = 995
|
||||
MAIL_USER = "lyudream@163.com"
|
||||
MAIL_PWD = "DVZxyF5NKCkR6fL5"
|
||||
|
||||
# ========== 本地MariaDB配置 ==========
|
||||
DB_HOST = "127.0.0.1"
|
||||
DB_USER = "root"
|
||||
DB_PWD = "hp93000"
|
||||
DB_NAME = "alert_mail_stat"
|
||||
|
||||
# 解码邮件标题、正文
|
||||
def decode_str(s):
|
||||
value, charset = decode_header(s)[0]
|
||||
if charset:
|
||||
value = value.decode(charset)
|
||||
return value
|
||||
|
||||
# 获取邮件正文
|
||||
def get_email_content(msg):
|
||||
content = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
content_type = part.get_content_type()
|
||||
content_disposition = str(part.get("Content-Disposition"))
|
||||
if content_type == 'text/plain' and 'attachment' not in content_disposition:
|
||||
payload = part.get_payload(decode=True)
|
||||
charset = part.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
break
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
charset = msg.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
return content
|
||||
|
||||
# 简单解析告警关键字(适配Alertmanager中文邮件模板:告警名称、实例、级别)
|
||||
def parse_alert_info(text):
|
||||
alert_name = ""
|
||||
instance = ""
|
||||
severity = "unknown"
|
||||
lines = text.splitlines()
|
||||
for line in lines:
|
||||
if "告警名称" in line:
|
||||
alert_name = line.split(":")[-1].strip()
|
||||
if "实例" in line:
|
||||
instance = line.split(":")[-1].strip()
|
||||
if "级别" in line:
|
||||
s_val = line.split(":")[-1].strip()
|
||||
if s_val.lower() in ["critical", "严重"]:
|
||||
severity = "critical"
|
||||
elif s_val.lower() in ["warning", "警告"]:
|
||||
severity = "warning"
|
||||
return alert_name, instance, severity
|
||||
|
||||
# 主抓取逻辑
|
||||
def crawl_mail():
|
||||
# 连接数据库
|
||||
db = pymysql.connect(host=DB_HOST, user=DB_USER, password=DB_PWD, database=DB_NAME, charset='utf8mb4')
|
||||
cursor = db.cursor()
|
||||
|
||||
# 连接POP3邮箱
|
||||
pop_conn = poplib.POP3_SSL(MAIL_HOST, MAIL_PORT)
|
||||
pop_conn.user(MAIL_USER)
|
||||
pop_conn.pass_(MAIL_PWD)
|
||||
total_num, total_size = pop_conn.stat()
|
||||
print(f"当前邮箱总邮件数量: {total_num}")
|
||||
|
||||
if total_num == 0:
|
||||
print("暂无新邮件")
|
||||
pop_conn.quit()
|
||||
db.close()
|
||||
return
|
||||
|
||||
# 从最新一封开始遍历
|
||||
for idx in range(total_num, 0, -1):
|
||||
# 获取邮件原始内容
|
||||
resp, raw_lines, octet = pop_conn.retr(idx)
|
||||
raw_msg = b'\r\n'.join(raw_lines).decode('utf-8', errors='ignore')
|
||||
msg = email.message_from_string(raw_msg)
|
||||
|
||||
# 生成唯一标识去重
|
||||
mail_uid = msg.get("Message-ID", str(time.time()))
|
||||
|
||||
# 查重,避免重复入库
|
||||
cursor.execute("SELECT id FROM alert_log WHERE mail_uid=%s", (mail_uid,))
|
||||
if cursor.fetchone():
|
||||
print(f"邮件{idx}已存在数据库,跳过")
|
||||
continue
|
||||
|
||||
# 解析标题、发件人
|
||||
subject = decode_str(msg.get("Subject", ""))
|
||||
from_addr = msg.get("From", "")
|
||||
|
||||
# ===================== 临时关闭发件人过滤,全部邮件放行测试 =====================
|
||||
# if "prometheusalert" not in from_addr.lower():
|
||||
# print(f"邮件{idx}发件人不匹配,跳过,发件人:{from_addr}")
|
||||
# continue
|
||||
|
||||
# 调试打印所有邮件基础信息
|
||||
print("\n========================================")
|
||||
print(f"【调试】正在处理第 {idx} 封邮件")
|
||||
print(f"发件人:{from_addr}")
|
||||
print(f"邮件标题:{subject}")
|
||||
print("========================================")
|
||||
|
||||
# 正文解析告警字段
|
||||
body = get_email_content(msg)
|
||||
alert_name, instance, severity = parse_alert_info(body)
|
||||
if not alert_name:
|
||||
print(f"邮件{idx}未识别到【告警名称】关键字,跳过")
|
||||
continue
|
||||
|
||||
# 区分触发/恢复告警
|
||||
alert_type = 1
|
||||
if "恢复" in subject or "resolved" in subject.lower():
|
||||
alert_type = 2
|
||||
|
||||
now = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
sql = """
|
||||
INSERT INTO alert_log
|
||||
(mail_uid, alert_type, alert_name, instance, severity, starts_at, ends_at, content, receive_time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
cursor.execute(sql, (mail_uid, alert_type, alert_name, instance, severity, now, None, body, now))
|
||||
db.commit()
|
||||
print(f"入库成功 | 告警:{alert_name} 实例:{instance}")
|
||||
|
||||
pop_conn.quit()
|
||||
cursor.close()
|
||||
db.close()
|
||||
print("\n本次抓取全部完成")
|
||||
|
||||
if __name__ == "__main__":
|
||||
crawl_mail()
|
||||
@@ -0,0 +1,140 @@
|
||||
import poplib
|
||||
import ssl
|
||||
import email
|
||||
from email.header import decode_header
|
||||
import time
|
||||
import pymysql
|
||||
|
||||
# 关闭SSL校验,解决老Python握手重置
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
# ========== 邮箱配置 自行修改 ==========
|
||||
MAIL_HOST = "pop.163.com"
|
||||
MAIL_PORT = 995
|
||||
MAIL_USER = "lyudream@163.com"
|
||||
MAIL_PWD = "DVZxyF5NKCkR6fL5"
|
||||
|
||||
# ========== 本地MariaDB配置 ==========
|
||||
DB_HOST = "127.0.0.1"
|
||||
DB_USER = "root"
|
||||
DB_PWD = "hp93000"
|
||||
DB_NAME = "alert_mail_stat"
|
||||
|
||||
# 解码邮件标题、正文
|
||||
def decode_str(s):
|
||||
value, charset = decode_header(s)[0]
|
||||
if charset:
|
||||
value = value.decode(charset)
|
||||
return value
|
||||
|
||||
# 获取邮件正文
|
||||
def get_email_content(msg):
|
||||
content = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
content_type = part.get_content_type()
|
||||
content_disposition = str(part.get("Content-Disposition"))
|
||||
if content_type == 'text/plain' and 'attachment' not in content_disposition:
|
||||
payload = part.get_payload(decode=True)
|
||||
charset = part.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
break
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
charset = msg.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
return content
|
||||
|
||||
# 简单解析告警关键字(适配Alertmanager中文邮件模板:告警名称、实例、级别)
|
||||
def parse_alert_info(text):
|
||||
alert_name = ""
|
||||
instance = ""
|
||||
severity = "unknown"
|
||||
lines = text.splitlines()
|
||||
for line in lines:
|
||||
if "告警名称" in line:
|
||||
alert_name = line.split(":")[-1].strip()
|
||||
if "实例" in line:
|
||||
instance = line.split(":")[-1].strip()
|
||||
if "级别" in line:
|
||||
s_val = line.split(":")[-1].strip()
|
||||
if s_val.lower() in ["critical", "严重"]:
|
||||
severity = "critical"
|
||||
elif s_val.lower() in ["warning", "警告"]:
|
||||
severity = "warning"
|
||||
return alert_name, instance, severity
|
||||
|
||||
# 主抓取逻辑
|
||||
def crawl_mail():
|
||||
# 连接数据库
|
||||
db = pymysql.connect(host=DB_HOST, user=DB_USER, password=DB_PWD, database=DB_NAME, charset='utf8mb4')
|
||||
cursor = db.cursor()
|
||||
|
||||
# 连接POP3邮箱
|
||||
pop_conn = poplib.POP3_SSL(MAIL_HOST, MAIL_PORT)
|
||||
pop_conn.user(MAIL_USER)
|
||||
pop_conn.pass_(MAIL_PWD)
|
||||
total_num, total_size = pop_conn.stat()
|
||||
print(f"当前邮箱总邮件数量: {total_num}")
|
||||
|
||||
if total_num == 0:
|
||||
print("暂无新邮件")
|
||||
pop_conn.quit()
|
||||
db.close()
|
||||
return
|
||||
|
||||
# 从最新一封开始遍历
|
||||
for idx in range(total_num, 0, -1):
|
||||
# 获取邮件原始内容
|
||||
resp, raw_lines, octet = pop_conn.retr(idx)
|
||||
raw_msg = b'\r\n'.join(raw_lines).decode('utf-8', errors='ignore')
|
||||
msg = email.message_from_string(raw_msg)
|
||||
|
||||
# 生成唯一标识去重
|
||||
mail_uid = msg.get("Message-ID", str(time.time()))
|
||||
|
||||
# 查重,避免重复入库
|
||||
cursor.execute("SELECT id FROM alert_log WHERE mail_uid=%s", (mail_uid,))
|
||||
if cursor.fetchone():
|
||||
continue
|
||||
|
||||
# 解析标题、发件人
|
||||
subject = decode_str(msg.get("Subject", ""))
|
||||
from_addr = msg.get("From", "")
|
||||
# 过滤非告警发件人(自行修改匹配你的Alertmanager发件地址)
|
||||
if "prometheusalert" not in from_addr.lower():
|
||||
continue
|
||||
|
||||
# 正文解析告警字段
|
||||
body = get_email_content(msg)
|
||||
alert_name, instance, severity = parse_alert_info(body)
|
||||
if not alert_name:
|
||||
print(f"邮件{idx}未识别到告警,跳过")
|
||||
continue
|
||||
|
||||
# 区分触发/恢复告警
|
||||
alert_type = 1
|
||||
if "恢复" in subject or "resolved" in subject.lower():
|
||||
alert_type = 2
|
||||
|
||||
now = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
sql = """
|
||||
INSERT INTO alert_log
|
||||
(mail_uid, alert_type, alert_name, instance, severity, starts_at, ends_at, content, receive_time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
cursor.execute(sql, (mail_uid, alert_type, alert_name, instance, severity, now, None, body, now))
|
||||
db.commit()
|
||||
print(f"入库成功 | 告警:{alert_name} 实例:{instance}")
|
||||
|
||||
pop_conn.quit()
|
||||
cursor.close()
|
||||
db.close()
|
||||
print("本次抓取完成\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
crawl_mail()
|
||||
@@ -0,0 +1,77 @@
|
||||
import poplib
|
||||
import ssl
|
||||
import email
|
||||
from email.header import decode_header
|
||||
|
||||
# SSL兼容修复
|
||||
try:
|
||||
ctx = ssl._create_unverified_context
|
||||
except:
|
||||
ctx = None
|
||||
if ctx:
|
||||
ssl._create_default_https_context = ctx
|
||||
|
||||
# ========= 修改这里你的邮箱信息 =========
|
||||
MAIL_HOST = "pop.163.com"
|
||||
MAIL_PORT = 995
|
||||
MAIL_USER = "lyudream@163.com"
|
||||
MAIL_PWD = "DVZxyF5NKCkR6fL5"
|
||||
|
||||
def decode_text(s):
|
||||
value, charset = decode_header(s)[0]
|
||||
if charset:
|
||||
value = value.decode(charset)
|
||||
return value
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== 开始连接pop.163.com:995 ===")
|
||||
try:
|
||||
pop = poplib.POP3_SSL(MAIL_HOST, MAIL_PORT)
|
||||
print("连接服务器成功,正在登录...")
|
||||
pop.user(MAIL_USER)
|
||||
pop.pass_(MAIL_PWD)
|
||||
print("登录邮箱成功!")
|
||||
|
||||
total, _ = pop.stat()
|
||||
print(f"邮箱共有邮件:{total} 封\n")
|
||||
if total == 0:
|
||||
print("邮箱无邮件")
|
||||
pop.quit()
|
||||
exit()
|
||||
|
||||
# 从最新邮件遍历
|
||||
for i in range(total, 0, -1):
|
||||
resp, lines, octet = pop.retr(i)
|
||||
msg_raw = b"\r\n".join(lines).decode("utf-8", errors="ignore")
|
||||
msg = email.message_from_string(msg_raw)
|
||||
|
||||
subject = decode_text(msg.get("Subject", ""))
|
||||
from_addr = msg.get("From", "")
|
||||
|
||||
# 取正文
|
||||
body = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
t = part.get_content_type()
|
||||
disp = str(part.get("Content-Disposition"))
|
||||
if t == "text/plain" and "attachment" not in disp:
|
||||
payload = part.get_payload(decode=True)
|
||||
body = payload.decode("utf-8", errors="ignore")
|
||||
break
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
body = payload.decode("utf-8", errors="ignore")
|
||||
|
||||
print("========================================")
|
||||
print(f"第{i}封邮件")
|
||||
print(f"发件人:{from_addr}")
|
||||
print(f"标题:{subject}")
|
||||
print(f"正文内容:\n{body}")
|
||||
print("========================================\n")
|
||||
|
||||
pop.quit()
|
||||
print("全部读取完成")
|
||||
|
||||
except Exception as e:
|
||||
print("连接/登录失败,错误信息:")
|
||||
print(str(e))
|
||||
Reference in New Issue
Block a user