-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started RU
Установка, поддерживаемые целевые платформы, карта пространств имён и первый рабочий запрос — вручную и через внедрение зависимостей.
LogsParser — это .NET-библиотека для скрейпинга и интеграции с arizonarp.logsparser.info, просмотрщиком
логов игровых серверов Arizona RP. Она выполняет вход на сайт и подтверждение TOTP-двухфакторной аутентификации,
получает страницы по HTTP и превращает возвращённый HTML в неизменяемые типизированные записи. Официального API
за этим нет: каждая модель получается вручную написанным разбором разметки сайта.
| Идентификатор пакета | LogsParser |
| Версия | 1.2.7 |
| Сборка / корневое пространство имён | LogsParser |
| Репозиторий / решение / папка проекта | LogTools |
| Лицензия | CC BY-NC 4.0 — только некоммерческое использование |
Идентификатор пакета и все пространства имён — LogsParser; репозиторий, решение и папка проекта — LogTools. Эти два имени никогда не взаимозаменяемы.
Из NuGet:
dotnet add package LogsParser
Явным PackageReference:
<ItemGroup>
<PackageReference Include="LogsParser" Version="1.2.7" />
</ItemGroup>Либо, если исходники подключаются напрямую из копии репозитория, — через ProjectReference на
LogTools.csproj (обратите внимание на имя файла проекта: это не LogsParser.csproj):
<ItemGroup>
<ProjectReference Include="..\LogTools\LogTools.csproj" />
</ItemGroup>Библиотека собирается сразу под четыре платформы со следующими настройками компиляции:
| Свойство | Значение |
|---|---|
TargetFrameworks |
net7.0;net8.0;net9.0;net10.0 |
LangVersion |
latest |
Nullable |
enable |
ImplicitUsings |
enable |
GenerateDocumentationFile |
true |
Поскольку нижняя граница — net7.0, любой используемый API базовой библиотеки должен существовать там; более
новые API реализуются внутренними полифилами, а не поднятием границы. Nullable-ссылочные типы включены везде,
поэтому необязательные значения объявлены как nullable (LogsParserCredentials?, ICookieStorage?,
LogPageMetaInfo?), а ненулевые члены гарантированно не равны null: при отсутствии данных коллекции равны
Array.Empty<T>(), а не null.
Их ровно две, и обе закреплены по версиям для каждой целевой платформы:
| Целевая платформа | Microsoft.Extensions.DependencyInjection |
Microsoft.Extensions.Logging.Abstractions |
|---|---|---|
net7.0 |
7.0.0 |
7.0.1 |
net8.0 |
8.0.1 |
8.0.2 |
net9.0 |
9.0.3 |
9.0.3 |
net10.0 |
10.0.5 |
10.0.5 |
Ни одна библиотека разбора HTML не подключена. Вся работа с разметкой сделана вручную написанными регулярными
выражениями по реальной разметке сайта — это осознанное проектное решение, а не упущение. Учтите, что подключены
только абстракции логирования: чтобы вызвать AddLogging() или подключить конкретный провайдер, добавьте в своё
приложение Microsoft.Extensions.Logging (или Microsoft.Extensions.Hosting).
Имена папок в репозитории намеренно не совпадают с пространствами имён. Никогда не выводите пространство имён
из пути к файлу — берите его из объявления namespace или из этой таблицы.
| Пространство имён | Что там находится |
|---|---|
LogsParser |
LogsParserClient, LogsHtmlParser, LogsRequestUriBuilder, ParserRequest, ParserCookie
|
LogsParser.Abstractions |
ILogsParserDataSource, ICookieStorage, MemoryCookieStorage
|
LogsParser.Models |
все записи запросов, ответов и конфигурации — LogsQuery, AdminActivityQuery, TopOperationsQuery, LogsPage, LogEntry, LogsAccount, LogsFilterCatalog, AdminActivityReport, TopOperationsReport, LogsParserCredentials, LogsParserHttpOptions, LogsParserRegistrationOptions
|
LogsParser.Net |
LogsParserHttpDataSource |
LogsParser.Parsing |
LogsFilterCatalogParser |
LogsParser.Diagnostics |
LogsParserLogging |
LogsParser.DependencyInjection |
LogsParserServiceCollectionExtensions |
LogsParser.Exceptions |
все типы исключений, одним плоским пространством имён |
Три примера несовпадения: Contracts/ICookieStorage.cs — это LogsParser.Abstractions,
Infrastructure/Http/LogsParserHttpDataSource.cs — это LogsParser.Net, а Parsing/LogsHtmlParser.cs относится
к корневому LogsParser, тогда как все остальные файлы в Parsing/ — к LogsParser.Parsing.
Участвуют три объекта: хранилище cookie, источник данных, владеющий HTTP-транспортом, и клиент-фасад, который превращает HTML в модели.
public LogsParserHttpDataSource(
LogsParserCredentials? credentials = null,
ICookieStorage? cookieStorage = null,
LogsParserHttpOptions? options = null,
HttpClient? httpClient = null,
ILoggerFactory? loggerFactory = null)using LogsParser;
using LogsParser.Abstractions;
using LogsParser.Models;
using LogsParser.Net;
var cookies = new MemoryCookieStorage();
using var dataSource = new LogsParserHttpDataSource(
credentials: new LogsParserCredentials(
Login: "my_login",
Password: "my_password",
TotpSecret: "BASE32SECRET"),
cookieStorage: cookies,
options: new LogsParserHttpOptions
{
BaseUri = new Uri("https://arizonarp.logsparser.info/"),
MaxRetryAttempts = 5,
WaitForRateLimitReset = true
});
var client = new LogsParserClient(dataSource);
var page = await client.GetLogsAsync(new LogsQuery(
ServerId: 201,
Filters: ["warn", "mute"],
PeriodFrom: DateTime.UtcNow.AddDays(-1),
PeriodTo: DateTime.UtcNow,
Page: 1,
Limit: 1000));
Console.WriteLine($"{page.Entries.Count} entries, account: {page.Account?.Nickname}");
foreach (var entry in page.Entries)
{
Console.WriteLine($"{entry.Timestamp:u} {entry.Text}");
}LogsParserHttpDataSource реализует IDisposable; using var здесь важен, потому что источник данных создаёт и
сам владеет внутренним HttpClient, если параметр httpClient оставлен null. Если вы передаёте собственный
HttpClient, источник данных его не освобождает, а у его обработчика должно быть
AllowAutoRedirect = false — см. Транспорт и аутентификация.
LogsParserCredentials и значения по умолчанию LogsParserHttpOptions:
public sealed record LogsParserCredentials(string Login, string Password, string TotpSecret);Свойство LogsParserHttpOptions
|
Тип | По умолчанию | Описание |
|---|---|---|---|
BaseUri |
Uri |
new("https://arizonarp.logsparser.info/") |
Базовый адрес, применяемый к внутреннему HttpClient
|
UserAgent |
string |
строка UA Chrome 128 для десктопа | Значение заголовка запроса User-Agent
|
Accept |
string |
браузероподобный список text/html,…
|
Значение заголовка запроса Accept
|
MaxRetryAttempts |
int |
5 |
Ограничение на повторы при временных сбоях |
WaitForRateLimitReset |
bool |
true |
При 429 ждать момента сброса лимита вместо выброса исключения |
Учётные данные необязательны. Создание источника данных без них оправдано для сессии, уже аутентифицированной
через восстановленное хранилище cookie; если сервис затем потребует аутентификацию, запрос завершится
исключением AuthenticationRequiredException.
| Исключение | Когда возникает |
|---|---|
AuthenticationRequiredException |
Сервис потребовал вход или подтверждение второго фактора, а LogsParserCredentials не заданы |
AuthenticationFailedException |
Процесс входа не стабилизировался за 3 попытки |
TwoFactorAuthenticationException |
Не удалось сгенерировать TOTP, определить часовой пояс или подтвердить второй фактор |
CsrfTokenNotFoundException |
На странице аутентификации нет <meta name="csrf-token">
|
AccountConfigurationException |
Аккаунт не настроен, и сервис перенаправил на /profile
|
ReactShieldBypassException |
Anti-DDoS-испытание продолжало выдаваться после 3 решённых токенов |
RateLimitExceededException |
429 при WaitForRateLimitReset = false либо исчерпан бюджет повторов |
LogsParserHttpException |
Неуспешный код состояния либо временный сбой, переживший MaxRetryAttempts
|
Все они наследуются от LogsParserException, поэтому один catch (LogsParserException) покрывает библиотеку
целиком. См. Исключения.
public static IServiceCollection AddLogsParser(
this IServiceCollection services,
Action<LogsParserRegistrationOptions> configure)using LogsParser;
using LogsParser.DependencyInjection;
using LogsParser.Models;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddLogging();
services.AddLogsParser(options =>
{
options.Credentials = new LogsParserCredentials(
Login: "my_login",
Password: "my_password",
TotpSecret: "BASE32SECRET");
options.HttpOptions = new LogsParserHttpOptions
{
MaxRetryAttempts = 5,
WaitForRateLimitReset = true
};
});
await using var provider = services.BuildServiceProvider();
using var scope = provider.CreateScope();
var client = scope.ServiceProvider.GetRequiredService<LogsParserClient>();
var page = await client.GetLogsAsync(new LogsQuery(ServerId: 201));AddLogging() регистрируется первым, чтобы ILoggerFactory уже существовала к моменту создания источника
данных: регистрация достаёт её из провайдера и устанавливает в LogsParserLogging. Без этого библиотека
откатывается к NullLoggerFactory и молчит. Сам AddLogging находится в пакете Microsoft.Extensions.Logging,
который библиотека за вас не подключает.
LogsParserRegistrationOptions:
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
Credentials |
LogsParserCredentials? |
null |
Регистрируется как singleton только если не null
|
HttpOptions |
LogsParserHttpOptions |
new() |
Регистрируется как singleton |
CookieStorageFactory |
Func<IServiceProvider, ICookieStorage>? |
null |
Заменяет singleton MemoryCookieStorage по умолчанию |
DataSourceFactory |
Func<IServiceProvider, ILogsParserDataSource>? |
null |
Заменяет transient LogsParserHttpDataSource по умолчанию |
Разрешайте клиента через область (scope), как выше: ILogsParserDataSource зарегистрирован как transient, а
LogsParserHttpDataSource реализует IDisposable, поэтому контейнер освобождает каждый экземпляр вместе с
областью, в которой он был получен. Существует и перегрузка AddLogsParser() без параметров: она регистрирует
тот же граф с параметрами по умолчанию и без учётных данных. Подробности — в
Внедрении зависимостей.
Никакого LoginAsync, SignInAsync или шага «сначала подключитесь» нет — аутентификация полностью реактивна.
LogsParserHttpDataSource сначала отправляет запрос данных с AllowAutoRedirect = false и читает заголовок
Location ответа 302 как сигнал протокола:
| Цель перенаправления | Что делает источник данных |
|---|---|
/login |
Полный вход: получить CSRF-токен, отправить логин и пароль, затем перейти к подтверждению второго фактора |
/authenticator |
Только подтверждение второго фактора — пароль повторно не отправляется (сессия, у которой истекло окно 2FA) |
/profile |
Выбрасывает AccountConfigurationException — сам аккаунт непригоден к работе |
После успешной аутентификации исходный запрос повторяется автоматически, поэтому данные возвращает именно тот
вызов, который сделал вызывающий код. Практическое следствие: самый первый GetLogsAsync в процессе может
выполнить весь вход вместе с TOTP и потому занять заметно больше времени, чем последующие. Чтобы этого избежать,
сохраняйте хранилище cookie между запусками — см. Хранилище cookie.
TotpSecret — это «сырой» Base32-секрет из приложения-аутентификатора. Библиотека не извлекает его из QR-кода
или migration-URI, она принимает только итоговую строку. Полный автомат состояний, счётчики повторов, поведение
при ограничении частоты запросов и обработка anti-DDoS-испытания описаны в разделе
Транспорт и аутентификация.
Парсеры — это чистые статические функции над строками, никак не связанные с транспортом, поэтому HTML, полученный откуда угодно (из файла, через прокси, из другого сервиса), можно разобрать напрямую.
public static LogsPage ParseLogs(string html)using LogsParser;
using LogsParser.Models;
string html = await File.ReadAllTextAsync("logs.html");
LogsPage page = LogsHtmlParser.ParseLogs(html);
foreach (var entry in page.Entries)
{
Console.WriteLine($"{entry.Timestamp:u} {entry.Text}");
}LogsHtmlParser находится в корневом пространстве имён LogsParser, а не в LogsParser.Parsing. ParseLogs
выбрасывает ArgumentNullException / ArgumentException, если html равен null, пуст или состоит из
пробельных символов, и деградирует до пустого результата, когда ожидаемая разметка просто отсутствует, — в
отличие от ParseAdminActivity и ParseTopOperations, которые выбрасывают HtmlParsingException. См.
Парсеры.
| Страница | Что охватывает |
|---|---|
| Главная | Обзор библиотеки и оглавление вики |
| LogsParserClient | Высокоуровневый фасад: все методы, параметры и возвращаемые типы |
| Запросы и построитель URI |
LogsQuery, AdminActivityQuery, TopOperationsQuery и правила нормализации LogsRequestUriBuilder
|
| Модели | Справочник по каждой публичной записи, возвращаемой библиотекой |
| Парсеры |
LogsHtmlParser и LogsFilterCatalogParser в автономном режиме |
| Транспорт и аутентификация |
ILogsParserDataSource, автомат аутентификации, повторы, ограничение частоты запросов, React-испытание |
| Хранилище cookie | Контракт ICookieStorage и сохранение сессии между перезапусками |
| Внедрение зависимостей |
AddLogsParser, параметры регистрации, времена жизни служб |
| Логирование |
LogsParserLogging, категории и уровни логирования |
| Исключения | Иерархия исключений и их обработка |
LogsParser · CC BY-NC 4.0 — non-commercial use only / только некоммерческое использование
English
- Home
- Getting Started
- LogsParserClient
- Requests and URI Builder
- Models
- Parsers
- Transport and Authentication
- Cookie Storage
- Dependency Injection
- Logging
- Exceptions
Русский
- Главная
- Начало работы
- LogsParserClient
- Запросы и построитель URI
- Модели
- Парсеры
- Транспорт и авторизация
- Хранение cookies
- Внедрение зависимостей
- Логирование
- Исключения