Удаление ненужных символов, которые нарушают readline () - PullRequest
1 голос
/ 21 марта 2019

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

Я столкнулся с одной странной проблемой, когда несколько файлов, которые я анализирую, выбрасывают странные символы в середине строки, разрушая мой анализ возвратов readline (). При чтении в текстовом редакторе рассматриваемая строка выглядит нормально, но readline () читает символ '=' и два символа \ n прямо в середине IP-адреса.

, например

Normal return from readline():
"IP Address: xxx.xxx.xxx.xxx"

Broken readline() return:
"IP Address: xxx.xxx.xxx="

The next two lines after that being:
""
".xxx"

Есть идеи, как мне это обойти? Я действительно не могу контролировать, какая проблема может быть причиной этого, мне просто нужно разобраться с этим, не становясь слишком сумасшедшим.

Соответствующая функция, для справки (я знаю, что это беспорядок):

def getIP(em):
ce = codecs.open(em, encoding='latin1')
iplabel = ""
while  not ("Torrent Hash Value: " in iplabel):
    iplabel = ce.readline()

ipraw = ce.readline()
if ("File Size" in ipraw):
    ipraw = ce.readline()

ip = re.findall( r'[0-9]+(?:\.[0-9]+){3}', ipraw)
if ip:
    return ip[0]
    ce.close()
else:
    ipraw = ce.readline()
    ip = re.findall( r'[0-9]+(?:\.[0-9]+){3}', ipraw)
    if ip:
        return ip[0]
        ce.close()
    else:
        return ("No IP found in: " + ipraw)
        ce.close()

Ответы [ 2 ]

0 голосов
/ 22 марта 2019

Кажется вероятным, что по крайней мере некоторые из обрабатываемых вами электронных писем были закодированы как цитата-печатная .

Это кодирование используется для обеспечения переносимости 8-битных символьных данных по 7-битным (только для ASCII) системам, но также обеспечивает фиксированную длину строки в 76 символов.Это реализуется путем вставки мягкого разрыва строки, состоящего из «=», за которым следует маркер конца строки.

Python предоставляет модуль quopri для обработки кодирования и декодирования из цитируемой печати.Декодирование ваших данных из quoted-printable удалит эти мягкие разрывы строк.

В качестве примера, давайте использовать первый абзац вашего вопроса.

>>> import quopri
>>> s = """I'm writing a small script to run through large folders of copyright notice emails and finding relevant information (IP and timestamp). I've already found ways around a few little formatting hurdles (sometimes IP and TS are on different lines, sometimes on same, sometimes in different places, timestamps come in 4 different formats, etc.)."""

>>> # Encode to latin-1 as quopri deals with bytes, not strings.
>>> bs = s.encode('latin-1')

>>> # Encode
>>> encoded = quopri.encodestring(bs)
>>> # Observe the "=\n" inserted into the text.
>>> encoded
b"I'm writing a small script to run through large folders of copyright notice=\n emails and finding relevant information (IP and timestamp). I've already f=\nound ways around a few little formatting hurdles (sometimes IP and TS are o=\nn different lines, sometimes on same, sometimes in different places, timest=\namps come in 4 different formats, etc.)."

>>> # Printing without decoding from quoted-printable shows the "=".
>>> print(encoded.decode('latin-1'))
I'm writing a small script to run through large folders of copyright notice=
 emails and finding relevant information (IP and timestamp). I've already f=
ound ways around a few little formatting hurdles (sometimes IP and TS are o=
n different lines, sometimes on same, sometimes in different places, timest=
amps come in 4 different formats, etc.).

>>> # Decode from quoted-printable to remove soft line breaks.
>>> print(quopri.decodestring(encoded).decode('latin-1'))
I'm writing a small script to run through large folders of copyright notice emails and finding relevant information (IP and timestamp). I've already found ways around a few little formatting hurdles (sometimes IP and TS are on different lines, sometimes on same, sometimes in different places, timestamps come in 4 different formats, etc.).

Чтобы правильно декодировать, все тело сообщениянеобходимо обработать, что противоречит вашему подходу с использованием readline.Одним из способов решения этой проблемы является загрузка декодированной строки в буфер:

import io

def getIP(em):
    with open(em, 'rb') as f:
        bs = f.read()
    decoded = quopri.decodestring(bs).decode('latin-1')

    ce = io.StringIO(decoded)
    iplabel = ""
    while  not ("Torrent Hash Value: " in iplabel):
        iplabel = ce.readline()
        ...

Если ваши файлы содержат полные электронные письма, включая заголовки, то с помощью инструментов модуля email это можно будет обработать.декодирование автоматически.

import email
from email import policy

with open('message.eml') as f:
    s = f.read()
msg = email.message_from_string(s, policy=policy.default)
body = msg.get_content()
0 голосов
/ 21 марта 2019

Решено, если у кого-то еще есть подобная проблема, сохраните каждую строку в виде строки, объедините их вместе и выньте () их, учитывая символы \ r и \ n. Мое решение немного спагетти, но предотвращает ненужные регулярные выражения для каждого файла:

def getIP(em):
ce = codecs.open(em, encoding='latin1')
iplabel = ""
while  not ("Torrent Hash Value: " in iplabel):
    iplabel = ce.readline()

ipraw = ce.readline()
if ("File Size" in ipraw):
    ipraw = ce.readline()

ip = re.findall( r'[0-9]+(?:\.[0-9]+){3}', ipraw)
if ip:
    return ip[0]
    ce.close()
else:
    ipraw2 = ce.readline()                              #made this a new var
    ip = re.findall( r'[0-9]+(?:\.[0-9]+){3}', ipraw2)
    if ip:
        return ip[0]
        ce.close()
    else:
        ipraw = ipraw + ipraw2                          #Added this section
        ipraw = re.sub(r'(=\r*\n)', '', ipraw)          #
        ip = re.findall( r'[0-9]+(?:\.[0-9]+){3}', ipraw)
        if ip:
            return ip[0]
            ce.close()
        else:
            return ("No IP found in: " + ipraw)
            ce.close()
...