Python3 - поврежденные почтовые файлы при парсинге - PullRequest
0 голосов
/ 07 августа 2020

Я скромный аналитик инфраструктуры / информации c, который старается работать умно и интересуется миром python! В настоящее время я запускаю сценарий python, чтобы прочитать старую базу данных файлов почты postfix, проанализировать некоторые поля и вставить их в базу данных SQL Server для индексации и быстрого поиска.

Однако после запуска финальной версии версия скрипта я наткнулся на кучу файлов, которые, казалось, были "повреждены" в процессе, таким образом, что некоторые файлы, похоже, имеют свое содержимое, перезаписанное кусками других почтовых файлов .

Любые идеи относительно того, почему это происходит?

Чтобы помочь, следующие подробности о скрипте:

Он устанавливает несколько переменных, например путь к папке, дата, время и учетные данные базы данных. Затем я определяю функцию для анализа данных из электронных писем, а другую - для преобразования файлов электронной почты из LATIN-1 / ISO-8859 в UTF-8.

Основная часть кода - al oop, в котором перечислены все файлы в данной папке и для каждого из перечисленных файлов проверяется, является ли это файлом электронной почты или обычным файлом.

  • Если это файл электронной почты, он проверяет кодировку.
  • Если это UTF-8, он запускает функцию синтаксического анализа и вставляет тада в базу данных. Если это файл LATIN-1, он преобразуется в UTF-8 и затем запускает функцию синтаксического анализа.
  • Если это не файл электронной почты, он переходит к следующему файлу.

Основная часть скрипта выглядит следующим образом:

#####################################
#########Start of main loop#########
#####################################
    
for file in os.listdir(folder_path):
        
    countertotal += 1
    date_time = strftime("%Y-%m-%d %H:%M:%S", localtime())
      
      
###Detects file type###
    
file_path = str(folder_path)+"/"+file
p1 = subprocess.Popen(["file", file_path], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["awk", '{print $2}'], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
file_type = p2.communicate()[0].rstrip()
 
###Detects file format/encoding####
        
file_path = str(folder_path)+"/"+file
p1 = subprocess.Popen(["file", file_path], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["awk", '{print $4}'], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
file_format = p2.communicate()[0].rstrip()
 
###Checks if the file is an email and acts depending on it´s encoding####

if (file_type.decode('utf-8') == "SMTP") or (file_type.decode('utf-8') != "SMTP" and re.match('([0-9]+)\.(.*)\.(.*)', str(file))):
    if (file_format.decode('utf-8') == 'ASCII' or file_format.decode('utf-8') == 'UTF-8'):
        try:
            ProcessEmail(file_path)
            counter += 1
      
         except:
             counterb +=1
             ex = sys.exc_info()[0]
             tb = textwrap.fill(traceback.format_exc(), 1000)
             print ("[ERRO]","[",date_time,"]: ","File: ", file, file=open(log_file_name, "a"))
             print ("[ERRO]","[",date_time,"]: ","File format: ", file_format, file=open(log_file_name, "a"))
             print ("[ERRO]","[",date_time,"]: ","Error type: ",ex, file=open(log_file_name, "a"))
             print ("[ERRO]","[",date_time,"]: ","Traceback: ", tb, file=open(log_file_name, "a"))
             pass
    
    elif (file_format.decode('utf-8') == 'ISO-8859'):
        try:
                   
            ConvertEmailIso(file_path) 
            ProcessEmail(file_path)
            print ("[INFO]","[",date_time,"]: ", file,"-", file_format.decode('utf-8'), "converted to UTF-8",file=open(log_file_name, "a"))        
            counter += 1
            counterd += 1
                    
        except:
            counterb +=1
            ex = sys.exc_info()[0]
            tb = textwrap.fill(traceback.format_exc(), 1000)
            print ("[ERRO]","[",date_time,"]: ","File: ", file, file=open(log_file_name, "a"))
            print ("[ERRO]","[",date_time,"]: ","File format: ", file_format, file=open(log_file_name, "a"))
            print ("[ERRO]","[",date_time,"]: ","Error type: ",ex, file=open(log_file_name, "a"))
            print ("[ERRO]","[",date_time,"]: ","Traceback: ", tb, file=open(log_file_name, "a"))
            pass
                
    else:
        print ("[INFO]","[",date_time,"]: ", file, "Is not an SMTP file", file=open(log_file_name, "a"))
        counterc += 1
    
####################################      
##########End of main loop##########
####################################

Определены следующие функции:

############################################################################################
###Function that parses data from mail files of SMTP and ASCII format and  UTF-8 encoding ##
############################################################################################

def ProcessEmail(file_path):
    h1 = subprocess.Popen(["md5sum", file_path], stdout=subprocess.PIPE)
    h2 = subprocess.Popen(["awk", '{print $1}'], stdin=h1.stdout, stdout=subprocess.PIPE)
    h1.stdout.close()
    hash_key = h2.communicate()[0].decode('utf-8')

    with open(file_path, 'rb') as fp:

        headers = BytesParser(policy=default).parse(fp)
        content = fp.read()
        new_format = "%Y-%m-%d %H:%M:%S"
        original_format = "%d %b %Y %H:%M:%S %z"
        subject_truncated = format(headers['subject'])[:200]

        try:
            original_date = str(format(headers['Date']))[5:31]
            converted_date = datetime.datetime.strptime(original_date, original_format).strftime(new_format)

        except:
            alternate_date = re.findall('\d\d\s(?:[A-Z][a-z][a-z])\s\d{4}\s[0-9]+:[0-9]+:[0-9]+\s\-[0-9]+', open(file_path).read())[0]
            converted_date = datetime.datetime.strptime(alternate_date, original_format).strftime(new_format)

        cursorprod.execute("insert into MAIL_AUDIT.dbo.mail_index (mail_hash,mail_to,mail_from,mail_subject,mail_date,mail_path) values (?,?,?,?,?,?)", hash_key, format(headers['to'])[0:500], format(headers['from'])[0:500], subject_truncated, converted_date, file_path)
        connprod.commit()

############################################################        

#############################################################
###Converts the email file from  ISO-8891/LATIN-1 to UTF-8###
#############################################################

def ConvertEmailIso(file_path):

    with io.open(file_path, 'r', encoding='latin-1') as f:
        text = f.read()
    
    with io.open(file_path, 'w', encoding='utf8') as f:
        f.write(text)

Я записываю некоторую информацию, включая обнаруженные ошибки. В журнале я смог увидеть ошибки, в основном связанные с функцией синтаксического анализа + вставки (скрипт не может вставить в базу данных, потому что нет даты, проанализированной для поврежденных писем). Скрипт, оба почтовых файла и журнал находятся по ссылке. ниже:

https://github.com/armandelli/Python_bugs/tree/master/corrupted_files

Большое спасибо!

...