Регулярные выражения предназначены для обработки относительно простых текстов, которы
задаются регулярными языками. Регулярные выражения со времени своего появления сильн
усложнились, особенно в Perl, реализация регулярных выражений в котором является вдохновение
для остальных языков и библиотек, но регулярные выражения всё ещё плохо приспособлен
(и вряд ли когда-либо будут) для обработки сложных языков типа HTML. Сложность обработк
HTML заключается ещё и в очень сложных правилах обработки невалидного кода, которы
достались по наследству от первых реализаций времён рождения Интернета, когда никаки
стандартов не было и в помине, а каждый производитель браузеров нагромождал уникальны
и неповторимые возможности.
Итак, в общем случае регулярные выражения — не лучший кандидат для обработки HTML
Обычно разумнее использовать специализированные парсеры HTML.
CsQuery
Лицензия: MIT
Один из современных парсеров HTML для .NET. В качестве основы взят парсер validator.n
для Java, который в свою очередь является портом парсера из движка Gecko (Firefox)
Это гарантирует, что парсер будет обрабатывать код точно так же, как современные браузеры.
API черпает вдохновение у jQuery, для выбора элементов используется язык селекторо
CSS. Названия методов скопированы практически один-в-один, то есть для программистов
знакомых с jQuery, изучение будет простым.
Обладает высокой производительностью. На порядки превосходит HtmlAgilityPack+Fizzle
по скорости на сложных запросах.
CQ cq = CQ.Create(html);
foreach (IDomObject obj in cq.Find("a"))
Console.WriteLine(obj.GetAttribute("href"));
Если требуется более сложный запрос, то код практически не усложняется:
CQ cq = CQ.Create(html);
foreach (IDomObject obj in cq.Find("h3.r a"))
Console.WriteLine(obj.GetAttribute("href"));
HtmlAgilityPack
Лицензия: Ms-PL
Самый старый, и потому самый популярный парсер для .NET. Однако возраст не означае
качество, например, уже пять лет (!!!) висит незакрытым критический баг Incorrect parsin
of HTML4 optional end tags, который приводит к некорректной обработке тегов HTML, закрывающи
теги для которых опциональны. В API присутствуют странности, например, если ничего н
найдено, возвращается null, а не пустая коллекция.
Для выбора элементов используется язык XPath, а не селекторы CSS. На простых запроса
код получается более-менее удобочитаемый:
HtmlDocument hap = new HtmlDocument();
hap.LoadHtml(html);
HtmlNodeCollection nodes = hap.DocumentNode.SelectNodes("//a");
if (nodes != null)
foreach (HtmlNode node in nodes)
Console.WriteLine(node.GetAttributeValue("href", null));
Однако если нужны сложные запросы, то XPath оказывается не очень приспособленны
для имитации CSS селекторов:
HtmlDocument hap = new HtmlDocument();
hap.LoadHtml(html);
HtmlNodeCollection nodes = hap.DocumentNode.SelectNodes(
"//h3[contains(concat(' ', @class, ' '), ' r ')]/a");
if (nodes != null)
foreach (HtmlNode node in nodes)
Console.WriteLine(node.GetAttributeValue("href", null));
Fizzler
Лицензия: LGPL
Надстройка к HtmlAgilityPack, позволяющая использовать селекторы CSS.
HtmlDocument hap = new HtmlDocument();
hap.LoadHtml(html);
foreach (HtmlNode node in hap.DocumentNode.QuerySelectorAll("h3.r a"))
Console.WriteLine(node.GetAttributeValue("href", null));
AngleSharp
Лицензия: BSD (3-clause)
Новый игрок на поле парсеров. В отличие от CsQuery, написан с нуля вручную на C#
Также включает парсеры других языков.
API построен на базе официальной спецификации по JavaScript HTML DOM. В некоторы
местах есть странности, непривычные для разработчиков на .NET (например, при обращени
к неверному индексу в коллекции будет возвращён null, а не выброшено исключение; ест
свой отдельный класс Url; пространства имён очень гранулярные, даже базовое использовани
библиотеки требует три using и т. п.), но в целом ничего критичного.
Из других странностей — библиотека тащит за собой Microsoft BCL Portability Pack
Поэтому, когда подключите AngleSharp через NuGet, не удивляйтесь, если обнаружите подключенным
три дополнительных пакета: Microsoft.Bcl, Microsoft.Bcl.Build, Microsoft.Bcl.Async.
Обработка HTML простая:
IHtmlDocument angle = new HtmlParser(html).Parse();
foreach (IElement element in angle.QuerySelectorAll("a"))
Console.WriteLine(element.GetAttribute("href"));
Она не усложняется, и если нужна более сложная логика:
IHtmlDocument angle = new HtmlParser(html).Parse();
foreach (IElement element in angle.QuerySelectorAll("h3.r a"))
Console.WriteLine(element.GetAttribute("href"));
Regex
Страшные и ужасные регулярные выражения. Применять их нежелательно, но иногда возникае
необходимость, так как парсеры, которые строят DOM, заметно прожорливее, чем Regex
они потребляют больше и процессорного времени, и памяти.
Если дошло до регулярных выражений, то нужно понимать, что вы не сможете построит
на них универсальное и абсолютно надёжное решение. Однако если вы хотите парсить конкретны
сайт, то эта проблема может быть не так критична.
Ради всего святого, не надо превращать регулярные выражения в нечитаемое месиво
Вы не пишете код на C# в одну строчку с однобуквенными именами переменных, так и регулярны
выражения не нужно портить. Движок регулярных выражений в .NET достаточно мощный, чтоб
можно было писать качественный код.
Например, вот немного доработанный код для извлечения ссылок из вопроса:
Regex reHref = new Regex(@"(?inx)
]*
href \s* = \s*
(? ['""] )
(? [^""]+ )
\k
[^>]* >");
foreach (Match match in reHref.Matches(html))
Console.WriteLine(match.Groups["url"].ToString());
Комментариев нет:
Отправить комментарий