Il modo migliore per tornare ad usare il potere della lxml dopo dover utilizzare una regex di trovare qualcosa in un documento HTML

StackOverflow https://stackoverflow.com/questions/2421396

Domanda

Sto cercando di strappare una parte di testo da un gran numero di documenti html (numeri nell'ordine delle centinaia di migliaia). I documenti sono in realtà forme, ma sono preparati da un gruppo molto ampio di organizzazioni diverse per cui v'è una variazione significativa nel modo in cui creare il documento. Ad esempio, i documenti sono divisi in capitoli. Potrei voler estrarre il contenuto del capitolo 5 da ogni documento in modo da poter analizzare il contenuto del capitolo. Inizialmente ho pensato che questo sarebbe stato facile ma si scopre che gli autori potrebbero utilizzare una serie di tabelle nidificate non tutto il documento di tenere il contenuto in modo che il capitolo n potrebbe essere visualizzato utilizzando i tag td all'interno di una tabella. Oppure potrebbero utilizzare altri elementi come i tag p tag H, tag div o qualsiasi altro elemento a livello di blocco.

Dopo aver tentato più volte di utilizzare lxml per aiutarmi a identificare l'inizio e la fine di ogni capitolo ho determinato che è molto più pulito per usare un'espressione regolare perché in ogni caso, non importa quale sia l'elemento che racchiude HTML è l'etichetta capitolo è sempre in forma di

>Chapter #

E 'un po' più complicato in quanto ci potrebbe essere qualche spazio vuoto o spazio unificatore rappresentato in modi diversi (o solo o spazi). Ciò nonostante è stato banale scrivere un'espressione regolare per identificare l'inizio di ogni sezione. (L'inizio di una sezione è la fine della sezione precedente.)

Ma ora voglio usare lxml per ottenere il testo fuori. Il mio pensiero è che non ho davvero altra scelta che camminare lungo la mia stringa per trovare il tag di chiusura per l'elemento che racchiude il testo che sto usando per trovare la relativa sezione.

Ecco qui è un esempio in cui l'elemento che tiene il nome del capitolo è un div

<div style="DISPLAY: block; MARGIN-LEFT: 0pt; TEXT-INDENT: 0pt; MARGIN-RIGHT: 0pt" align="left"><font style="DISPLAY: inline; FONT-WEIGHT: bold; FONT-SIZE: 10pt; FONT-FAMILY: Times New Roman">Chapter 1.&#160;&#160;&#160;Our Beginnings.</font></div>

Così sto immaginando che io comincerei nella posizione in cui ho trovato il match per il capitolo 1 e impostare un espressioni regolari per trovare il prossimo

</div|</td|</p|</h1 . . .

Quindi a questo punto ho identificato il tipo di elemento trattenendo il titolo del capitolo

posso usare la stessa logica per trovare tutto il testo che è dentro di quell'elemento che è impostato un'espressione regolare per aiutarmi a segno da

>Chapter 1.&#160;&#160;&#160;Our Beginnings.<

Così ho individuato dove il mio capitolo 1 inizia

che posso fare lo stesso per il capitolo 2 (che è dove Capitolo 1 finisce)

Ora sto immaginando che sto andando a tagliare il documento a partire dalla apertura del elemento che ho identificato come l'elemento della indica dove capitolo 1 inizia e termina poco prima dell'apertura del elemento che ho identificato come l'elemento che indica dove Capitolo 2 ha inizio. La stringa che ho identificato sarà poi alimentato a lxml di usare il suo potere per ottenere il contenuto.

Ho intenzione di tutti questi problemi perché ho letto più e più volte - mai usare un'espressione regolare per estrarre contenuti da documenti HTML e non ho colpito su un modo di essere il più precisi con lxml per identificare l'inizio e la fine posizioni per il testo che desidera estrarre. Ad esempio, posso mai essere certi che il sottotitolo del capitolo 1 è il nostro inizio potrebbe essere nostro canarino rosso. Lasciatemi dire che ho passato due giorni interi cercando con lxml essere sicuri che ho avuto l'inizio e gli elementi che terminano e ho potuto solo essere accurato <60% del tempo, ma un tempo molto breve espressione regolare mi ha dato più del 95% di successo.

ho la tendenza a rendere le cose più complicate del necessario quindi mi chiedo se qualcuno ha visto o risolto un problemi simili e se avessero un approccio (non i dettagli si mente) che vorrebbero offrire.

È stato utile?

Soluzione 3

Come temevo non c'è modo sistematico per usare lxml per identificare ed estrarre quello che mi serve. O h ben apprezzo tutti rintocchi. Nota: questo non è colpa di lxml, è colpa del codice HTML incoerente. Per esempio. Poiché un capitolo è una divisione ragionevole di un documento tutto il contenuto di un capitolo dovrebbe essere avvolto in un certo tipo di elemento. Probabilmente il più flessibile sarebbe un tag div con la successiva div essere il prossimo capitolo. Questo sarebbe un capitolo di un ramo dell'albero. Purtroppo, mentre circa il 20% dei documenti potrebbe essere che ben strutturato gli altri non sono.

ho potuto testare per ogni tipo di elemento che dovrebbe tenere il mio contenuto (div, p) e prendere tutti i suoi figli e tutti i suoi fratelli fino a ottenere al successivo elemento di quel tipo che dispone di informazioni che mi avvisa che siamo sono alla fine della sezione (all'inizio della sezione successiva). Ma questo sembra troppo lavoro quando io sono buono 95% del tempo o più con un'espressione regolare.

Grazie per tutte le risposte e commenti, come sempre ho learnded da loro.

Altri suggerimenti

A volte ci non è un percorso lineare per ottenere il contenuto quando si tratta di HTML male o in modo incoerente scritta.

Si potrebbe desiderare di guardare con lynx o uno dei browser basati su testo per il dump del contenuto della pagina, sia in un file, o per il tubo è nel codice, e poi elaborarlo. In alternativa, è possibile utilizzare lxml per caricare e analizzare la pagina, quindi estrarre il testo utilizzando TEXT_CONTENT () e andare dopo i capitoli tramite espressioni regolari.

Come si suol dire, GIGO - garbage in, garbage out, ed è il nostro lavoro come sviluppatori di girare quella spazzatura in oro. In questo modo può diventare piuttosto disordinato.

La cosa più semplice che suona come si potrebbe fare è iterate oltre tree.getroot (). Iterdescendants () alla ricerca di un nodo con node.text che corrisponde alla tua espressione regolare desiderato. Da quel punto, è possibile passare il nodo a una funzione che utilizza alcune euristiche ad hoc per determinare dove il testo è. (Forse se iterdescendants sulla radice è troppo lento è possibile utilizzare il metodo regex e tuffarsi in eTree per cercare di trovare una funzione f(text_position) -> node.)

Ad esempio, se si scopre che l'obiettivo era un //tr/td, si può passare a qualche subroutine tavolo-text-ricerca che ha esaminato il prossimo td in node.parent () per vedere se ha il testo che abbia un senso ( circa il capitolo di lunghezza, contenenti determinate parole, a prescindere). Allo stesso modo, è possibile effettuare alcune euristiche per trovare i dati in altri tag come div e p. Se vi trovate in un tag sconosciuto come font si può provare zampillante un numero limitato di livelli per trovare qualcosa che si sa come gestire - bisogna essere prudenti, non a ribollire troppo lontano, o immagino si potrebbe accidentalmente recuperare il testo da un altro capitolo.

Il nocciolo del problema sembra essere che si sta data mining che non è presentato a livello di codice in modo programmatico -. In questi casi, l'interazione umana è di solito necessario in una certa misura

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top