Как извлечь полезный текст из HTML (исходники, документация)Источник: it2b Sergey Edunov
Задача на первый взгляд может показаться тривиальной: извлечь полезный текст из HTML страниц с различных сайтов, например новости с новостных лент. На практике, однако, реализация подобной функциональности, как правило, оканчивается написанием кучи парсеров заточенных под конкретные сайты. Поддерживать такие парсеры - сущий кошмар, особенно если система должна работать в автономном режиме долгое время. Хотелось бы иметь универсальное решение. Сегодня я опишу один из возможных вариантов решения этой проблемы. Веб страница состоит из многих частей: полезный текст, некоторым образом размеченный, меню, заголовки, метатекст, скрипты итп. Можно было бы просто убрать всю HTML-разметку, но, к сожалению, это не работает, т.к. остается слишком много мусора. Кроме того, иногда мы хотим сохранить некоторые элементы разметки, например ссылки или изображения относящиеся к тексту, слова и предложения выделенные другим шрифтом итп. Суть предлагаемого подхода состоит в том, чтобы разбить документ на большое количество частей (это могут быть строки либо параграфы) и для каждой части посчитать количество HTML разметки. Оказывается, что количество HTML разметки в участках с осмысленным текстом существенно меньше чем в других участках документа. Для нашего примера я взял статью с rbcdaily. Можно было бы использовать версию для печати, но в целях чистоты эксперимента, остановимся на стандартной версии. Текст был разбит на строки и для каждой строки посчитано количество HTML-тегов разметки и количество прочего текста.
Красной линией на графике обозначается длина строки, синей линией количество не-HTML текста. В целях улучшения визуализации, показаны данные усредненные по 5 строк.
Не слишком понятная картина, правда? Некий пик между 89 и 100, а в остальном, много пиков и провалов. Беглый взгляд в HTML и становится понятно, что в нашем случае он очень сильно засорен JavaScipt-ом и HTML-комментариями. Для улучшения результатов, стоит их удалить. Это сделать достаточно просто, предварительно обработав HTML. После этого, результаты становятся более очевидными:
У нас четко нарисовался пик с основным текстом и куча мусора, который можно смело выбрасывать в корзину. Простейшим способам выбрать где здесь текст, а где мусор, это отобрать строки в которых величина отношения длины HTML разметки к длине строки меньше определенного порогового значения. В нашем случае я взял 0.3 и получил на удивление хорошие результаты
У такого подхода, однако, есть недостаток: несмотря на то, что все заголовки убраны, в тексте все еще сохраняется подпись. Кроме того, могут быть пропущены часть строк реального текста если, по некоторому стечению обстоятельств, там оказалось много разметки или сама строчка была слишком короткой. Для того чтобы улучшить фильтрацию следует рассматривать не только текущую строку но и соседние с ней. Как это сделать, я расскажу в следующий раз. Протестировать результаты такого фильтра можно тут, введите адрес страницы которую бы вы хотели отфильтровать и нажмите старт. Решение основывалось на том, что в тех участках HTML-страниц где содержится полезный текст, как правило, очень мало разметки. То есть, величина отношения количества текста к количеству разметки больше некоторого порогового значения. Для своего тестирования я использовал новостные ленты rbc.ru, rbcdaily.ru и свой блог algorithmist.ru. В качестве параметров для нейронной сети я выбрал следующие атрибуты:
Все длины строк предварительно нормированы относительно максимальной длины строки в документе. Номер строки в документе так же нормирован относительно общего количества строк. Таким образом все 7 параметров принимают значения от 0 до 1 включительно.
Чтобы не гадать какая же конфигурация нейронной сети будет оптимальной, я воспользовался алгоритмом под названием pruning. Идея заключается в том, чтобы последовательно упрощать либо усложнять нейронную сеть, в поисках варианта с наименьшей ошибкой. Наилучших результатов удалось добиться с нейронной сетью из трех невидимых уровней, в первых двух из которых 7 нейронов, а в третьем 3. Тут главное знать меру, можно задать и большее количество невидимых уровней, но тогда возникает риск перетренировать нейронную сеть, слишком точно настроив на конкретные данные и тем самым ухудшить результаты на новых данных.
Для тренировки нейронной сети было создано два набора данных. Один тренировочный, другой проверочный. Конечно, мне было слишком лениво создавать большое количество данных вручную, поэтому каждый набор состоял всего из 10 статей с разных сайтов. |