Analisi di dati in formato fisso incorporati in HTML in Python
-
03-07-2019 - |
Domanda
Sto usando l'API dell'appengine di Google
from google.appengine.api import urlfetch
per recuperare una pagina web. Il risultato di
result = urlfetch.fetch("http://www.example.com/index.html")
è una stringa del contenuto html (in result.content). Il problema è che i dati che voglio analizzare non sono realmente in formato HTML, quindi non penso che usare un parser HTML Python funzionerà per me. Ho bisogno di analizzare tutto il testo normale nel corpo del documento HTML. L'unico problema è che urlfetch restituisce una singola stringa dell'intero documento HTML, rimuovendo tutte le nuove righe e gli spazi extra.
Modifica Ok, ho provato a recuperare un URL diverso e apparentemente urlfetch non elimina le nuove righe, era la pagina web originale che stavo cercando di analizzare che serviva il file HTML in quel modo ... MODIFICA FINE
Se il documento è simile a questo:
<html><head></head><body>
AAA 123 888 2008-10-30 ABC
BBB 987 332 2009-01-02 JSE
...
A4A 288 AAA
</body></html>
result.content sarà questo, dopo che urlfetch lo recupera:
'<html><head></head><body>AAA 123 888 2008-10-30 ABCBBB 987 2009-01-02 JSE...A4A 288 AAA</body></html>'
L'uso di un parser HTML non mi aiuterà con i dati tra i tag body, quindi avrei usato espressioni regolari per analizzare i miei dati, ma come puoi vedere l'ultima parte di una riga viene combinata con la prima parte di la riga successiva e non so come dividerlo. Ho provato
result.content.split('\n')
e
result.content.split('\r')
ma l'elenco risultante era tutto solo 1 elemento. Non vedo alcuna opzione nella funzione urlfetch di Google per non rimuovere le nuove righe.
Qualche idea su come posso analizzare questi dati? Forse dovrei prenderlo diversamente?
Grazie in anticipo!
Soluzione
Comprendo che il formato del documento è quello che hai pubblicato. In tal caso, sono d'accordo che un parser come Beautiful Soup potrebbe non essere una buona soluzione.
Presumo che tu stia già ottenendo i dati interessanti (tra i tag BODY) con un'espressione regolare come
import re
data = re.findall('<body>([^\<]*)</body>', result)[0]
quindi, dovrebbe essere facile come:
start = 0
end = 5
while (end<len(data)):
print data[start:end]
start = end+1
end = end+5
print data[start:]
(nota: non ho verificato questo codice rispetto ai casi limite e mi aspetto che fallisca. È solo qui per mostrare l'idea generica)
Altri suggerimenti
L'unico suggerimento che mi viene in mente è di analizzarlo come se avesse colonne a larghezza fissa. Le nuove righe non vengono prese in considerazione per HTML.
Se hai il controllo dei dati di origine, inseriscili in un file di testo anziché in HTML.
Una volta che hai il corpo del testo come una singola stringa lunga, puoi scomporlo come segue. Ciò presume che ogni record contenga 26 caratteri.
body= "AAA 123 888 2008-10-30 ABCBBB 987 2009-01-02 JSE...A4A 288 AAA"
for i in range(0,len(body),26):
line= body[i:i+26]
# parse the line
EDIT: la comprensione della lettura è una cosa desiderabile. Mi sono perso un po 'le linee che correvano insieme senza un separatore tra loro, che sarebbe un po' il punto di tutto questo, no? Quindi, non importa la mia risposta, in realtà non è pertinente.
Se sai che ogni riga è composta da 5 colonne separate da spazio, allora (una volta eliminato l'html) potresti fare qualcosa del genere (non testato):
def generate_lines(datastring):
while datastring:
splitresult = datastring.split(' ', 5)
if len(splitresult) >= 5:
datastring = splitresult[5]
else:
datastring = None
yield splitresult[:5]
for line in generate_lines(data):
process_data_line(line)
Ovviamente, puoi modificare il carattere diviso e il numero di colonne secondo necessità (eventualmente anche passandole nella funzione generatore come parametri aggiuntivi) e aggiungere la gestione degli errori come appropriato.
Ulteriori suggerimenti per dividere la stringa s
in blocchi di 26 caratteri:
Come elenco:
>>> [s[x:x+26] for x in range(0, len(s), 26)]
['AAA 123 888 2008-10-30 ABC',
'BBB 987 2009-01-02 JSE',
'A4A 288 AAA']
Come generatore:
>>> for line in (s[x:x+26] for x in range(0, len(s), 26)): print line
AAA 123 888 2008-10-30 ABC
BBB 987 2009-01-02 JSE
A4A 288 AAA
Sostituisci range ()
con xrange ()
in Python 2.x se s
è molto lungo.