Skip to content

Getting Started RU

Алексей . edited this page Jul 26, 2026 · 2 revisions

Начало работы

English Русский

Установка, поддерживаемые целевые платформы, карта пространств имён и первый рабочий запрос — вручную и через внедрение зависимостей.

Что это за библиотека

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) покрывает библиотеку целиком. См. Исключения.

Первый запрос через DI

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-испытания описаны в разделе Транспорт и аутентификация.

Разбор без HTTP

Парсеры — это чистые статические функции над строками, никак не связанные с транспортом, поэтому 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, категории и уровни логирования
Исключения Иерархия исключений и их обработка

См. также

Clone this wiki locally