2013-04-27 35 views
6

Ho una serie di file HTML che vengono analizzati in un singolo file di testo utilizzando Beautiful Soup. I file HTML sono formattati in modo tale che la loro produzione è sempre tre righe all'interno del file di testo, in modo da l'output sarà simile a:Analizzare un file di testo semplice in un file CSV utilizzando Python

Hello! 
How are you? 
Well, Bye! 

ma potrebbe altrettanto facilmente essere

83957 
And I ain't coming back! 
hgu39hgd 

In altre parole , i contenuti dei file HTML non sono veramente standard su ognuno di essi, ma producono sempre tre righe.

Così, mi chiedevo dove dovrei cominciare se voglio poi prendere il file di testo che viene prodotto da Beautiful Soup e analizzare che in un file CSV con le colonne come ad esempio (utilizzando gli esempi di cui sopra):

Title Intro Tagline 
Hello! How are you? Well, Bye! 
83957 And I ain't coming back! hgu39hgd 
codice

il Python per lo stripping il codice HTML dai file di testo è questo:

import os 
import glob 
import codecs 
import csv 
from bs4 import BeautifulSoup 

path = "c:\\users\\me\\downloads\\" 

for infile in glob.glob(os.path.join(path, "*.html")): 
    markup = (infile) 
    soup = BeautifulSoup(codecs.open(markup, "r", "utf-8").read()) 
    with open("extracted.txt", "a") as myfile: 
     myfile.write(soup.get_text()) 

E io raccogliere posso usare questo per impostare le colonne nel mio file CSV:

csv.put_HasColumnNames(True) 

csv.SetColumnName(0,"title") 
csv.SetColumnName(1,"intro") 
csv.SetColumnName(2,"tagline") 

Dove sto disegnando in bianco è come iterare attraverso il file di testo (extracted.txt) una riga alla volta e, quando arrivo a una nuova riga, impostarla sulla cella corretta nel file CSV. Le prime diverse righe del file sono vuote e ci sono molte righe vuote tra ogni raggruppamento di testo. Quindi, prima avrei bisogno di aprire il file e leggerlo:

file = open("extracted.txt") 

for line in file.xreadlines(): 
    pass # csv.SetCell(0,0 X) (obviously, I don't know what to put in X) 

Inoltre, non so come dire Python per tenere solo la lettura del file, e l'aggiunta al file CSV finché non è finito. In altre parole, non c'è modo di sapere esattamente quante linee totali saranno nelle file HTML, e quindi non posso solo csv.SetCell(0,0) to cdv.SetCell(999,999)

+1

'.xreadlines' più,' per la linea nel file' – jamylak

+0

Non sono sicuro di aver capito cosa stai cercando di fare. Stai cercando di leggere il file 'extracted.txt', ignorare le righe vuote e posizionare ciascun gruppo di tre linee in una singola riga in un file CSV? – icktoofay

+0

Ah, quasi. Sto cercando di leggere la prima di tre righe e impostarla su "titolo" e la seconda di tre righe e impostarla su "intro" e sulla terza di tre righe e impostarla su "tagline" e quindi saltare lo spazio bianco fino a quando non arrivo alle tre righe successive, e poi lo rifaccio. –

risposta

7

Non sono completamente sicuro di quale libreria CSV si sta utilizzando, ma non sembra Python's built-in one. Comunque, ecco come lo farei:

import csv 
import itertools 

with open('extracted.txt', 'r') as in_file: 
    stripped = (line.strip() for line in in_file) 
    lines = (line for line in stripped if line) 
    grouped = itertools.izip(*[lines] * 3) 
    with open('extracted.csv', 'w') as out_file: 
     writer = csv.writer(out_file) 
     writer.writerow(('title', 'intro', 'tagline')) 
     writer.writerows(grouped) 

Questo tipo di rende una pipeline. Prima ottiene i dati dal file, quindi rimuove tutti gli spazi bianchi dalle linee, quindi rimuove le eventuali righe vuote, quindi le raggruppa in gruppi di tre e quindi (dopo aver scritto l'intestazione CSV) scrive quei gruppi nel file CSV.

di combinare le ultime due colonne come lei ha ricordato nei commenti, è possibile modificare il writerow chiamata nel modo più ovvio e il writerows a: nessuno uso

writer.writerows((title, intro + tagline) for title, intro, tagline in grouped) 
+1

Secondo me, penso che il generatore sia più chiaro (come avevi prima della modifica). –

+1

@OscarMederos: Aveva un bug: non eliminava le newline prima del raggruppamento. Ciononostante, credo di poterlo riscrivere ancora con la comprensione del generatore. – icktoofay

+0

@icktoofay Non ho mai sentito itertools, grazie per avermi indicato in quel modo. Quando eseguo questo, ottengo l'errore: file "csvify.py", line5, in righe = itertools.ifilter (bool, itertools.imap (str.strip, in_file)) AttributeError: 'oggetto' modulo 'deve attribuire' ifilter ' –

3

Forse non ho capito che si correttamente, ma si può fare:

file = open("extracted.txt") 

# if you don't want to do .strip() again, just create a list of the stripped 
# lines first. 
lines = [line.strip() for line in file if line.strip()] 

for i, line in enumerate(lines): 
    csv.SetCell(i % 3, line) 
+0

Questo è stato abbastanza vicino, ma @icktoofay l'ha capito. Comunque grazie per il tuo aiuto! –

+0

@ZacBrown Cosa intendi per * abbastanza vicino *? Hai provato? Ho solo cercato di mantenerlo simile a quello che stavi cercando (usando 'csv.SetCell', ecc.). A proposito, ho svalutato la sua risposta;) –

Problemi correlati