воскресенье, 31 января 2010 г.

Парсинг Html документов с целью извлечения данных

Ехал я как-то с работы вместе со своим коллегой Валерой Щербининым и заговорили о теме парсинга HTML.

Большую часть времени на работе я занимаюсь поддержкой и активным развитием биллинговой подсистемы одной большой системы которая занимается записью компакт дисков. Название компании опускаю, так как я подписывал договор о неразглашении нечитая, посему не знаю что можно разглашать, а что нет :).

Учитывая специфику проекта и интеграцию всего со всем я трижды сталкивался с задачей импорта данных из HTML документов в биллинговую систему.

Три раза я использовал один и тот же подход - Regular Expression.
Причем один из документов имел такую нетривиальную структуру, что мне пришлось использовать аж два регулярных выражения. В один проход я выделял все данные вместе с частью HTML разметки, а во второй уже выкусывал сами данные. Мне пришлось так поступить, потому как я уважаю мэйнтейнеров и не хочу писать код, после которого меня будут долго вспоминать.

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

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

Возможно Валера подумал что я полоумный, но тем не менее вежливо поделился своей идеей - использовать HTML Tidy для нормализации HTML до well formed XHTML, а потом наворачивать на это дело Xslt-преобразование которое извлекает все данные.

Идея мне сразу же понравилась. Но меня смутило то, что мне придется вызывать unmanaged HTML Tidy, плюс я практически незнаком с Xslt хотя и знаю XPath.

И вот, сегодня, совершенно случайно наткнулся на замечательное во всех отношениях решение - SGMLReader:
SGMLReader - Converting almost any HTML to valid XML

SGMLReader это pure C# .NET 2.0 библиотека, центральный класс которой это SgmlReader унаследованный от XmlReader со всем вытекающими отсюда преимуществами.

Есть даже примеры, которые запускаются на лету на живом коде из trunk:
HTML-to-XML Conversion Examples

Благодаря это библиотеке мне не придется погружаться в жестокий unmanaged мир и я смогу использовать Linq to Xml / Xslt / XPath на выбор.


В нагрузку ссылка на статью в которой описывается интеграция HTML Tidy и .NET. Если в двух словах то это либо P/Invoke либо COM Iterop. Брр...
Fix Up Your HTML with HTML Tidy and .NET


Ну и раз уж я удосужился написать пост, то упомяну что я завел себе твиттер :)
http://twitter.com/alexey_diyan

В твиттер я делаю посты очень часто. Всех интересующихся заверяю, что посты в твиттер буду делать только на техническую тематику.
Посты обычно касаются либо каких-то актуальных для меня вещей, изредка бывают 140-символьные размышлизмы.

2 комментария:

Mike Chaliy комментирует...

Я обычно юзаю HtmlAgilityPack.. Он предоставляет XPathNavigable на лету. Удобно.

Alexey Diyan комментирует...

Миша, спасибо за наводку.

Когда потребуется у меня уже будет два варианта на рассмотрение.

Судя по всему HtmlAgilityPack более активно развивается в настоящее время.

Жалко что нет времени как следует посмотреть ни на первый ни на второй вариант :(