目录
目标:我要提取 发件人(From)、收件人(To)、邮件主题(Subject)、邮件正文(zhengwen) 作为邮件特征,然后输入到线性分类模型中进行训练
首先是这四个特征提取的部分
发件人
收件人
邮件主题
邮件正文
获取 标签--路径 对照表
把这一部分的全部的代码放这儿:
~~~~~~~~~~~待更新~~~~~~~~~~~~~~~~~~~~~~~~~~~
数据集是这样的
data里是数据文件
full里是index文件,存放哪个路径的文件是什么类型
index文件 (类型--文件路径 对照表)
通过上面的邮件的图,可以看到From、Subject中有用gb2312和base64编码的部分,需要进行解码
另外 如果多打开几个文件可以观察到 From字段的情况比较复杂,我观察到了这四种(列在下面),其实可能不止这四种格式
From: [email protected]
From: "yan"<(8月27-28,上海)培训课程>
From: [email protected]"
From: =?GB2312?B?zuLmw+bD?=
我做的处理步骤大体如下:
解码部分优先用gb2312解 ,如果报异常 就在用gbk解,如果还是报异常,就直接赋空串
def From_email(email): # email是整封邮件的内容字符串
# 发件人
# 先提取From后的所有内容
try:
From_raw = re.search(r'From: (.*)', email).group(1)
except:
From_raw = ''
From = ''
# 先看看有没有加密部分 有加密部分就给他解密
name = re.search(r'=\?GB2312\?B\?(.*)\?=', From_raw, re.I) # name保存加密部分
if name is None: # 没有加密部分
name = ''
# 没有加密部分 就保留串的所有内容
From = From_raw
else: # 有加密部分
name = name.group(1)
try:
name = base64.b64decode(name).decode('gb2312')
except:
try:
name = base64.b64decode(name).decode('gbk')
except:
name = ''
From = name + re.search(r'\?=(.*)', From_raw).group(1)
# print('From: ', From)
return From
存在以TO: 开头的情况,加个re.I 就不区分大小写了
def To_email(email):
# 收件人
To = re.search(r'^To: (.*)', email, re.M | re.I).group(1) # re.M 从每行文本开头的位置开始匹配
# print('To: ', To)
return To
处理这个字段的流程基本和From字段一样,Subject的格式比较统一,基本都是加密形式
def Subject_email(email):
# 主题
Subject = re.search(r'=\?gb2312\?B\?(.*)\?=', email)
if Subject is None:
Subject = ''
else: # subject 有内容
Subject = Subject.group(1)
Subject = base64.b64decode(Subject) # 解密
try:
Subject = Subject.decode('gb2312') # 解码
except:
try:
Subject = Subject.decode('gbk') # 解码
except:
Subject = ''
# print('Subject: ', Subject)
return Subject
有两个换行符后是正文的,也有三个换行符后是正文的情况,这里就直接:第一次成功遇到两个换行符,就返回之后的所有内容,re.S的作用是一直到正文底部,而不是\n\n随后的一行(单拎出来自己运行一下代码就懂我的意思了)
def zhengwen_email(email):
# 正文
zhengwen = re.search(r'\n\n(.*)', email, re.S).group(1)
zhengwen = clean_str(zhengwen) # 剔除了非中文字符
# print('正文: \n', zhengwen)
return zhengwen
然后对正文部分有一个去掉非中文字符的处理
# 去掉非中文字符
def clean_str(string):
string = re.sub(r"[^\u4e00-\u9fff]", " ", string)
string = re.sub(r"\s{2,}", " ", string) # 能直接变成一个字符串 可以在txt中写成一行
return string.strip()
所以在主函数中调用上面四个函数就可以了
path = 'C:\\Users\\zhang\\Desktop\\trec06c\\data' # trec06c数据集所在路径
dirs = os.listdir(path)# ['000','001',...]
for dir in dirs: # 文件夹
dir_path = path + '\\' + dir
files = os.listdir(dir_path) # ['000','001',...]
for file in files: # 数据文件
file_path = dir_path + '\\' + file
f = codecs.open(file_path, 'r', 'gbk', errors='ignore')
email = '' # 存储一封邮件的所有内容
for line in f: # 每一行
email += line
print(index)
# 提取特征
# 发件人
From = From_email(email)
# 收件人
To = To_email(email)
# 主题
Subject = Subject_email(email)
# 正文
zhengwen = zhengwen_email(email)
存成dataframe类型,另外把标签从字符串弄成了0,1数值 (1是垃圾邮件 0是正常邮件)
def Index_File():
"""index文件 路径--标签 对照表"""
index_file = 'C:\\Users\\zhang\\Desktop\\trec06c\\full\\index'
f = codecs.open(index_file, 'r', 'gbk', errors='ignore')
table = defaultdict(list)
for line in f:
label, path = line.strip().split()
if label == 'spam': # 是垃圾邮件
label = 1
else:
label = 0
table['label'].append(label)
table['path'].append(path)
table = pd.DataFrame(data=table)
return table
接下来就将提取到的四个特征存成文件,对照着 标签--路径 对照表,也就是table,判断是哪类,然后将垃圾邮件存入spam.txt中,将正常邮件存入ham.txt中
一封邮件四个特征存成一行,用 ‘<<<<<’ 串进行分隔
if __name__ == '__main__':
"""主函数"""
# 获取 路径--标签 对照表
table = Index_File()
i = 0
j = 0
path = 'C:\\Users\\zhang\\Desktop\\trec06c\\data'
dirs = os.listdir(path)# ['000','001',...]
for dir in dirs: # 文件夹
dir_path = path + '\\' + dir
files = os.listdir(dir_path) # ['000','001',...]
for file in files: # 数据文件
file_path = dir_path + '\\' + file
f = codecs.open(file_path, 'r', 'gbk', errors='ignore')
email = '' # 存储一封邮件的所有内容
for line in f: # 每一行
email += line
# 打印文件路径
index = '../data/' + dir + '/' + file
print(index)
# 提取特征
# 发件人
From = From_email(email)
# 收件人
To = To_email(email)
# 主题
Subject = Subject_email(email)
# 正文
zhengwen = zhengwen_email(email)
print('*'*100)
f.close()
flag = table[table['path'] == index]['label'].values[0]
if flag == 1:
f = open('.\\trec06c\\data\\spam.txt', 'a', encoding='utf8')
i += 1
elif flag == 0:
f = open('.\\trec06c\\data\\ham.txt', 'a', encoding='utf8')
j += 1
f.write(From + '<<<<<' + To + '<<<<<' + Subject + '<<<<<' + zhengwen + '\n') # 保存成一行用<<<<<分隔
f.close()
处理完成后,我手动将spam.txt 和 ham.txt 合并成了 mailcorous.txt 文件,正常邮件在前,垃圾邮件在后。稍微的看一下这个文件哈(见下图)
mailcorous.txt
因为From、To、Subject里面的内容是中英文混杂的状态,正文全是中文,这个时候如果将中文和英文分开来进行分词很麻烦,我就试了试能不能偷个懒儿,哈哈~
我们都知道jieba可以处理纯中文文本,我就想看看jieba能不能同时对中英文进行分词。然后,随便取了mailcorous.txt中的两行,也就是两封邮件的内容进行测试。
测试一下 四个特征在一行当中,且中英文混杂,且不去掉分隔符 进行分词
import jieba
from sklearn.feature_extraction.text import CountVectorizer
text = """
"pan" <<<<<<<<
结果发现,我敲~!!可以哎~!! 哈哈~
process.py
# coding=gbk
import os
import codecs
import re
import base64
import pandas as pd
from collections import defaultdict
# 去掉非中文字符
def clean_str(string):
string = re.sub(r"[^\u4e00-\u9fff]", " ", string)
string = re.sub(r"\s{2,}", " ", string) # 能直接变成一个字符串 可以在txt中写成一行
return string.strip()
def Index_File():
"""index文件 路径--标签 对照表"""
index_file = 'C:\\Users\\zhang\\Desktop\\trec06c\\full\\index'
f = codecs.open(index_file, 'r', 'gbk', errors='ignore')
table = defaultdict(list)
for line in f:
label, path = line.strip().split()
if label == 'spam': # 是垃圾邮件
label = 1
else:
label = 0
table['label'].append(label)
table['path'].append(path)
table = pd.DataFrame(data=table)
return table
#提取四个特征
def From_email(email):
# 发件人
# 先提取From后的所有内容
try:
From_raw = re.search(r'From: (.*)', email).group(1)
except:
From_raw = ''
From = ''
# 先看看有没有加密部分 有加密部分就给他解密
name = re.search(r'=\?GB2312\?B\?(.*)\?=', From_raw, re.I) # name保存加密部分
if name is None: # 没有加密部分
name = ''
# 没有加密部分 就保留串的所有内容
From = From_raw
else: # 有加密部分
name = name.group(1)
try:
name = base64.b64decode(name).decode('gb2312')
except:
try:
name = base64.b64decode(name).decode('gbk')
except:
name = ''
From = name + re.search(r'\?=(.*)', From_raw).group(1)
# print('From: ', From)
return From
def To_email(email):
# 收件人
To = re.search(r'^To: (.*)', email, re.M | re.I).group(1) # re.M 从每行文本开头的位置开始匹配
# print('To: ', To)
return To
def Subject_email(email):
# 主题
Subject = re.search(r'=\?gb2312\?B\?(.*)\?=', email)
if Subject is None:
Subject = ''
else: # subject 有内容
Subject = Subject.group(1)
Subject = base64.b64decode(Subject) # 解密
try:
Subject = Subject.decode('gb2312') # 解码
except:
try:
Subject = Subject.decode('gbk') # 解码
except:
Subject = ''
# print('Subject: ', Subject)
return Subject
def zhengwen_email(email):
# 正文
zhengwen = re.search(r'\n\n(.*)', email, re.S).group(1)
zhengwen = clean_str(zhengwen) # 剔除了非中文字符
# print('正文: \n', zhengwen)
return zhengwen
if __name__ == '__main__':
"""主函数"""
# 获取 路径--标签 对照表
table = Index_File()
i = 0
j = 0
path = 'C:\\Users\\zhang\\Desktop\\trec06c\\data'
dirs = os.listdir(path)# ['000','001',...]
for dir in dirs: # 文件夹
dir_path = path + '\\' + dir
files = os.listdir(dir_path) # ['000','001',...]
for file in files: # 数据文件
file_path = dir_path + '\\' + file
f = codecs.open(file_path, 'r', 'gbk', errors='ignore')
email = '' # 存储一封邮件的所有内容
for line in f: # 每一行
email += line
# 打印文件路径
index = '../data/' + dir + '/' + file
print(index)
# 提取特征
# 发件人
From = From_email(email)
# 收件人
To = To_email(email)
# 主题
Subject = Subject_email(email)
# 正文
zhengwen = zhengwen_email(email)
print('*'*100)
f.close()
flag = table[table['path'] == index]['label'].values[0]
if flag == 1:
f = open('.\\trec06c\\data\\spam.txt', 'a', encoding='utf8')
i += 1
elif flag == 0:
f = open('.\\trec06c\\data\\ham.txt', 'a', encoding='utf8')
j += 1
f.write(From + '<<<<<' + To + '<<<<<' + Subject + '<<<<<' + zhengwen + '\n') # 保存成一行用<<<<<分割
f.close()
接下来就是分词转化为词向量然后输入到线性模型里面训练的步骤啦~
哎呀到饭点儿了,去吃饭了喽~,回来接着写~
欢迎转发~ 评论讨论~ 点赞~
转载请注明出处~
谢谢大家的支持!~ O(∩_∩)O~
后续来了:
垃圾邮件分类(trec06c数据集)特征分词、特征向量化、模型训练(https://blog.csdn.net/qq_39321513/article/details/112021355)