Страницы

Поиск по вопросам

Показаны сообщения с ярлыком anglesharp. Показать все сообщения
Показаны сообщения с ярлыком anglesharp. Показать все сообщения

вторник, 31 марта 2020 г.

Парсинг безымянных блоков в AngleSharp

#c_sharp #парсер #anglesharp


Подскажите пожалуйста как из этого блока выбрать только вот это : 8.85 р / шт

дисконт 8.60
8.85 р / шт
Сейчас пробую так: var price = document.Result.QuerySelectorAll(@".price"); Но в результате выводится все, что находится в блоке


Ответы

Ответ 1



Я дал вам ссылку на вопрос на enSO, там есть красивый вариант (через чтение AngleSharp'ом безымянных блоков CSS) и мой варварский в вопросе (вырезанием всех "лишних" нод). В вашем случае начните с чего-то типа: var parser = new HtmlParser(); var document = parser.Parse(@"
дисконт 8.60
8.85 р / шт
"); var priceBlocks = document.QuerySelectorAll("div.price"); foreach (var block in priceBlocks) { var element = block.ChildNodes.First(o => o.NodeType == AngleSharp.Dom.NodeType.Text && o.TextContent.Trim() != ""); element.Text().Trim().Dump(); } Linqpad говорит, что вам вполне сойдёт для начала: Писал наспех, поэтому подразумеваю, что вы понимаете, что такое linq.

четверг, 12 декабря 2019 г.

Как правильно парсить с помощью AngleSharp?

#c_sharp #html #css #anglesharp


Всем привет! Много тем уже перечитал похожих, но в них в основном какие-то частности
спрашивались. Очень согласен вот с этими словами. Ну, честно говоря, вообще ничего
непонятно. Понял, что информация из html парсится либо через LINQ, либо через CSS селекторы.
С первым вообще не знаком, CSS знаю поверхностно. Но все равно такой вариант мне интуитивно
что ли ближе, поэтому хотелось бы ответы получить в виде CSS селекторов.  

Сразу вопрос: всю ли инфу можно запарсить обоими способами? Или есть только случаи,
когда работает только один из способов? Или же есть случаи, где вообще нельзя?)  

Теперь непосредственно к задаче. Хочу запарсить данные контактов с сайта домофонда.
Например, возьмем вот эту страницу. Парсю всю страницу для начала

var parser = new HtmlParser();
var doc = parser.Parse("ссыль");


Как, например, запарсить имя? Смотрю исходник, вижу, что имя находится в блоке
div class="df_panel". Вроде бы этот блок с уникальным названием, поэтому можно сузить
поиск

var div = doc.QuerySelector("div.df_panel");


Вот тут сразу начинаются вопросы. Сам разобрался, что, если в блоке div указывается
название класса, то пишется так, как приведено. Если, например, div id="test", то уже
запрос по-другому пишется (долго доходило на основе кучу примеров из разных форумов)

var div = doc.QuerySelector("div[id="test"");


Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то
регулярные выражения. Может они аналогичные каким-то другим парсерам, как, например,
написано тут, что AngleSharp очень похож на Fizzler. Но что, если у меня это локально
возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять,
что именно мне писать?  

Ладно, отвлекся. Див ближайший для сужения круга поиска получили. (Опять отвлекусь
- кстати, а как быть, если бы его вообще не было? Можно ли каким-то образом получить
определенные данные, если нет уникальных идентификаторов, посредством которых сужается
постепенно зона поиска нужного значения?). Итого видим, что имя записано в тег заголовка
НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка? Пока на этом вопросы задавать перестану. Буду благодарен за любые объяснения. Желательно очень получить ответы на более общие вопросы (например, по поводу, как я предполагаю, этих регулярных выражений с хелпом или хорошими примерами), тогда может с остальной частью я и сам разберусь.


Ответы

Ответ 1



Самое важное Перво-наперво, вам нужно выучить CSS селекторы. А для лучшего понимания, хотя бы еще основы HTML. Сделать это можно, например, на HTML Academy. Бесплатно. Я бы еще добавил, что никакой магии нет- все выборки AngleSharp это стандартные селекторы CSS, а не что-то необычное. (c) ReinRaus Отвечу на ваш вопрос: Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать? Чтобы понять, что надо писать, повторюсь, вам надо выучить CSS селекторы. Сделать это можно, например, здесь: "Знаете ли вы селекторы?". Приведу здесь краткую выжимку из упомянутой выше статьи: Основные виды селекторов Основных видов селекторов всего несколько: * – любые элементы. div – элементы с таким тегом. #id – элемент с данным id. .class – элементы с таким классом. [name="value"] – селекторы на атрибут (см. далее). :visited – «псевдоклассы», остальные разные условия на элемент (см. далее). Селекторы можно комбинировать, записывая последовательно, без пробела: .c1.c2 – элементы одновременно с двумя классами c1 и c2 a#id.c1.c2:visited – элемент a с данным id, классами c1 и c2, и псевдоклассом visited Отношения В CSS3 предусмотрено четыре вида отношений между элементами. Самые известные вы наверняка знаете: div p – элементы p, являющиеся потомками div. div > p – только непосредственные потомки Есть и два более редких: div ~ p – правые соседи: все p на том же уровне вложенности, которые идут после div. div + p – первый правый сосед: p на том же уровне вложенности, который идёт сразу после div (если есть). Селекторы атрибутов На атрибут целиком: [attr] – атрибут установлен, [attr="val"] – атрибут равен val. На начало атрибута: [attr^="val"] – атрибут начинается с val, например value. [attr|="val"] – атрибут равен val или начинается с val-, например равен val-1. На содержание: [attr*="val"] – атрибут содержит подстроку val, например равен myvalue. [attr~="val"] – атрибут содержит val как одно из значений через пробел. Например: [attr~="delete"] верно для edit delete и неверно для undelete, а еще неверно для no-delete. На конец атрибута: [attr$="val"] – атрибут заканчивается на val, например равен myval. Где попрактиковаться? CSS Diner - здесь нужно выбирать элемент, соответствующий указанному CSS правилу. HTML Academy - здесь можно изучить основы верстки. htmlbook - справочник по css селекторам и html тегам. Ответы на остальные вопросы Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то регулярные выражения. Это не регулярные выражения, а CSS селекторы. Об этом я написал выше. Можно ли каким-то образом получить определенные данные, если нет уникальных идентификаторов, посредством которых сужается постепенно зона поиска нужного значения? Да, комбинируя дочерние элементы по любому признаку. Например, первый потомок в родителе (* > *:first-child), точно второй по счету элемент p внутри своего родителя (p:nth-child(2)), не пустой a элементы (a:not(:empty)) и так далее. Итого видим, что имя записано в тег заголовка
НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка? Если я правильно понял, и имеется в виду значение, не обернутое в какой-либо тег, то все равно ответ будет – да. Можно выполнить поиск по тексту. Для этого конкретного случая решение в виде селектора будет таким: h6[itemprop="name"] как только не пробовал. Не парсит с .df_panel Ваш код из комментариев использует метод QuerySelector, который, как я понимаю, выбирает первый элемент с указанным селектором. Первый .df_panel из шести на странице не содержит элемента h6. Поэтому у вас ничего и не находит. Еще раз подчеркну: на странице шесть элементов .df_panel. Код для выборки нужного вам элемента var seller = doc.QuerySelector("[itemprop='seller']"); var name = seller.QuerySelector("[itemprop='name']").Text();

Ответ 2



Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать? Выше ответили про то, что вам нужно знать css селекторы, однако поскольку вопрос светится в поисковиках (вопросов на ru-so не так много) - допишу ещё полезную ссылку по теме. В официальных репозиториях AngleSharp на гитхабе есть демо-приложение.

четверг, 5 декабря 2019 г.

Как парсить сайты с авторизацией?

#c_sharp #anglesharp


Парсер с использованием Anglesharp.

Как парсить сайты с авторизацией?
Я пробую написать парсер.
Если я правильно понял теорию, то логика должна быть следующая:
- авторизация;
- получить куки;
Движение по страницам
- отправить куки;
- перейти на страницу_1;
- отправить куки;
- перейти на страницу_2;  

Форма авторизации

Минимальный код public async void Authorization(string pathPageLogin, string userName, string password) { IConfiguration config = Configuration.Default.WithDefaultLoader().WithCookies(); IBrowsingContext browsingContext = BrowsingContext.New(config); browsingContext.OpenAsync(pathPageLogin).Wait(); (browsingContext.Active.QuerySelector("input[name = 'login[login]']") as IHtmlInputElement).Value = userName; (browsingContext.Active.QuerySelector("input[name = 'login[password]']") as IHtmlInputElement).Value = password; (browsingContext.Active.QuerySelector("form") as IHtmlFormElement).SubmitAsync().Wait(); } public async void Parsing(string url, string pathFileHtml) { HttpClient client = new HttpClient(); var response = await client.GetAsync(url); // скачиваем страницу string source = await response.Content.ReadAsStringAsync(); // Переносим в переменную #region Сохранить страницу в файл File.WriteAllText(pathFileHtml, source); #endregion Сохранить страницу в файл #region Парсер // HTML парсер, который доступен из "AngleSharp". var domParser = new HtmlParser(); // Спарсим асинхронно наш исходный код и получим документ с которым мы можем работать var document = await domParser.ParseAsync(source); // *** Парсер **** // результат var list = new List(); var items = document.QuerySelectorAll("a").Where(item => item.ClassName != null && item.ClassName.Contains("post__title_link")); foreach (var item in items) { list.Add(item.TextContent); } #endregion } Вопросы. 1. Правильно ли я понимаю логику? 2. Как сделать код с минимальным набором основных методов для простых сайтов, чтобы было видно принцип логики? Дополнение Для примера использовать: rabota.by/login/ Дополнение Логин - test9631@yandex.by Пароль - Ym3LDp1FPs Дополнение


Ответы

Ответ 1



Анализируем. Первым делом надо проанализировать сайт и понять как он работает. Я лично буду использовать Fiddler для отлова запросов, вы это можете делать там, где вам удобно... И так, заходим на страницу авторизации, включаем отлов запросов, авторизуемся и смотрим на запросы. Обычно они выглядят довольно заметно и идут на страницу вида /login или что то в этом духе. После авторизации на сайте я поймал такой запрос: Смотрим сам запрос: POST /login/ HTTP/1.1 Host: rabota.by Connection: keep-alive Content-Length: 186 Cache-Control: max-age=0 Origin: https://rabota.by Upgrade-Insecure-Requests: 1 DNT: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 Vivaldi/2.2.1388.37 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Referer: https://rabota.by/ Accept-Encoding: gzip, deflate, br Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7 Cookie: sessionRabota=4t8r5v068lb7g9alo3; _ga=GA1.2.20569718.1545649; _gid=GA1.2.202925.15449; _ym_uid=15595112; _ym_d=154552; _ym_isad=1; _ym_visorc_2318=w; 388c2c03bbed9f4661; captcha=4509285; captcha_md5=59bf907333254603af10; arp_scroll_position=0; *0=*0 Первым делом нас тут интересует тип запроса, у нас это POST на адрес /login/. Далее смотрим на тип передаваемых данных Content-Type: application/x-www-form-urlencoded. Также может пригодиться User-Agent и некоторые Cookie. Так, как у нас запрос с данными веб формы, то также стоит посмотреть его тело: login[login] user@mail.com login[password] pass login[remember] 1 submitButton Войти login[type] cad5afb6ed280bc4041d5689d561144a Здесь все довольно понятно - наши логин, пароль, запоминать или нет, имя кнопки и неизвестный параметр с логина. Проверим этот неизвестный параметр, просто проделав авторизацию еще раз. Если он изменится, то стоит искать как он формируется, если нет, то можно использовать его. В моем случае он статичный. Ну и еще стоит посмотреть сам ответ сервера, что он отдает и что он устанавливает: Content-Type: text/html; charset=UTF-8 Set-Cookie: *0=%2A0; expires=Wed, 12-Dec-2018 19:21:31 GMT; Max-Age=-864000; path=/; domain=rabota.by Set-Cookie: 666c9aea5601eb92b8=7df1b7318a82be0b068b; expires=Tue, 22-Jan-2019 19:21:32 GMT; Max-Age=2678400; path=/; httponly Set-Cookie: d2c3f55839194555558=f33b13af8cfcd2d14c8650; expires=Tue, 22-Jan-2019 19:21:32 GMT; Max-Age=2678400; path=/; httponly Видно, что в ответ сервер отдает нам обычный html и устанавливает пару Cookie. Тело ответа смотреть пока бессмысленно. Пробуем отправить запрос сами. Для этих целей отлично подходит Postman. Устанавливаем, пропускаем авторизацию (или нет) и создаем новый запрос. Выбираем POST. Указываем адрес запроса https://rabota.by/login [вкладка Body] Указываем тип данных x-www-form-urlencoded [вкладка Body] Заполняем все поля запроса Пробуем отправить запрос. Смотрим данные (HTML). И видим там, что простой отправки данных нам не достаточно, сайт не авторизует нас. Что то не хватает. Обычно это либо заголовок UserAgent или какой то уникальный, либо Cookie. Пробуем добавить UserAgent - не подошел. Пробуем подобрать Cookie - и тут видим, что сайт наконец нас пустил (в HTML видим свои данные). Теперь очистим запрос: Удаляем из Cookie по одному, пока не перестанет отправлять нам нужные данные. Я лично выяснил, что нужны всего одна Cookie - *0=*0. [вкладка Body] Тут по такому же принципу, убираем все не нужное, убирая просто галки. Мои наблюдения показывают, что достаточно всего лишь login[login], login[password] и login[type]. [вкладка Headers] Убираем также лишние заголовки. На авторизацию влияют Content-Type и Referer.

суббота, 8 июня 2019 г.

Парсинг безымянных блоков в AngleSharp

Подскажите пожалуйста как из этого блока выбрать только вот это : 8.85 р / шт

дисконт 8.60
8.85 р / шт

Сейчас пробую так: var price = document.Result.QuerySelectorAll(@".price"); Но в результате выводится все, что находится в блоке


Ответ

Я дал вам ссылку на вопрос на enSO, там есть красивый вариант (через чтение AngleSharp'ом безымянных блоков CSS) и мой варварский в вопросе (вырезанием всех "лишних" нод).
В вашем случае начните с чего-то типа:
var parser = new HtmlParser();
var document = parser.Parse(@"

дисконт 8.60
8.85 р / шт
");
var priceBlocks = document.QuerySelectorAll("div.price");
foreach (var block in priceBlocks) { var element = block.ChildNodes.First(o => o.NodeType == AngleSharp.Dom.NodeType.Text && o.TextContent.Trim() != "");
element.Text().Trim().Dump(); }
Linqpad говорит, что вам вполне сойдёт для начала:

Писал наспех, поэтому подразумеваю, что вы понимаете, что такое linq.

четверг, 18 октября 2018 г.

Как правильно парсить с помощью AngleSharp?

Всем привет! Много тем уже перечитал похожих, но в них в основном какие-то частности спрашивались. Очень согласен вот с этими словами. Ну, честно говоря, вообще ничего непонятно. Понял, что информация из html парсится либо через LINQ, либо через CSS селекторы. С первым вообще не знаком, CSS знаю поверхностно. Но все равно такой вариант мне интуитивно что ли ближе, поэтому хотелось бы ответы получить в виде CSS селекторов.
Сразу вопрос: всю ли инфу можно запарсить обоими способами? Или есть только случаи, когда работает только один из способов? Или же есть случаи, где вообще нельзя?)
Теперь непосредственно к задаче. Хочу запарсить данные контактов с сайта домофонда. Например, возьмем вот эту страницу. Парсю всю страницу для начала
var parser = new HtmlParser(); var doc = parser.Parse("ссыль");
Как, например, запарсить имя? Смотрю исходник, вижу, что имя находится в блоке div class="df_panel". Вроде бы этот блок с уникальным названием, поэтому можно сузить поиск
var div = doc.QuerySelector("div.df_panel");
Вот тут сразу начинаются вопросы. Сам разобрался, что, если в блоке div указывается название класса, то пишется так, как приведено. Если, например, div id="test", то уже запрос по-другому пишется (долго доходило на основе кучу примеров из разных форумов)
var div = doc.QuerySelector("div[id="test"");
Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то регулярные выражения. Может они аналогичные каким-то другим парсерам, как, например, написано тут, что AngleSharp очень похож на Fizzler. Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать?
Ладно, отвлекся. Див ближайший для сужения круга поиска получили. (Опять отвлекусь - кстати, а как быть, если бы его вообще не было? Можно ли каким-то образом получить определенные данные, если нет уникальных идентификаторов, посредством которых сужается постепенно зона поиска нужного значения?). Итого видим, что имя записано в тег заголовка

НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка?
Пока на этом вопросы задавать перестану. Буду благодарен за любые объяснения. Желательно очень получить ответы на более общие вопросы (например, по поводу, как я предполагаю, этих регулярных выражений с хелпом или хорошими примерами), тогда может с остальной частью я и сам разберусь.


Ответ

Самое важное
Перво-наперво, вам нужно выучить CSS селекторы. А для лучшего понимания, хотя бы еще основы HTML. Сделать это можно, например, на HTML Academy. Бесплатно.
Я бы еще добавил, что никакой магии нет- все выборки AngleSharp это стандартные селекторы CSS, а не что-то необычное. (c) ReinRaus
Отвечу на ваш вопрос:
Но что, если у меня это локально возникшая задача, и не с какими другими парсерами я дело не имел? Как я должен понять, что именно мне писать?
Чтобы понять, что надо писать, повторюсь, вам надо выучить CSS селекторы. Сделать это можно, например, здесь: "Знаете ли вы селекторы?".
Приведу здесь краткую выжимку из упомянутой выше статьи:
Основные виды селекторов
Основных видов селекторов всего несколько:
* – любые элементы. div – элементы с таким тегом. #id – элемент с данным id .class – элементы с таким классом. [name="value"] – селекторы на атрибут (см. далее). :visited – «псевдоклассы», остальные разные условия на элемент (см. далее).
Селекторы можно комбинировать, записывая последовательно, без пробела:
.c1.c2 – элементы одновременно с двумя классами c1 и c2 a#id.c1.c2:visited – элемент a с данным id, классами c1 и c2, и псевдоклассом visited
Отношения
В CSS3 предусмотрено четыре вида отношений между элементами.
Самые известные вы наверняка знаете:
div p – элементы p, являющиеся потомками div. div > p – только непосредственные потомки Есть и два более редких:
div ~ p – правые соседи: все p на том же уровне вложенности, которые идут после div. div + p – первый правый сосед: p на том же уровне вложенности, который идёт сразу после div (если есть).
Селекторы атрибутов
На атрибут целиком:
[attr] – атрибут установлен, [attr="val"] – атрибут равен val.
На начало атрибута:
[attr^="val"] – атрибут начинается с val, например value. [attr|="val"] – атрибут равен val или начинается с val-, например равен val-1. На содержание: [attr*="val"] – атрибут содержит подстроку val, например равен myvalue. [attr~="val"] – атрибут содержит val как одно из значений через пробел. Например: [attr~="delete"] верно для edit delete и неверно для undelete, а еще неверно для no-delete
На конец атрибута:
[attr$="val"] – атрибут заканчивается на val, например равен myval
Где попрактиковаться?
CSS Diner - здесь нужно выбирать элемент, соответствующий указанному CSS правилу. HTML Academy - здесь можно изучить основы верстки. htmlbook - справочник по css селекторам и html тегам.
Ответы на остальные вопросы
Вот где по этому поводу что-то написано? Я так понимаю, что здесь применяются какие-то регулярные выражения.
Это не регулярные выражения, а CSS селекторы. Об этом я написал выше.
Можно ли каким-то образом получить определенные данные, если нет уникальных идентификаторов, посредством которых сужается постепенно зона поиска нужного значения?
Да, комбинируя дочерние элементы по любому признаку. Например, первый потомок в родителе (* > *:first-child), точно второй по счету элемент p внутри своего родителя (p:nth-child(2)), не пустой a элементы (a:not(:empty)) и так далее.
Итого видим, что имя записано в тег заголовка

НУЖНОЕ ИМЯ
. Как получить это значение? Было бы возможно вытащить имя, если бы оно было записано вообще без тега заголовка?
Если я правильно понял, и имеется в виду значение, не обернутое в какой-либо тег, то все равно ответ будет – да. Можно выполнить поиск по тексту. Для этого конкретного случая решение в виде селектора будет таким: h6[itemprop="name"]
как только не пробовал. Не парсит с .df_panel
Ваш код из комментариев использует метод QuerySelector, который, как я понимаю, выбирает первый элемент с указанным селектором. Первый .df_panel из шести на странице не содержит элемента h6. Поэтому у вас ничего и не находит. Еще раз подчеркну: на странице шесть элементов .df_panel
Код для выборки нужного вам элемента
var seller = doc.QuerySelector("[itemprop='seller']"); var name = seller.QuerySelector("[itemprop='name']").Text();