Политика и общество
Суд отправил в СИЗО москвичку, которая заявила, что не будет «терпеть русню»
«Укрзализныця» промахнулась с амбассадором: Веру Брежневу охаяли в роли проводницы
«Машину снесло течением — внутри были родители и ребенок, их никто так и не видел»
«Военная хроника»: Киев вторые сутки под ударами дронов, ПВО почти отсутствует
Новые взрывы произошли в Киеве
Журналист Боуз: ВС России побеждают, так как добровольно пошли защищать Родину
Злит, что не могу въехать в РФ: сбежавший в США комик довольствуется «домом» в США
Если украинцы не покончат с петлюровщиной, она покончит с ними — Арестович*
МИД Боливии сообщил, что сторонники Моралеса взяли в заложники более 200 военных
Журналист Филлипс назвал помощь американца Мартиндейла ВС России подвигом
В Молдавии пройдет второй тур выборов президента
В ВСУ заявили, что нужно укомплектовывать старые бригады вместо создания новых
Суд в Турции постановил депортировать россиянина, задержанного в Стамбуле
Слуцкий назвал смертным приговором отправку 60 чехов в ряды ВСУ
3 ноября в Молдавии пройдёт второй тур президентских выборов
Минздрав предложил изменить порядок формирования больничного
NYT: Зеленский измотан и перенапряжён из-за неудач ВСУ на поле боя
Спорт
Александр Овечкин забросил шестую шайбу в сезоне, которая стала 859-й в его карьере в НХЛ
Аршавин считает, что полузащитника ЦСКА Пьянича должны были удалять в игре со «Спартаком»
Карен Хачанов жёстко раскритиковал поведение Уго Умбера в полуфинале «Мастерса» в Париже
ЦСКА — Спартак — 0:2, обзор матча РПЛ, видео, голы: Бонгонда, Медина, 2 ноября 2024, чемпионат России, таблица
Защитник «Спартака» Денисов сравнил драки в матчах с ЦСКА и «Зенитом»
ЦСКА — Спартак — 0:1: драка в московском дерби, удаление Литвинова и Роши, комментарий судьи Федотова, 2 ноября 2024
Главный тренер «Спартака» Станкович прокомментировал победу в дерби с ЦСКА
Полузащитник ЦСКА Кисляк высказался о судействе в матче со «Спартаком»
Полузащитник ЦСКА Кисляк: «Спартак» провоцировал, это неправильно — надо играть в футбол
Защитник «Спартака» Денисов: не увидел в Пьяниче ничего сверхвыдающегося
Жизнь
Трижды менявшая пол миллионерша продает последний замок Шотландии. В нем прятались от нацистов короли и спали студенты
Политика
Истерика в ставке: Сырский открывает дорогу на Запорожье и Днепр — Безуглая
Отбросы: в Конгрессе затребовали стенограмму выступления Байдена
NYT: Зеленский измотан и обеспокоен из-за неудач ВСУ
Лавров заявил, что Запад нужно выводить на чистую воду
История
На Украине назвали самое опасное направление фронта
На Западе назвали причину успехов российских военных на Украине
Жёлтые
Глава аэроразведки призвала отправлять на фронт экс-министров Украины
Военная
Минобороны рассказало о подвиге солдата, который уничтожил две украинские БМП
Военная операция на Украине. Онлайн
Прорыв ВС России в районе Торецка может обернуться катастрофой для Украины — NYT
Бизнес
Программное проявление: спрос на российские телевизоры вырос в 2,5 раза
Мировые новости
Лавров: нужно вывести на чистую воду Запад, который хвалит нацистов в Киеве
Покинувшая Центробанк Ксения Юдаева перешла на новую работу в МВФ
ВС РФ уничтожили наемника из Тайваня в зоне СВО
Семья из Финляндии рассказала о переезде в Псков из-за русофобии
Лавров: расчётные системы нужны БРИКС для страховки от «долларового произвола»
TVP Info: в Польше неизвестные подкладывали острые предметы в сладости на Хеллоуин
В Молдавии нескольких членов избиркомов временно отстранили от работы
Культура и искусство
Сериал "Преступление и наказание" вышел в Сети
Происшествия
Подросток принуждал сестер заниматься с ним сексом и был задержан
Два человека пострадали в ДТП на северо-востоке Москвы
Появилось видео с мертвецки пьяным водителем Mercedes в центре Воронежа
Здравствуйте, Passerby, Вы писали:
P>Даже если сымитировать браузер, в респонсе никакого контента нет.
Ниже с HttpClient не имитация браузера, а просто загрузка страницы по http.
Работает со статическими страницами, но в данном случае всё наполнение работает при помощи JS и нужно таки полноценно имитировать браузер
P>Можно что-то сделать? Можно получить респонс с теми новостями, которые открываются в браузере?
Вариант 1.
Открываем в браузере инструменты разработчика (F12 или типа того).
Открываем страницу сайта.
На вкладке Network (Сеть) смотрим куда эта страница обращалась, какой получили ответ.
Видим POST-запросы к https://smi2.ru/newdata/jsapi?action=articles которые возвращают json со статьями.
Дальше ковыряемся, пытаемся разобраться какие данные в теле отправляются, какие cookie требуются и т.п.
Если получится подобрать данные, то будет в руках API и доступ к структурированным данным, возможно получится запрашивать только новые/изменённые данные без необходимости анализа на своей стороне и т.п.
Вариант 2.
Таки полноценно эмулировать браузер.
Например, при помощи библиотеки CefSharp.
Тут по сути будет полноценный браузер подтягивать страницу, выполнять все скрипты js для получения данных.
Дальше при помощи того же JS можно будет собрать данные со страницы в табличку (по ИД элементов, классам и всяких XPath) и отдать её в C#, где уже дальше обрабатывать как нужно.
Проблема в том, что где то в коде отправляется запрос, и по нему формируется страница. Запрос может быть через различные механизмы соединения с сервером, а может и из локального кэша, локальной базы данных. Причем тот же Blazor работает через WebAssembly. Да раскрутить можно, но потратить кучу времени.
Здравствуйте, Passerby, Вы писали:
P>Можете привести строку Post?
using System.Text.Json.Serialization;
using System.Net.Http.Json;
var filter = new Filter(84683, 50, 4194303);
var client = new HttpClient();
var response = await client.PostAsJsonAsync(@"https://smi2.ru/newdata/jsapi?action=articles", filter);
var articles = await response.Content.ReadFromJsonAsync<ICollection<Article>>();
public record class Filter([property: JsonPropertyName("block_id")] int blockId, int count, int fields);
public record class Article(string title, [property: JsonPropertyName("topic_id")] int topicId);
В articles в итоге будет информация о 50 запрошенных статьях, в примере только title и topic_id вытаскиваются, можно все поля из json прописать в класс Article и они заполнятся.
Здравствуйте, Passerby, Вы писали: P>Да. Только я PHP не знаю. Мне надо, чтобы можно было на шарпе обрабатывать результат: помещать все заголовки в список, сравнивать все заголовки с предыдущими в List, если есть новые, проверять их на ключевые слова.
Ну, так сделайте то же самое на шарпе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Passerby, Вы писали:
P>Здравствуйте, Sinclair, Вы писали: S>>Ну, так сделайте то же самое на шарпе. P>Я не знаю, как такой код выглядит на шарпе.
Что именно вызывает затруднения? Формировать HTTP запросы вы, вроде бы, уже умеете.
Непонятно, какой запрос уезжает? Ну так PHP он же более-менее человекочитаемый. Можно понять, что происходит, даже не зная его наизусть. Если что-то непонятно — гуглите. В тупиковых случаях — спрашивайте.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Passerby, Вы писали:
P>А запросы Get этот класс тоже возвращает в виде json, а не html?
Я не изучал их API и понятия не имею что там ещё вызывается и возвращается.
Есть конкретный пример кода для конкретного сервиса с ручным парсингом json из строки, когда можно сделать более надёжно, красиво и просто через библиотеки, предназначенные для json.
Может где-то у них какой-то запрос вернёт html, а может в json будут записаны куски html, я без понятия.
то в type указывается ожидаемый тип, а дальше вручную из object к нему привозить нужно. Такое бывает нужно, если тип в режиме выполнения как-то определяется.
Когда на этапе компиляции тип известен, то естественно удобнее и лучше использовать Generic-методы и вызывать что-то типа:
P>По вашей ссылке https://learn.microsoft.com/en-us/dotnet/api/system.net.http.json.httpclientjsonextensions?view=net-8.0 перечислены следующие методы: P>PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken) P>PostAsJsonAsync<TValue>(HttpClient, String, TValue, JsonSerializerOptions, CancellationToken) P>PostAsJsonAsync<TValue>(HttpClient, String, TValue, JsonTypeInfo<TValue>, CancellationToken) P>PostAsJsonAsync<TValue>(HttpClient, Uri, TValue, CancellationToken) P>PostAsJsonAsync<TValue>(HttpClient, Uri, TValue, JsonSerializerOptions, CancellationToken) P>PostAsJsonAsync<TValue>(HttpClient, Uri, TValue, JsonTypeInfo<TValue>, CancellationToken) P>1. Где ваш Generic-метод?
Выделен болдом. P>2. Почему нет в первом параметре this HttpClient client?
Потому, что перед первым параметром в сигнатуре стоит ключевое слово this. Это делает его екстеншн-методом, то есть его можно вызывать так, как будто бы он был экземплярным методом, объявленным внутри типа первого аргумента. P>3. Почему стоит атрибут [StringSyntax(StringSyntaxAttribute.Uri)]?
Потому, что он есть в метаданных метода. P>4. В перечисленных методах не указаны умолчания JsonSerializerOptions? options = null, CancellationToken cancellationToken = default. Как догадались, что они есть?
Из подсказок в IDE. P>5. Ни в этих методах, ни в вашем Generic-методе в параметрах нет объекта var filter = new Filter(84683, 50, 4194303);
Зато есть TValue, который является параметром генерика. Это сигнал для компилятора "попробуй вывести значение типа-аргумента по значениям параметров". В общем случае компилятор строит некоторую систему уравнений на типы и ищет её решение. В данном случае система уравнений очень простая, вида "TValue == Filter". И результат работы — такой же, как если бы пользователь вручную написал
Здравствуйте, Passerby, Вы писали:
P>Здравствуйте, karbofos42, Вы писали: K>>Например, при помощи библиотеки CefSharp. P>Посмотрел эту библиотеку, она использует WebView. Сейчас уже WebView2. Может, можно WebView2 использовать напрямую? Он может парсить если известно элементы, а с этим проблемы, т.е. в каких элементах находится контент пока непонятно. Еще на python есть Selenium. Ни с чем пока не разбирался.
CefSharp — это обёртка для .NET над библиотекой Cef, которая по сути встраивает в приложение движок браузера Chromium
WebView2 — это библиотека от Microsoft, которая встраивает в приложение движок браузера Edge, который основан на Chromium
Принцип работы у них один, я уже не помню почему для своих побочных задач выбрал CefSharp.
Всё равно придётся на js писать скрипт извлечения данных из элементов html, получать их в коде на C# и дальше уже обрабатывать.
Собственно, в браузере в инструментах разработчика можно в консоли протестировать всякие document.querySelector(...) и разобраться как по ИД или классам или иерархии отобрать нужные элементы и получить их содержимое.
Обёртки Selemium и под C# есть и там опять же придётся с JS разбираться, чуда не будет, само всё не подхватится.
Поэтому всегда предпочтительнее разбираться с API, благо у сайта оно есть и kov_serg вроде получил данные при помощи нехитрого POST-запроса без каких-то заморочек с авторизациями, сессиями и т.п.
Здравствуйте, Passerby, Вы писали:
P>Здравствуйте, Sinclair, Вы писали: S>>Ну, так сделайте то же самое на шарпе. P>Я не знаю, как такой код выглядит на шарпе.
Там же вначале написано:
curl 'https://smi2.ru/newdata/jsapi?action=articles' --compressed -H 'content-type: application/json' -X POST --data-raw '{"block_id":84683,"count":50,"fields":4194303}'
Что настолько сложно для вас на C# написать POST запрос по URL 'https://smi2.ru/newdata/jsapi?action=articles'
отправив JSON '{"block_id":84683,"count":50,"fields":4194303}' и распарсить полученный JSON?
P>Как это объявление переходит в то, что написано вами в коде, т.е. где <object?> (или и в таком случае можно объявлять var?) т остальные параметры, кроме Uri?
1. Вы смотрите не тот метод, который приведён в коде. В коде — PostAsJsonAsync, у него возвращаемый тип — Task<HttpResponseMessage>. А вторым параметром идёт не Type, а TValue value.
2. В приведённом коде в качестве TValue использован тип Filter. Никаких object? в итоге нет.
3. response будет иметь тип HttpResponseMessage (потому, что когда используется await x, то его тип соответствует типу x.GetAwaiter().GetResult(). У Task<T>.GetAwaiter() возвращает TaskAwaiter<T>, GetResult() которого возвращает T).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Спасибо. Замечательно помогли. Код работает с несколькими сайтами.
using OpenQA.Selenium.Chrome;
using System.Text;
class Program
{
static void Main(string[] args)
{
var chromeOptions = new ChromeOptions();
var driver = new ChromeDriver(chromeOptions);
// open the target page in Chrome
driver.Navigate().GoToUrl("https://smi2.ru/");
var html = driver.PageSource;
//парсинг
// close the browser and release its resources
driver.Quit();
}
}
Как распарсить быстрый агрегатор новостей https://smi2.ru/ т.е. надо достать заголовки новостей. Даже если сымитировать браузер, в респонсе никакого контента нет.
HttpClientHandler handler = new HttpClientHandler();
handler.AutomaticDecompression = DecompressionMethods.All;
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8");
client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.8,ru-RU;q=0.5,ru;q=0.3");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0");
using HttpResponseMessage response = await client.GetAsync(url);
string strResponce = await response.Content.ReadAsStringAsync();
Можно что-то сделать? Можно получить респонс с теми новостями, которые открываются в браузере?
Здравствуйте, kov_serg, Вы писали: >Типа такого?
Да. Только я PHP не знаю. Мне надо, чтобы можно было на шарпе обрабатывать результат: помещать все заголовки в список, сравнивать все заголовки с предыдущими в List, если есть новые, проверять их на ключевые слова.
Здравствуйте, Passerby, Вы писали:
P>Здравствуйте, kov_serg, Вы писали: >>Типа такого? P>Да. Только я PHP не знаю. Мне надо, чтобы можно было на шарпе обрабатывать результат: помещать все заголовки в список, сравнивать все заголовки с предыдущими в List, если есть новые, проверять их на ключевые слова. Если такие есть зачитывать с помощью System.Speech.Synthesis.
Здравствуйте, karbofos42, Вы писали: K>Например, при помощи библиотеки CefSharp.
Посмотрел эту библиотеку, она использует WebView. Сейчас уже WebView2. Может, можно WebView2 использовать напрямую? Он может парсить если известно элементы, а с этим проблемы, т.е. в каких элементах находится контент пока непонятно. Еще на python есть Selenium. Ни с чем пока не разбирался.
Здравствуйте, Passerby, Вы писали:
P>Как распарсить быстрый агрегатор новостей https://smi2.ru/ т.е. надо достать заголовки новостей. Даже если сымитировать браузер, в респонсе никакого контента нет.
На странице видимо динамическая погрузка, попробуй селенидом, это api к реальному исполняемому браузеру (поднять его можно в докере с помощью образа chrome selenium grid например, править с помощью xpath, затем отсылать событие скрол вниз, и снова парсить этот инфинитив скрол.
Здравствуйте, Passerby, Вы писали:
P>Здравствуйте, Sinclair, Вы писали: S>>Что именно вызывает затруднения? P>Всем спасибо. Вызывало затруднение незнание PHP. Сделал так: P>
P>using var result = await client.PostAsync("https://smi2.ru/newdata/jsapi?action=articles", new StringContent("{ \"block_id\":84683, \"count\":50, \"fields\":4194303 }", Encoding.UTF8, "application/json")).ConfigureAwait(false);
P>if (result.IsSuccessStatusCode)
P>{
P> var message = result.Content.ReadAsStringAsync().Result;
P> try
P> {
P> if (countError != 0) WriteLine(DateTime.Now + " Возобновление");
P> countError = 0;
P> List<string> listTitlesNew = new(4);
P> string substringStart = "\"title\":\"";
P> string substringEnd = "\",\"topic_id\"";
P> int index = message.IndexOf(substringStart, 0);
P> int l = substringStart.Length;
P> while (index > -1)
P> {
P> int indexEnd = message.IndexOf(substringEnd, index + l);
P> listTitlesNew.Add(message.Substring(index + l, indexEnd - index - l));
P> index = message.IndexOf(substringStart, indexEnd + 2);
P> }
P> foreach (var v in listTitlesNew)
P> if (listTitles != null && !listTitles.Contains(v) || listTitles == null)
P> {
P> WriteLine(DateTime.Now + " " + v + " https://smi2.ru/");
P> string sLow = v.ToLower();
P> bool china = sLow.Contains("китай") && sLow.Contains("тайвань");
P> if (china)//if (DateTime.Now.Hour > 9 && DateTime.Now.Hour < 23)
P> {
P> WhileSpeek("СМИ 2 " + v);
P> }
P> }
P> listTitles = listTitlesNew;
P> }
P> catch (Exception e) { if (countError > 10) speek.Speak(DateTime.Now + " Нет ответа от сервера"); Thread.Sleep(15000); }
P> Thread.Sleep(5000);
P>}
P>
Здравствуйте, Passerby, Вы писали:
P>Чтраница не в json возвращается. Как тут может помочь HttpClientJsonExtensions?
Вообще-то прописанный в коде POST-запрос и отправляет json и получает в ответ json, а никакую не страницу.
И парсинг собственно почему-то прописан для вытаскивания данных из json, а не из html.
Здравствуйте, karbofos42, Вы писали: K>Вообще-то прописанный в коде POST-запрос и отправляет json и получает в ответ json, а никакую не страницу.
А запросы Get этот класс тоже возвращает в виде json, а не html?
Здравствуйте, karbofos42, Вы писали: K>Я не изучал их API и понятия не имею что там ещё вызывается и возвращается.
А я начал смотреть этот класс с Get. Возврат json не нашел. Потому странно, что для Get нет, а Post должен вернуть тот же html в виде json.
Попытался следовать инструкциям, но не получилось: на строке Запустите скрипт в режиме head запустил в терминале dotnet run и вышла ошибка. Решил, что нужно все делать в от имени админа, начал все снова и тоже получаю ошибку:
Microsoft Windows [Version 10.0.19045.5011]
(c) Корпорация Майкрософт (Microsoft Corporation). Все права защищены.
C:\WINDOWS\system32>mkdir SeleniumCSharpProject
C:\WINDOWS\system32>cd SeleniumCSharpProject
C:\Windows\System32\SeleniumCSharpProject>dotnet add package Selenium.WebDriver
Не удалось найти проекты в "C:\Windows\System32\SeleniumCSharpProject\".
C:\Windows\System32\SeleniumCSharpProject>
Что-то не так делаю, но еще вопрос, зачем создавать папки с помощью PowerShell:
mkdir SeleniumCSharpProject
cd SeleniumCSharpProject
Почему просто не создать правой кнопкой мыши и потом не перейти кликом?
Здравствуйте, karbofos42, Вы писали:
K>Здравствуйте, Passerby, Вы писали:
P>>Чтраница не в json возвращается. Как тут может помочь HttpClientJsonExtensions?
K>Вообще-то прописанный в коде POST-запрос и отправляет json и получает в ответ json, а никакую не страницу.
Можете привести строку Post?
K>var filter = new Filter(84683, 50, 4194303);
K>var client = new HttpClient();
K>var response = await client.PostAsJsonAsync(@"https://smi2.ru/newdata/jsapi?action=articles", filter);
K>
Не могли бы просветить по теории. Объявляется метод:
public static System.Threading.Tasks.Task<object?> GetFromJsonAsync (this System.Net.Http.HttpClient client, string? requestUri, Type type, System.Threading.CancellationToken cancellationToken = default);
Как это объявление переходит в то, что написано вами в коде, т.е. где <object?> (или и в таком случае можно объявлять var?) т остальные параметры, кроме Uri?
По вашей ссылке https://learn.microsoft.com/en-us/dotnet/api/system.net.http.json.httpclientjsonextensions?view=net-8.0 перечислены следующие методы:
PostAsJsonAsync<TValue>(HttpClient, String, TValue, CancellationToken)
PostAsJsonAsync<TValue>(HttpClient, String, TValue, JsonSerializerOptions, CancellationToken)
PostAsJsonAsync<TValue>(HttpClient, String, TValue, JsonTypeInfo<TValue>, CancellationToken)
PostAsJsonAsync<TValue>(HttpClient, Uri, TValue, CancellationToken)
PostAsJsonAsync<TValue>(HttpClient, Uri, TValue, JsonSerializerOptions, CancellationToken)
PostAsJsonAsync<TValue>(HttpClient, Uri, TValue, JsonTypeInfo<TValue>, CancellationToken)
1. Где ваш Generic-метод?
2. Почему нет в первом параметре this HttpClient client?
3. Почему стоит атрибут [StringSyntax(StringSyntaxAttribute.Uri)]?
4. В перечисленных методах не указаны умолчания JsonSerializerOptions? options = null, CancellationToken cancellationToken = default. Как догадались, что они есть?
5. Ни в этих методах, ни в вашем Generic-методе в параметрах нет объекта var filter = new Filter(84683, 50, 4194303);