Я опаздываю на вечеринку, но я пытаюсь внести сюда немного здравого смысла.
Запрос статических веб-страниц
Для этого нам потребуется следующий набор инструментов/функционала:
- HTTP-запросчик (для получения ресурсов, например HTML-документов, через HTTP), потенциально с уровнем SSL/TLS поверх (либо принимает все сертификаты, либо работает с хранилищем сертификатов/известными центрами сертификации)
- парсер HTML
- Запрашиваемое представление объектной модели проанализированного HTML-документа.
- Возможно, дополнительно какое-то состояние куки и возможность переходить по ссылкам/формам публикации
AngleSharp дает нам все эти возможности (за исключением подключения к хранилищу сертификатов/известным центрам сертификации, поэтому для использования HTTPS мы необходимо выполнить некоторую дополнительную настройку, например, принять все сертификаты).
Мы начнем с создания конфигурации AngleSharp, которая определяет, какие возможности доступны для механизма просмотра. Этот движок представлен в виде «контекста просмотра», который можно рассматривать как вкладку без заголовка. На этой вкладке мы можем открыть новый документ (из локального источника, созданного источника или удаленного источника).
var config = Configuration.Default.WithDefaultLoader();
var context = BrowsingContext.New(config);
var document = await context.OpenAsync("http://example.com");
Получив документ, мы можем использовать селекторы запросов CSS для получения определенных элементов. Эти элементы можно использовать для сбора информации, которую мы ищем.
AngleSharp поддерживает LINQ (или IEnumerable в целом), однако имеет смысл предоставить полную мощность запросам, если это возможно.
Итак, вместо
var pricesListItemsLinq = document.All
.Where(m => m.LocalName == "span" && m.ClassList.Equals("c-price"));
Мы пишем
var pricesListItemsLinq = document.QuerySelectorAll("span.c-price");
Это также гораздо более надежно (ClassList
в любом случае является сложным объектом, предоставляющим доступ к списку классов, поэтому вы имели в виду либо ClassList.Contains
, либо ClassName.Equals
(последнее представляет собой строковое представление). Примечание: две версии не эквивалентны, потому что первый ищет класс в списке классов, в то время как последний ищет совпадение всей сериализации класса (таким образом, устанавливая некоторые дополнительные граничные условия для совпадения; это должен быть единственный класс).
Работа с динамическими страницами
Это гораздо сложнее. Основы такие же, как и раньше, но движок должен обеспечивать гораздо больше, чем просто ранее упомянутые требования. Кроме того, нам нужно
- Движок JavaScript
- Действительный CSSOM
- Поддельное (или даже полностью вычисленное) дерево рендеринга
- Гораздо больше интерфейсов DOM, которые можно найти в реальных браузерах (например, навигатор, полная история, веб-воркеры, ...) - список здесь безграничен.
Несмотря на то, что существует проект, который поставляет экспериментальный (и ограниченный) JS-движок только на C# для AngleSharp, последние два требования не могут быть полностью выполнены прямо сейчас. Кроме того, CSSOM может быть недостаточно полным для того или иного веб-приложения. Имейте в виду, что эти страницы потенциально предназначены для реальных браузеров. Они делают определенные предположения. Они могут даже требовать ввода данных пользователем (например, Google Captcha).
Короче говоря.
var config = Configuration.Default
.WithDefaultLoader()
.WithCss()
.WithJavaScript(); // maybe even more
var context = BrowsingContext.New(config);
Задача, стоящая за await
при открытии нового документа, эквивалентна событию load
в DOM. Таким образом, он не сработает, когда документ будет загружен и проанализирован, а только после того, как все скрипты будут загружены (и потенциально запущены), в т.ч. ресурсы, которые необходимо загрузить.
Надеюсь это немного поможет!
person
Florian Rappl
schedule
15.12.2017
document.QuerySelectorAll("span.c-price")
. - person Lucas Trzesniewski   schedule 06.09.2015var config = Configuration.Default.WithJavaScript(); var parser = new HtmlParser(config);
. Мне все еще не везет. Есть предложения по альтернативам? - person inquisitive_one   schedule 07.09.2015