La meilleure façon de revenir à l'utilisation de la puissance de lxml après avoir à utiliser une expression régulière pour trouver quelque chose dans un document html

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

Question

Je suis en train de déchirer un texte sur un grand nombre de documents html (numéros des centaines de milliers). Les documents sont vraiment des formes, mais ils sont préparés par un très grand groupe de différentes organisations donc il y a des variations importantes dans la façon dont ils créent le document. Par exemple, les documents sont divisés en chapitres. Je pourrais vouloir extraire le contenu du chapitre 5 de chaque document afin que je puisse analyser le contenu du chapitre. Au début, je pensais que ce serait facile, mais il se trouve que les auteurs peuvent utiliser un ensemble de tables non imbriquées dans le document pour tenir le contenu afin que le chapitre n pourrait être affiché à l'aide des balises td dans une table. Ou ils pourraient utiliser d'autres éléments tels que les balises balises p H, des balises div ou tout autre élément de niveau bloc.

Après avoir essayé à plusieurs reprises d'utiliser lxml pour me aider à identifier le début et la fin de chaque chapitre, je l'ai déterminé qu'il est beaucoup plus propre à utiliser une expression régulière parce que dans tous les cas, peu importe ce que l'élément html englobante est l'étiquette de chapitre est toujours sous la forme de

>Chapter #

Il est un peu plus compliqué qu'il pourrait y avoir un peu d'espace blanc ou espace insécable représenté de différentes façons (ou ou seulement des espaces). Néanmoins, il est trivial d'écrire une expression régulière pour identifier le début de chaque section. (Le début d'une section est la fin de la section précédente.)

Mais maintenant, je veux utiliser lxml pour obtenir le texte sur. Ma pensée est que je ne sais vraiment pas d'autre choix que de marcher le long de ma chaîne pour trouver la balise fermante de l'élément qui entoure le texte que je utilise pour trouver la section pertinente.

Ce qui est ici est un exemple où l'élément contenant le nom du chapitre est 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>

Alors j'imagine que je commencerais à l'endroit où j'ai trouvé le match pour le chapitre 1 et mettre en place une des expressions régulières pour trouver le prochain

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

Donc, à ce stade, j'ai identifié le type d'élément tenant ma tête de chapitre

Je peux utiliser la même logique pour trouver tout le texte qui se trouve dans cet élément qui est mis en place une expression régulière pour me aider à marquer de

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

Je l'ai identifié où mon chapitre 1 commence

Je peux faire la même chose pour le chapitre 2 (qui est l'endroit où le chapitre 1 se termine)

Maintenant, j'imagine que je vais snip le document à partir de l'ouverture de l'élément que j'identifié comme l'élément le indique où le chapitre 1 commence et se termine juste avant l'ouverture de l'élément que j'identifié comme l'élément indique où le chapitre 2 commence. La chaîne que j'ai identifié sera ensuite envoyé à lxml d'utiliser son pouvoir pour obtenir le contenu.

Je vais tous ces ennuis parce que j'ai lu et plus - ne jamais utiliser une expression régulière pour extraire le contenu des documents html et je ne l'ai pas frappé sur une façon d'être aussi précis avec lxml pour identifier le début et de fin emplacements pour le texte que je veux extraire. Par exemple, je ne peut jamais être certain que le sous-titre du chapitre 1 est Débuts il pourrait être Notre-Rouge Canaries. Permettez-moi de dire que j'ai passé deux jours solides essayer avec lxml pour être sûr que j'ai eu le début et les éléments de fin et je ne pouvais être précis <60% du temps, mais une très courte expression régulière m'a donné plus de 95% de réussite.

J'ai tendance à rendre les choses plus compliquées que nécessaire pour que je me demande si quelqu'un a vu ou résolu un des problèmes similaires et si elles avaient une approche (pas les détails que vous l'esprit) qu'ils aimeraient offrir.

Était-ce utile?

La solution 3

Comme je le craignais, il n'y a aucun moyen systématique d'utiliser lxml pour identifier et extraire ce que je dois. O h bien tout le monde apprécie que je tintement. Notez-ce n'est pas la faute de lxml, c'est la faute du codage HTML incompatible. Par exemple. Parce qu'un chapitre est une division raisonnable d'un document tout le contenu dans un chapitre doit être enveloppé dans un certain type d'élément. Probablement le plus flexible serait une balise div avec la div suivante étant le chapitre suivant. Cela ferait un chapitre d'une branche de l'arbre. Malheureusement, alors qu'environ 20% des documents peut être que bien structuré que les autres ne sont pas.

Je pourrais tester pour chaque type d'élément qui devrait tenir mon contenu (div, p) et de saisir tous ses enfants et tous ses frères et sœurs jusqu'à ce que je l'élément suivant de ce type qui a des informations qui me avertit que nous sont à la fin de la section (début de la section suivante). Mais cela semble trop de travail quand je suis bon 95% du temps ou plus avec une expression régulière.

Merci pour toutes les réponses et les commentaires comme toujours je learnded d'eux.

Autres conseils

Parfois, il n'y a pas un chemin droit pour obtenir le contenu en traitant avec le langage HTML ou mal écrit de façon incohérente.

Vous pouvez regarder en utilisant le lynx ou l'un des navigateurs en mode texte pour vider le contenu de la page, que ce soit dans un fichier, ou de tuyau dans votre code, et traiter ensuite. Ou bien, vous pouvez utiliser lxml pour charger et analyser la page, puis extraire le texte à l'aide text_content () et aller après les chapitres via regex.

Comme ils disent, GIGO - garbage in, garbage out, et il est notre travail en tant que développeurs de tourner que les ordures en or. Cela peut être assez en désordre.

La chose la plus simple, il semble que vous pourriez faire itérer sur tree.getroot (). Iterdescendants () à la recherche d'un noeud avec node.text qui correspond à votre expression régulière souhaitée. A partir de ce moment-là, vous pouvez passer le nœud à une fonction qui utilise des heuristiques ad hoc pour déterminer où le texte est. (Peut-être que si iterdescendants sur la racine est trop lent, vous pouvez utiliser votre approche regex et plongez dans etree pour essayer de trouver une fonction f(text_position) -> node.)

Par exemple, si vous trouvez que la cible était un //tr/td, vous pouvez passer à une sous-routine trouver texte-table qui avait l'air dans le prochain td dans node.parent () pour voir si elle a le texte qui est logique ( environ chapitre longueur, contenant certains mots, peu importe). De même, vous pouvez faire quelques heuristiques pour trouver les données dans d'autres balises comme div et p. Si vous vous trouvez dans une balise inconnue comme font vous pouvez essayer bouillonne un nombre limité de niveaux pour trouver quelque chose que vous savez comment gérer - vous devez être prudent pour ne pas bouillonner trop loin, ou j'imagine que vous pourriez récupérer accidentellement du texte d'un autre chapitre.

Le nœud du problème semble être que vous l'exploration de données qui n'est pas présenté par programme d'une manière programmatique -. Dans ces cas, l'interaction humaine est généralement nécessaire dans une certaine mesure

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top