March 25

Конспект-инструкция по переходу с InfiniteServer на WraithCore (ZennoPoster)

Данное руководство предназначено для пользователей (разработчиков шаблонов ZennoPoster) для плавного перехода со старого InfiniteServer (и его клиента) на новую, более производительную архитектуру WraithCore.

Несмотря на то, что ядро полностью изменилось на WraithCore, сама библиотека (DLL) для C# по-прежнему называется InfiniteClient.dll. Это сделано специально для сохранения максимальной совместимости с вашими старыми проектами — вам не придется переписывать using и менять ссылки на библиотеку в ZennoPoster.

Основное преимущество новой версии: больше не нужно запускать тяжелый IInfinitteServer.exe сервер на каждый поток! Теперь работает один общий сервер WraithCore.exe, а потоки подключаются к нему, создавая легковесные «Сессии» через быстрое HTTP-согласование. Это кардинально улучшает скорость работы проекта и стабильность!

🌟 Почему мы перешли на WraithCore?

Переход на новую архитектуру был продиктован необходимостью решить фундаментальные проблемы старого InfiniteServer и заложить мощный фундамент для развития. Вот главные причины:

  1. Рост производительности и экономия ресурсов. Старый подход требовал запуска отдельного тяжеловесного процесса InfiniteServer.exe на каждый рабочий поток в ZennoPoster. Это приводило к огромным накладным расходам CPU и оперативной памяти. Теперь сервер запускается всего один раз, а потоки просто создают внутри него легковесные "сессии", потребляя в разы меньше ресурсов.
  2. Абсолютная стабильность ("Никаких зависаний"). Благодаря отказу от самописного TCP-взаимодействия сокетами и переходу на надежное современное REST API (HTTP), проблемы с "зависанием кубиков", потери пакетов и обрывы связи остались в прошлом. Архитектура надежно изолирована.
  3. Скорость работы и парсинга. Новое ядро WraithCore кардинально оптимизировано для сверхбыстрой обработки DOM-дерева и маршрутизации команд внутри браузера. Парсинг огромных страниц и сложных селекторов отрабатывает моментально.
  4. Повышенная безопасность и Anti-Detect. Метод автоматического запуска браузера из коробки (LaunchBrowser) был намеренно удален. Это не только обезопашивает WraithCore от изменений в документации браузеров, но и дает вам полную свободу: вы сами запускаете браузер с любыми нужными аргументами, портами и флагами. WraithCore выступает как идеальный драйвер, подключаясь к вашему процессу по CDP порту, что критически снижает риск детектирования антифрод-системами.
  5. Современные стандарты кода. Отказ от "строковых" команд в пользу строгой типизации Enums (ActionMouse, ParseAttribute, KeyboardAction и т.д.) сводит к нулю глупые ошибки и опечатки в коде на этапе написания шаблонов. Совместимость со "строковыми" командами сохранена
  6. Отказ от плагинов в пользу гибкой C# библиотеки. C# библиотека предоставляет невероятную гибкость и простоту обновлений: вся сложная логика меняется исключительно "под капотом" в самом WraithCore.exe, поэтому вам не нужно постоянно переустанавливать плагины кубиками. При этом для пользователей, не владеющих программированием, API составлен интуитивно понятно и подробно. Более того, в вашем распоряжении удобный локальный generator.html, который позволяет генерировать готовый C#-код в пару кликов, а также комплексный тестовый шаблон со всеми основными функциями и сниппетами!

⚡️ Краткая суть миграции (Главные отличия)

Если у вас нет времени читать всё руководство, запомните два основных архитектурных изменения:

  1. Замена OpenConnect() на CreateSession(): Мы больше не "открываем соединение" с новым процессом сервера, а "создаем сессию" внутри уже запущенного общего сервера WraithCore.
  2. Удаление запуска браузера "из коробки": Раньше библиотека сама дергала API браузера, теперь вы запускаете его самостоятельно (любым удобным способом) и просто подключаете библиотеку к нему через ConnectToBrowser.

Остальной API остался максимально узнаваемым и совместимым.

1. Запуск сервера и сессии: Было / Стало

Было (Старый подход)

Раньше сервер запускался под каждый поток индивидуально. В кубике C# вы писали:

InfiniteClient.Client client = project.Context["client"] as InfiniteClient.Client;
client.OpenConnect(project, pathToExe);

В конце работы вы обязательно вызывали client.CloseConnect();, чтобы убить этот отдельный серверный процесс.

Стало (Новый подход WraithCore)

Сервер WraithCore.exe запускается ОДИН РАЗ руками или батником перед стартом шаблонов.

В кубике вашего рабочего шаблона подключение выглядит так:

// 1. Создаем сессию на сервере (создается новый браузер).
// "MyBotLogger" — это имя вашего потока/бота для удобного вывода логов в консоль WraithCore.
InfiniteClient.Client client = project.Context["client"] as InfiniteClient.Client;
client.CreateSession(project, "127.0.0.1:8000", "MyBotLogger");// 3. Подключаемся к браузеру по WebSocket (пример)client.ConnectToBrowser("ws://127.0.0.1:9222/devtools/browser/...");

WARNING

Для безопасности и стабильности метод LaunchBrowser был удален. Теперь браузер нужно запускать самостоятельно (через кубики ZennoPoster или Process.Start), передавая ему все необходимые параметры (например, --proxy-server, --user-agent, --headless и др). Это позволяет вам гибко настраивать отпечаток. Готовые примеры запуска и подключения лежат в тестовом шаблоне!

client.Session.Close();
// Альтернативно можно использовать: client.Close();
// Для обратной совместимости старый метод тоже поддерживается: client.CloseConnect();

2. Управление сессиями и эмуляцией

Новая архитектура строится вокруг сессий. Вы можете:

  • client.CreateSession(project, url) — создать новую сессию.
  • client.AttachToSession("uuid") — подключиться к уже запущенной сессии.
  • var list = client.Session.GetList() — получить список активных сессий

Пример переподключения:

var sessions = client.Session.GetList();
if (sessions.Count > 0) 
{ 
client.AttachToSession(sessions[0]); // Подключаемся к первой найденной
}

3. Эмуляция действий пользователя

Теперь вы можете гибко включать и отключать эмуляцию «на лету». Это полезно, когда нужно максимально быстро прокликать меню без движения мыши, а затем снова вернуть человекоподобное поведение:

// Полная эмуляция (плавное движение мыши, случайные задержки набора текста)
client.SetEmulationLevel(EmulationLevel.Full);
// Мгновенные действия (максимальная скорость)
client.SetEmulationLevel(EmulationLevel.None);

Также хочется отметить, что были удалены следующие emun:
LeftClick_notEmuliation, RightClick_notEmuliation, Focus_notEmuliation и т.д. для упрощения и очистки API

4. Обновленные типы данных (Enums)

Код стал строже и логичнее. Там, где раньше (например, в методах клавиатуры) передавались обычные строки, теперь везде используется строгая типизация, что защищает от опечаток (совместимость сохранена)

client.Keyboard("press", "Enter"); //Старый подход
client.Keyboard(KeyboardAction.Press, "Enter"); //Новый подход

Что касается работы с мышью: В старой версии вы привыкли использовать раздельные перечисления RiseBySelector.LeftClick и RiseByCoordinates.LeftClickчто могло вызвать путаницу. Они по-прежнему поддерживаются для совместимости, но в WraithCore добавлен новый универсальный Enum — ActionMouse.

Теперь вам не нужно запоминать и использовать разные Enum в зависимости от того, куда вы кликаете по элементу или по координатам. ActionMouse работает везде:

// Единый стандарт взаимодействия через ActionMouse:
// Legacy код: client.MouseRise("button#submit", RiseBySelector.LeftClick);
// Legacy код: client.MouseRise(500, 300, RiseByCoordinates.RightClick);
client.MouseRise("button#submit", ActionMouse.LeftClick); // Клик по селектору
client.MouseRise(500, 300, ActionMouse.RightClick); // Клик по координатам
client.MouseRise(".slider", ActionMouse.Focus); // Фокус

Это объединение делает код чище и избавляет от дублирования логики при написании шаблонов.

5. Изменения в работе с Трафиком

В новой версии отказались от TCP-сокетов и класса Traffic в пользу чистых REST-запросов и класса NetworkRequest.

Стало

Запросы теперь содержат полные данные: заголовки, статусы, метод.

// Включение мониторинга (с опцией захвата тела ответа и формата)
client.TrafficMonitorStart(TrafficCaptureFormat.Base64, captureBodies: true);
// Получение профильтрованного списка
List<NetworkRequest> requests = client.TrafficMonitorGet();
foreach(NetworkRequest req in requests) 
{ 
    if (req.Url.Contains("api/v1/login")) 
    { 
    project.SendInfoToLog(quot;Найден запрос авторизации: {req.Url}"); 
    project.SendInfoToLog(quot;Тело ответа: {req.ResponseBody}"); 
    // Полное тело ответа! 
    }
}
// Очистка и Остановка (обязательно отключайте для экономии ОЗУ)
client.TrafficMonitorStop();
client.TrafficMonitorClear();

6. Новые функции и улучшения

Помимо кардинального улучшения скорости парсинга и стабильности выполнения в проект добавлены новые супер-фичи:

6.1) Поддержка Shadow DOM (:locator:): Теперь можно искать элементы внутри закрытых теневых деревьев нестандартных сайтов! Используйте EvaluateHandle для захвата, а затем кликайте:

client.EvaluateHandle("document.querySelector('host').shadowRoot.querySelector('btn')");
// Legacy код: client.MouseRise(":locator:", RiseBySelector.LeftClick);
client.MouseRise(":locator:", ActionMouse.LeftClick);

6.2) Динамический Python client.Exec(python_script): Позволяет отправить сложный питон скрипт прямо на сервер для исполнения "по месту". Внутри вашего скрипта у вас есть прямой доступ к переменным page (объект страницы) и context (контекст браузера).

string code = @"
# Прямой доступ к браузеру
title = await page.title()
return title
";
var result = client.Exec(code);

6.2) Продвинутые ожидания загрузки страницы client.WaitForLoadState(...):

    • WaitUntilState.NetworkIdle — Ждать "тишины" сети (идеально для SPA, React/Vue сайтов, догружаемых скриптами).
    • WaitUntilState.DOMContentLoaded — Только DOM дерево (максимальная скорость, не ждет картинки). Включена по умолчанию
    • WaitUntilState.Load— Ждать полной прогрузки страницы
    • WaitUntilState.Commit— Отключается после начала действия навигации

6.3) Метод CheckAny (Умный и быстрый поиск элементов): Ищет любой из переданных селекторов на странице (даже во всех фреймах сразу) и возвращает название появившегося первым. Очень удобно для логики "Что появилось: Капча или Успех?".

var targets = new Dictionary<string, string>
{ 
   { "captcha", "div.g-recaptcha" },
   { "success_message", "div.alert-success" },
   { "error_login", "#login-error" }
};
// Ждем появления любого из этих 3-х элементов (таймаут 10 секунд)
string result = client.CheckAny(targets, 10000);
if (result == "captcha"){
   project.SendInfoToLog("Надо решать капчу!");
   return "Надо решать капчу!";
   }

6.4) Работа с мобильными профилями: Добавлена новая (пока тестовая) возможность работы с мобильными контекстами (задание fingerprint'ов мобильных устройств). Фича будет дорабатываться.

// Переключаем тип девайса для правильной эмуляции мобильных тапов
client.SelectDevice(DeviceType.Mobile);
Так же по умолчанию отключена функция эмуляции "свайпа", при включении скрипт вместо прокрутки колеса мыши, будет старатся эмулировать свай (зажать мышь в центре экрана и протянуть вверх/вниз), включить эту функцию можно с помощью:
client.Settings.SetMobileSwipesEnabled(true);

6.5) Работа с куками:

GetCookies(), ClearCookies(), AddCookies(json) теперь используют стандартные JSON массивы, полностью совместимые с форматами популярных расширений Chrome.

// 1. Получаем ВСЕ куки браузера в формате JSON
string cookiesJson = client.GetCookies();
// 2. Получаем куки только для конкретных URL
string specificCookies = client.GetCookies(new[] { "https://example.com", "https://google.com" });
// 3. Очищаем ВСЕ куки
client.ClearCookies();
// 4. Удаляем куки только для конкретных доменов
client.ClearCookies(new[] { "facebook.com", "instagram.com" });
// 5. Добавляем новые куки из сохраненного профиля
string myCookies = "[{\"name\":\"session_id\",\"value\":\"abc123\",\"domain\":\".example.com\"}]";
client.AddCookies(myCookies);

6.6) Централизованное управление настройками проекта (client.Settings)

В новой архитектуре все глобальные настройки клиентской части вынесены в специальный менеджер client.Settings. Это упрощает управление конфигурацией бота и делает исходный код более читаемым.

Вам больше не нужно искать, в каких методах настраиваются базовые параметры — всё хранится в одном месте:

  • Дополнительное время ожидания HTTP-ответа
client.Settings.CommandTimeout = 10; // Установить
int timeout = client.Settings.CommandTimeout; // Прочитать
  • Эмуляция и Anti-Detect
// Режим Human или мгновенный
client.Settings.SetEmulationLevel(EmulationLevel.Full);
client.Settings.SetEmulationLevel(EmulationLevel.None);
// Движок мыши: Ghost = кривые Безье, Native = прямые линии
client.Settings.SetCursorEngine(CursorEngine.Ghost);
// Скорость мыши и набора текста
client.Settings.SetMouseSpeed(70, 95);
client.Settings.SetTypingSpeed(50, 150);
// Процент опечаток при вводе (0-100)
client.Settings.SetMistakeRate(3);
  • Таймауты и Ожидания
/* Глобальный таймаут ждала появления элементов (сек)
Если не указать в методе, то будет использоватся именно это значение
client.MouseRise("//button");
*/
client.Settings.SetWaitElementTimeout(15.0);
// Что считать "загруженной страницей" для действий навигации
client.Settings.SetWaitUntilState(WaitUntilState.NetworkIdle);
// Нужное состояние элемента перед взаимодействием
client.Settings.SetState(ElementState.Visible); // Элемент должен быть виден
client.Settings.SetState(ElementState.Attached); // Просто в DOM
// Таймаут бездействия сессии (0 = откл)
client.Settings.SetIdleTimeout(300); //Если сессия не активна болеее 300 сек, то она будет закрыта
  • Мобильные устройства
// Переключение между Desktop и Mobile
client.Settings.SelectDevice(DeviceType.Mobile);
// Свайпы пальцем вместо колесика мыши
client.Settings.SetMobileSwipesEnabled(true);
  • Вспомогательные
// Логирование в консоль WraithCore.exe
client.Settings.SetLogging(true);
// Шаг прокрутки колесика (пиксели)
client.Settings.SetMouseWheelStepSize(100);
// Показать/скрыть красный отладочный курсор на странице
client.Settings.EnablesCursorVisibility();
client.Settings.DisablesCursorVisibility();
// Получить все настройки в JSON
string json = client.Settings.Get();
// Массовое обновление через анонимный объект
client.Settings.Update(new { device_type = "mobile", mistake_rate = 5 });