Melhor maneira de voltar a usar o poder da lxml depois de ter que usar um regex para encontrar algo em um documento HTML

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

Pergunta

Eu estou tentando rasgar algum texto a partir de um grande número de documentos HTML (números na ordem das centenas de milhares). Os documentos são realmente formas, mas eles são preparados por um grupo muito grande de diferentes organizações para que haja variação significativa na forma como eles criam o documento. Por exemplo, os documentos são divididos em capítulos. Eu poderia querer extrair o conteúdo do capítulo 5 de cada documento para que eu possa analisar o conteúdo do capítulo. Inicialmente eu pensei que este seria fácil, mas verifica-se que os autores podem usar um conjunto de tabelas não-aninhadas em todo o documento para manter o conteúdo de modo que o capítulo n poderia ser exibidos usando tags td dentro de uma tabela. Ou eles podem usar outros elementos, tais como tags de tags p H, tags div ou qualquer outro elemento nível de bloco.

Depois de tentar várias vezes para uso lxml para me ajudar a identificar o início eo fim de cada capítulo eu determinei que é muito mais limpo para usar uma expressão regular, porque em todos os casos, não importa o que o elemento html anexando é o rótulo capítulo está sempre na forma de

>Chapter #

É um pouco mais complicado em que pode haver algum espaço em branco ou espaço não separável representado de diferentes maneiras (ou ou espaços apenas). Não obstante, foi trivial para escrever uma expressão regular para identificar o início de cada seção. (O início de uma secção é a extremidade da secção anterior.)

Mas agora eu quero usar lxml para obter o texto para fora. Meu pensamento é que eu tenho realmente nenhuma escolha mas para andar ao longo da minha corda para encontrar o próximo tag para o elemento que encerra o texto que eu estou usando para encontrar a seção relevante.

É aqui está um exemplo onde o elemento que mantém o nome Capítulo é um 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>

Então, eu estou imaginando que eu iria começar no local onde eu encontrei o jogo para o capítulo 1 e configurar expressões regulares para encontrar o próximo

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

Assim, neste momento eu ter identificado o tipo de elemento segurando meu capítulo título

Eu posso usar a mesma lógica para encontrar todo o texto que está dentro esse elemento que está configurada uma expressão regular para me ajudar a marcar a partir

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

Então, eu identifiquei onde minha Capítulo 1 começa

Eu posso fazer o mesmo para o capítulo 2 (que é onde Capítulo 1 termina)

Agora eu estou imaginando que eu estou indo para cortar o documento começando na abertura do elemento que eu identificado como o elemento o indica onde capítulo 1 começa e termina pouco antes da abertura do elemento que eu identificado como o elemento que indica onde capítulo 2 começa. A cadeia que eu identifiquei será então alimentado para lxml de usar o seu poder para obter o conteúdo.

Vou a todos estes problemas, porque eu li mais e mais - nunca use uma expressão regular para o teor de extrato de documentos HTML e eu não ter batido em uma maneira de ser tão precisos com lxml para identificar o início e término locais para o texto que deseja extrair. Por exemplo, eu nunca pode ter certeza de que o subtítulo do capítulo 1 é nosso início que poderia ser nosso Red Canary. Deixe-me dizer que eu passei dois dias inteiros tentando com lxml para ter certeza de que eu tinha no início e elementos terminando e eu só podia ser precisos <60% do tempo, mas uma expressão regular muito curto deu-me melhor do que 95% de sucesso.

Eu tenho uma tendência a tornar as coisas mais complicadas do que o necessário para que eu estou querendo saber se alguém viu ou resolvido um problemas semelhantes e se eles tinham uma abordagem (não os detalhes você mente) que eles gostariam de oferta.

Foi útil?

Solução 3

Como eu temia não há nenhuma maneira sistemática para uso lxml para identificar e extrair o que eu preciso. O h bem eu apreciar todos chiming. Nota-isso não é culpa do lxml, é culpa do html inconsistente codificação. Por exemplo. Porque um capítulo é uma divisão razoável de um documento de todo o conteúdo em um capítulo deve ser envolvido em algum tipo de elemento. Provavelmente o mais flexível seria uma tag div com o div posterior ser o próximo capítulo. Isto faria um capítulo de um ramo da árvore. Infelizmente, enquanto aproximadamente 20% dos documentos pode ser que bem estruturado os outros não são.

eu poderia testar para cada tipo de elemento que deve manter o meu conteúdo (div, p) e pegue todos os seus filhos e todos os seus irmãos até que eu chegar ao próximo elemento desse tipo que tem informações que me alerta que são no final da secção (início da próxima secção). Mas isso parece muito trabalho quando eu sou bom 95% do tempo ou mais com uma expressão regular.

Obrigado por todas as respostas e comentários como sempre eu learnded deles.

Outras dicas

Às vezes, não há um caminho direto para a obtenção de conteúdo quando se lida com HTML mal ou de forma inconsistente escrito.

Você pode querer olhar usando lince ou um dos navegadores baseados em texto para despejar o conteúdo da página, ou em um arquivo, ou para canalizá-lo em seu código, e depois processá-lo. Ou, você pode usar lxml para carregar e analisar a página, em seguida, extrair o TEXT_CONTENT texto usando () e ir atrás dos capítulos via regex.

Como dizem, GIGO - lixo dentro, lixo para fora, e é nosso trabalho como os desenvolvedores a rotação que o lixo em ouro. Se o fizer, pode ficar bastante confuso.

A coisa mais simples que parece que você possivelmente poderia fazer é iterar tree.getroot () iterdescendants. () À procura de um nó com node.text que corresponde à sua expressão regular desejado. A partir desse ponto, você pode passar o nó para uma função que utiliza algumas heurísticas ad-hoc para determinar onde o texto é. (Talvez se iterdescendants na raiz é muito lento, você pode usar a sua abordagem regex e mergulhar etree para tentar encontrar uma função f(text_position) -> node.)

Por exemplo, se você achar que o alvo era um //tr/td, você pode passá-lo para alguma sub-rotina-table-texto descobrindo que olhou para a próxima td em node.parent () para ver se ele tem o texto que faz sentido ( cerca de capítulo de comprimento, contendo certas palavras, qualquer outro). Da mesma forma, você pode fazer-se algumas heurísticas para encontrar os dados em outras tags como div e p. Se você se encontra em uma tag desconhecido como font você pode tentar borbulhando um número limitado de níveis para encontrar algo que você sabe como lidar com - você tem que ser cauteloso para não borbulhar muito longe, ou eu imagino que você pode acidentalmente recuperar o texto de outro capítulo.

O cerne do problema parece ser que você está mineração de dados que não é apresentada por meio de programação de forma programática -. Nestes casos, a interação humana é geralmente necessário algum grau

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top