2012-04-20 12 views
10

Novità di Python qui. Voglio camminare attraverso un grande file mbox, analizzando i messaggi di posta elettronica. Posso farlo con:Analisi di file mbox in Python

import sys 
import mailbox 

def gen_summary(filename): 
    mbox = mailbox.mbox(filename) 
    for message in mbox: 
     subj = message['subject'] 
     print subj 

if __name__ == "__main__": 
    if len(sys.argv) != 2: 
     print 'Usage: python genarchivesum.py mbox' 
     sys.exit(1) 

    gen_summary(sys.argv[1]) 

Ma ho bisogno di più controllo. Devo essere in grado di ottenere la posizione in byte dell'inizio di una determinata email nel file mbox e ho anche bisogno di ottenere il numero di byte nel messaggio (come rappresentato sul disco). E poi in futuro, invece di iterare dall'inizio del file mbox, ho bisogno di essere in grado di cercare un dato messaggio e solo analizzarlo (quindi uno dei bisogni di ottenere la posizione dei byte sul disco). Questi sono file mbox di grandi dimensioni e l'efficienza è una preoccupazione.

Lo scopo di tutto questo è che posso generare un file di riepilogo, che contiene alcuni piccoli dettagli su ciascuna e-mail nella mbox, e quindi in futuro cercare in modo efficiente le singole e-mail all'interno della mbox.

+0

Non ho mai usato 'mailbox', ma ho appena letto' help (mailbox.mbox) '. Non puoi usare il metodo '.iterkeys()' per ottenere un iteratore di valori chiave e quindi usare i valori chiave per trovare i messaggi? Perché vuoi usare un indice di byte come chiave per trovare un messaggio invece di usare il modulo ... hai provato a usare il modulo per indicizzare i messaggi per chiave? Se l'hai provato ed è troppo lento o qualcosa del genere, ti preghiamo di dirlo. – steveha

+0

Dire che ho un mbox di 10.000 email. Non voglio dover leggere/analizzare/scorrere oltre 9,998 di loro quando voglio solo l'ultima email. Mi piacerebbe cercare fino a quel momento nel file mbox e leggere quel messaggio. –

+0

@MarkFletcher Hai funzionato? Se è così, per favore fatemelo sapere. – kingmakerking

risposta

8

Non ho provato questo, ma qualcosa di simile potrebbe funzionare per voi. Basta aprire il file (in modalità binaria in modo che i conteggi dei byte siano corretti) e scansionarlo, trovando i messaggi.

def is_mail_start(line): 
    return line.startswith("From ") 

def build_index(fname): 
    with open(fname, "rb") as f: 
     i = 0 
     b = 0 
     # find start of first message 
     for line in f: 
      b += len(line) 
      if is_mail_start(line): 
       break 
     # find start of each message, and yield up (index, length) of previous message 
     for line in f: 
      if is_mail_start(line): 
       yield (i, b) 
       i += b 
       b = 0 
      b += len(line) 
     yield (i, b) # yield up (index, length) of last message 

# get index as a list 
mbox_index = list(build_index(fname)) 

Una volta che avete l'indice, è possibile utilizzare il metodo .seek() su un oggetto file a cercare lì, e .read(length) sull'oggetto file per leggere un solo messaggio. Non sono sicuro di come utilizzerai il modulo mailbox con una stringa; Penso che sia pensato per lavorare su una cassetta postale sul posto. Forse c'è qualche altro modulo di analisi della posta che puoi usare.

+1

Ok, grazie. Immagino che userò qualcosa come questa strategia. btw, l'inizio di un'e-mail in un mbox inizia con "Da" (senza :). Posso usare email.Parser per analizzare l'email. Grazie. –

+0

Modifica la risposta per eliminare ":". Io * ho * detto di non averlo provato ... Buona fortuna per il tuo progetto e buon fine settimana! – steveha

+0

Per quello che vale, per gli utenti futuri, è in realtà entrambi, almeno sull'ultima versione di OSX. def is_mail_start (riga): \t return line.startswith ("From") e non line.startswith ("From:") – adammenges