Лучший способ вернуться к использованию возможностей lxml после использования регулярных выражений, чтобы найти что-то в HTML-документе - PullRequest
2 голосов
/ 11 марта 2010

Я пытаюсь вырвать какой-то текст из большого количества HTML-документов (числа в сотни тысяч). Документы на самом деле являются формами, но они подготовлены очень большой группой различных организаций, поэтому существуют значительные различия в том, как они создают документ. Например, документы разбиты на главы. Я мог бы захотеть извлечь содержание главы 5 из каждого документа, чтобы я мог проанализировать содержание главы. Сначала я думал, что это будет легко, но оказывается, что авторы могут использовать набор не вложенных таблиц по всему документу для хранения содержимого, чтобы глава n могла отображаться с использованием тегов td внутри таблицы. Или они могут использовать другие элементы, такие как p-теги, H-теги, теги div или любой другой элемент уровня блока.

После неоднократных попыток использовать lxml, чтобы помочь мне определить начало и конец каждой главы, я решил, что регулярное выражение намного чище, потому что в любом случае независимо от того, какой элемент html заключен в заголовок главы всегда в форме

>Chapter #

Это немного сложнее в том, что могут быть некоторые пробелы или неразрывные пробелы, представленные по-разному (или просто пробелы). Тем не менее, было довольно просто написать регулярное выражение для определения начала каждого раздела. (Начало одного раздела - это конец предыдущего раздела.)

Но теперь я хочу использовать lxml для вывода текста. Я думаю, что у меня действительно нет выбора, кроме как пройтись по моей строке, чтобы найти закрывающий тег для элемента, который содержит текст, который я использую, чтобы найти соответствующий раздел.

Вот один из примеров, где элементом, содержащим имя главы, является 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>

Итак, я представляю, что я начну с того места, где я нашел совпадение для главы 1, и настрою регулярные выражения для поиска следующего

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

Итак, на данный момент я определил тип элемента, который содержит заголовок моей главы

Я могу использовать ту же логику, чтобы найти весь текст в этом элементе, который настроен на регулярное выражение, чтобы помочь мне пометить

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

Итак, я определил, где начинается моя Глава 1

Я могу сделать то же самое для главы 2 (на этом глава 1 заканчивается)

Теперь я представляю, что собираюсь отрезать документ, начиная с открытия элемента, который я определил как элемент, который указывает, где начинается глава 1, и заканчивается непосредственно перед открытием элемента, который я определил как элемент, который указывает, где начинается глава 2. Затем указанная мной строка будет передана в lxml, чтобы использовать ее возможности для получения содержимого.

Я собираюсь решить все эти проблемы, потому что я перечитывал снова и снова - никогда не использую регулярные выражения для извлечения содержимого из HTML-документов, и я не нашел способа быть настолько точным с lxml, чтобы определить начало и конец места для текста, который я хочу извлечь. Например, я никогда не могу быть уверен, что подзаголовок главы 1 - «Наши начинания», это может быть «Наша Красная Канарейка». Позвольте мне сказать, что я потратил два целых дня, пытаясь с lxml быть уверенным, что у меня есть начальный и конечный элементы, и я мог быть точным <60% времени, но очень короткое регулярное выражение дало мне успех лучше, чем 95%. </p>

У меня есть склонность усложнять вещи, чем это необходимо, поэтому мне интересно, видел ли кто-либо подобные проблемы или решил их, и если у них был подход (не детали, обратите внимание), который он хотел бы предложить.

Ответы [ 3 ]

2 голосов
/ 11 марта 2010

Иногда нет прямого пути к получению контента при работе с плохо или непоследовательно написанным HTML.

Возможно, вы захотите взглянуть на использование lynx или одного из текстовых браузеров для выгрузки содержимого страницы, либо в файл, либо для передачи его в код, а затем обработки. Или вы можете использовать lxml для загрузки и анализа страницы, затем извлечь текст с помощью text_content () и перейти к главам с помощью регулярных выражений.

Как говорится, GIGO - мусор входит, мусор выходит, и наша работа как разработчиков заключается в том, чтобы превратить этот мусор в золото. Это может стать довольно грязным.

1 голос
/ 18 марта 2010

Как я и опасался, не существует систематического способа использования lxml для выявления и извлечения того, что мне нужно. О, хорошо, я ценю всех, кто вмешивается. Заметьте, это не ошибка lxml, а ошибка несовместимого кодирования html. Например. Поскольку глава является разумным разделением документа, все содержимое одной главы должно быть заключено в элемент определенного типа. Вероятно, наиболее гибким будет тег div с последующим разделом, являющимся следующей главой. Это сделало бы главу ветвью дерева. К сожалению, в то время как приблизительно 20% документов могут быть настолько хорошо структурированы, другие нет.

Я мог бы проверить для каждого типа элемента, который должен содержать мое содержимое (div, p), и захватить все его дочерние элементы и все его родные элементы, пока я не доберусь до следующего элемента этого типа, который имеет информацию, которая предупреждает меня о находятся в конце раздела (начало следующего раздела). Но это кажется слишком большой работой, когда я хорошо справляюсь с регулярным выражением в 95% случаев.

Спасибо за все ответы и комментарии, как я всегда узнал из них.

1 голос
/ 11 марта 2010

Самое простое, что вы можете сделать, это перебирать tree.getroot (). Iterdescendants (), ища узел с node.text, который соответствует вашему желаемому регулярному выражению. С этого момента вы можете передать узел функции, которая использует некоторую специальную эвристику, чтобы определить, где находится текст. (Возможно, если iterdescendants в root слишком медленный, вы можете использовать свой подход регулярных выражений и погрузиться в etree, чтобы попытаться найти функцию f(text_position) -> node.)

Например, если вы обнаружите, что целью был //tr/td, вы можете передать его какой-нибудь подпрограмме поиска текста в таблице, которая изучила следующий td в node.parent (), чтобы увидеть, есть ли у него текст, который делает смысл (приблизительно длина главы, содержащая определенные слова, что угодно). Аналогично, вы можете составить некоторую эвристику для поиска данных в других тегах, таких как div и p. Если вы обнаружите себя в неизвестном теге, таком как font, вы можете попробовать всплыть на ограниченном количестве уровней, чтобы найти что-то, что вы знаете, как справиться - вы должны быть осторожны, чтобы не всплывать слишком далеко, или я думаю, вы можете случайно получить текст из другой главы.

Суть проблемы, по-видимому, заключается в том, что вы добываете данные, которые не представлены программно, программным способом - в этих случаях взаимодействие с человеком обычно в некоторой степени необходимо.

...