- Регистрация
- 02.06.2015
- Сообщения
- 1 890
- Благодарностей
- 1 631
- Баллы
- 113
Этот проект не предназначен для обхода капч TikTok или других сервисов. Для предотвращения возможных недоразумений я создал офлайн-аналог страницы, имитирующей процесс верификации. Это позволяет тестировать и демонстрировать алгоритм без нарушения правил использования сервисов. Во избежание претензий со стороны соцсети TikTok к ZennoLab, проект реализован в строгом соответствии с правилами и стандартами. Наш форум Zenno.club представляет собой дружелюбное сообщество разработчиков, ориентированное на автоматизацию рутинных задач, а не на взлом систем защиты. Проект создан исключительно в образовательных целях и для участия в конкурсе ZennoLab.
Если кратко: у нас есть два фрагмента изображения, перевернутые в противоположные стороны, а также слайдер, который при перемещении поворачивает их до совпадения.
Программа TikTok Angle Solver предназначена для визуальной настройки параметров, которые затем указываются в библиотеке TikTok Angle Solution и используются в Zenno Poster.
Для наглядности и лучшего понимания я создал файл HTML, который можно открыть в браузере, просто дважды щелкнув по TikTok_.html.
Выберите любое изображение на вашем компьютере.
Появилась капча, похожая на TikTok. Мы видим цель — 123° и слайдер, который пока стоит на 0°.
Теперь нужно передвинуть слайдер, чтобы собрать изображение. Для удобства отображается текущий угол и цель. Когда слайдер перемещается на нужный угол, оба фрагмента изображения начинают вращаться: внутренняя часть (круг) — по часовой стрелке, а внешняя (кольцо) — против часовой.
Интересно, как это работает? Нажмите F12, чтобы открыть DevTools (Инструменты разработчика) и посмотреть код страницы с пояснениями. Или просто откройте файл TikTok_.html в Блокноте.
Обратите внимание на функцию checkCompletion(angle) — в настоящей капче TikTok также учитывается допустимая погрешность.
В функции checkCompletion(angle) можно настроить допустимую погрешность угла для проверки точности. В текущем примере погрешность установлена на 0°, что означает точное совпадение углов. Однако, если нужно учесть небольшие отклонения, вы можете изменить значение погрешности в условии:
Если вы хотите, чтобы погрешность была, например, 1°, просто замените 0 на 1 в условии. Это позволит алгоритму учитывать небольшие отклонения и не считать задачу выполненной только при идеальном совпадении углов.
в DevTools (Инструменты разработчика)
На скриншоте выше обе части изображений (круг и кольцо) закодированы в base64. Мы будем работать именно с ними, чтобы определить угол. Представьте, что строки с подсказкой ('Угол: 123° / Цель: 123°') нет – мы не знаем, какой там угол, и нам нужно вычислить его самостоятельно.
Выберите любое изображение на вашем компьютере.
Появилась капча, похожая на TikTok. Мы видим цель — 123° и слайдер, который пока стоит на 0°.
Теперь нужно передвинуть слайдер, чтобы собрать изображение. Для удобства отображается текущий угол и цель. Когда слайдер перемещается на нужный угол, оба фрагмента изображения начинают вращаться: внутренняя часть (круг) — по часовой стрелке, а внешняя (кольцо) — против часовой.
Интересно, как это работает? Нажмите F12, чтобы открыть DevTools (Инструменты разработчика) и посмотреть код страницы с пояснениями. Или просто откройте файл TikTok_.html в Блокноте.
Обратите внимание на функцию checkCompletion(angle) — в настоящей капче TikTok также учитывается допустимая погрешность.
В функции checkCompletion(angle) можно настроить допустимую погрешность угла для проверки точности. В текущем примере погрешность установлена на 0°, что означает точное совпадение углов. Однако, если нужно учесть небольшие отклонения, вы можете изменить значение погрешности в условии:
Если вы хотите, чтобы погрешность была, например, 1°, просто замените 0 на 1 в условии. Это позволит алгоритму учитывать небольшие отклонения и не считать задачу выполненной только при идеальном совпадении углов.
в DevTools (Инструменты разработчика)
На скриншоте выше обе части изображений (круг и кольцо) закодированы в base64. Мы будем работать именно с ними, чтобы определить угол. Представьте, что строки с подсказкой ('Угол: 123° / Цель: 123°') нет – мы не знаем, какой там угол, и нам нужно вычислить его самостоятельно.
Для подбора подходящих значений порогов фильтров и определения угла поворота изображения было разработано консольное приложение TikTok Angle Solver, написанное на .NET 9. Оно работает в связке с Selenium WebDriver.
Для работы консольного приложения TikTokAngleSolver нужно скачать и установить .NET 9, как показано на скриншоте (выделено красным) - скачать .Net 9
При первом запуске приложения автоматически создаётся файл config.json с настройками, включающими справку и все параметры.
Файл config.json можно редактировать без закрытия приложения — после сохранения в Блокноте (Ctrl + S) настройки обновляются в реальном времени, и нет необходимости постоянно открывать и закрывать файл.
Итак, давайте начнём с настроек. По умолчанию все они включены. Кратко разберём каждый блок настроек.
В папке с программой находится файл manual_corrections.json (файл создается сам при первом обращении), в котором хранятся хеш (в шестнадцатеричном формате) и соответствующее им значение угла. Если включена настройка "EnableHashLookup" (поиск по хешу), то сначала выполняется поиск угла в этом файле. Если совпадений не найдено, угол определяется с помощью фильтров.
Чтобы добавить хеш в словарь, всё просто: нужно ввести угол и нажать Enter. Если хотите пропустить, просто нажмите Enter.
Для создания хеша нужно указать угол
Нажимаем Enter и видим что сработал поиск по хешу.
Что такое перцептивный хэш?
Перцептивный хэш (pHash) — это способ представить изображение в виде короткого цифрового кода, который отражает его визуальное содержание. Он позволяет находить похожие изображения, даже если они были изменены (например, сжаты, осветлены или слегка искажены).
Как это работает:
Например, найденный угол при помощи поиска по хешу:
Если не удалось найти по хешу и в настройках включены соответствующие опции, то автоматически применяется выбранное голосование с фильтрами.
Не сохраняйте хеш для всех возможных углов изображения. Используйте его только в тех случаях, когда фильтры не смогли определить правильный угол.
При первом запуске приложения автоматически создаётся файл config.json с настройками, включающими справку и все параметры.
Файл config.json можно редактировать без закрытия приложения — после сохранения в Блокноте (Ctrl + S) настройки обновляются в реальном времени, и нет необходимости постоянно открывать и закрывать файл.
Итак, давайте начнём с настроек. По умолчанию все они включены. Кратко разберём каждый блок настроек.
Блок GeneralSettings включает несколько важных настроек:
"DefaultToBaseline": true/false — позволяет включить работу с базовым углом по умолчанию, если установлено значение true, или с перевёрнутым углом на 180 градусов, если false.
"EnableFilters": true/false — включает или отключает фильтры. Если фильтры отключены, будет использоваться только угол, выбранный по умолчанию.
"EnableManualCorrection": true/false — управляет возможностью ручной корректировки, определяя, будет ли включена опция для сохранения хеша.
"EnableHashLookup": true/false — отвечает за поиск по хешу в словаре. Файл manual_corrections.json будет автоматически создан при первом сохранении хеша.
"EnableVoting": true/false — включает или отключает голосование фильтров. Если голосование отключено, применяются фильтры из списка ListFilterOrder.
"EnableMajorityVoting": true/false — позволяет выбрать вид голосования. Если включено, используется мажоритарное голосование; если выключено, комбинированное.
"UseWinningAngle": true/false — выбирает результат проголосовавших фильтров. Если включено, выбирается вариант с большей уверенностью, если отключено — с меньшей уверенностью.
По умолчанию включены все опции - true
Давайте начнем с выключения всех настроек и будем постепенно включать их, чтобы наблюдать, как изменяется работа приложения.
Сейчас DefaultToBaseline": false – значит, угол перевернут на 180°
А тут "DefaultToBaseline": true – значит, угол остаётся базовым.
Здесь у нас включён базовый угол, не перевёрнутый, и список активных фильтров.
Далее мы включили ручную корректировку с опцией "EnableManualCorrection": true. Как видите, в консоли появилась возможность задать свой правильный угол или просто нажать Enter, чтобы пропустить.
Затем мы включили поиск по хешу с опцией "EnableHashLookup": true и голосование с опцией "EnableVoting": true. Однако, поскольку следующая опция отключена — "EnableMajorityVoting": false — будет использоваться комбинированное голосование.
На этом этапе мы включили мажоритарное голосование с опцией "EnableMajorityVoting": true. Обратите внимание на результат, выделенный зеленым цветом: уверенность снизилась, а неправильный результат стал правильным. Это связано с тем, что опция "UseWinningAngle": false сейчас отключена — именно эта опция переключает результаты голосования.
Тут снова включены все опции. "UseWinningAngle": true – теперь результаты снова поменялись местами, всё стало на своё место.
Блок ThresholdsSettings включает несколько важных настроек пороговых значений для фильтров:
С подбором настроек особо не заморачивался, на глаз все делал. Но это работает!
Значения нужно подбирать самостоятельно. Ваша цель — установить значение порогов так, чтобы они подходили для большинства изображений в среднем. Например, если у вас есть 100 изображений, пороговые значения следует настроить так, чтобы они подходили хотя бы для 60-75 изображений. Для остальных, которые не подходят, можно использовать словарь с хешами — manual_corrections.json
Блок ListFilterOrder содержит список активных фильтров:
Количество и порядок фильтров могут быть любыми: в списке может быть как один фильтр, так и любое количество из 8 доступных.
Например:
или
или
или
Блок DictionaryFilterWeights содержит словарь весов влияния фильтров:
В этом словаре каждое значение представляет вес фильтра. Можно провести аналогию с ролями в обществе: например, президент имеет наибольшее влияние — его слово закон. Если он сказал, что вода сухая, значит, она сухая, и его вес может быть равен 2 или выше. Директор тоже имеет влияние, он знает, что вода мокрая, но перед президентом его слово будет гораздо менее весомым, и его вес может быть равен 1.5. Учитель, несмотря на свой авторитет, имеет меньшее влияние, его вес может быть равен 1. Сантехник Вася и тракторист Дима имеют одинаковое влияние, их вес может быть равен 0.5. Школьник, с минимальным влиянием, имеет вес, близкий к 0.1. Вес фильтров может быть дробным (например, 0.5 или 1.5), что позволяет гибко настраивать их влияние. Чем выше вес фильтра, тем сильнее его влияние на результат. Вы сами выбираете и устанавливаете вес влияния каждому фильтру на ваше усмотрение.
"DefaultToBaseline": true/false — позволяет включить работу с базовым углом по умолчанию, если установлено значение true, или с перевёрнутым углом на 180 градусов, если false.
"EnableFilters": true/false — включает или отключает фильтры. Если фильтры отключены, будет использоваться только угол, выбранный по умолчанию.
"EnableManualCorrection": true/false — управляет возможностью ручной корректировки, определяя, будет ли включена опция для сохранения хеша.
"EnableHashLookup": true/false — отвечает за поиск по хешу в словаре. Файл manual_corrections.json будет автоматически создан при первом сохранении хеша.
"EnableVoting": true/false — включает или отключает голосование фильтров. Если голосование отключено, применяются фильтры из списка ListFilterOrder.
"EnableMajorityVoting": true/false — позволяет выбрать вид голосования. Если включено, используется мажоритарное голосование; если выключено, комбинированное.
"UseWinningAngle": true/false — выбирает результат проголосовавших фильтров. Если включено, выбирается вариант с большей уверенностью, если отключено — с меньшей уверенностью.
По умолчанию включены все опции - true
Давайте начнем с выключения всех настроек и будем постепенно включать их, чтобы наблюдать, как изменяется работа приложения.
Сейчас DefaultToBaseline": false – значит, угол перевернут на 180°
А тут "DefaultToBaseline": true – значит, угол остаётся базовым.
Здесь у нас включён базовый угол, не перевёрнутый, и список активных фильтров.
Далее мы включили ручную корректировку с опцией "EnableManualCorrection": true. Как видите, в консоли появилась возможность задать свой правильный угол или просто нажать Enter, чтобы пропустить.
Затем мы включили поиск по хешу с опцией "EnableHashLookup": true и голосование с опцией "EnableVoting": true. Однако, поскольку следующая опция отключена — "EnableMajorityVoting": false — будет использоваться комбинированное голосование.
На этом этапе мы включили мажоритарное голосование с опцией "EnableMajorityVoting": true. Обратите внимание на результат, выделенный зеленым цветом: уверенность снизилась, а неправильный результат стал правильным. Это связано с тем, что опция "UseWinningAngle": false сейчас отключена — именно эта опция переключает результаты голосования.
Тут снова включены все опции. "UseWinningAngle": true – теперь результаты снова поменялись местами, всё стало на своё место.
Блок ThresholdsSettings включает несколько важных настроек пороговых значений для фильтров:
С подбором настроек особо не заморачивался, на глаз все делал. Но это работает!
Значения нужно подбирать самостоятельно. Ваша цель — установить значение порогов так, чтобы они подходили для большинства изображений в среднем. Например, если у вас есть 100 изображений, пороговые значения следует настроить так, чтобы они подходили хотя бы для 60-75 изображений. Для остальных, которые не подходят, можно использовать словарь с хешами — manual_corrections.json
Блок ListFilterOrder содержит список активных фильтров:
Количество и порядок фильтров могут быть любыми: в списке может быть как один фильтр, так и любое количество из 8 доступных.
Например:
или
или
или
Блок DictionaryFilterWeights содержит словарь весов влияния фильтров:
В этом словаре каждое значение представляет вес фильтра. Можно провести аналогию с ролями в обществе: например, президент имеет наибольшее влияние — его слово закон. Если он сказал, что вода сухая, значит, она сухая, и его вес может быть равен 2 или выше. Директор тоже имеет влияние, он знает, что вода мокрая, но перед президентом его слово будет гораздо менее весомым, и его вес может быть равен 1.5. Учитель, несмотря на свой авторитет, имеет меньшее влияние, его вес может быть равен 1. Сантехник Вася и тракторист Дима имеют одинаковое влияние, их вес может быть равен 0.5. Школьник, с минимальным влиянием, имеет вес, близкий к 0.1. Вес фильтров может быть дробным (например, 0.5 или 1.5), что позволяет гибко настраивать их влияние. Чем выше вес фильтра, тем сильнее его влияние на результат. Вы сами выбираете и устанавливаете вес влияния каждому фильтру на ваше усмотрение.
В папке с программой находится файл manual_corrections.json (файл создается сам при первом обращении), в котором хранятся хеш (в шестнадцатеричном формате) и соответствующее им значение угла. Если включена настройка "EnableHashLookup" (поиск по хешу), то сначала выполняется поиск угла в этом файле. Если совпадений не найдено, угол определяется с помощью фильтров.
Чтобы добавить хеш в словарь, всё просто: нужно ввести угол и нажать Enter. Если хотите пропустить, просто нажмите Enter.
Для создания хеша нужно указать угол
Нажимаем Enter и видим что сработал поиск по хешу.
Что такое перцептивный хэш?
Перцептивный хэш (pHash) — это способ представить изображение в виде короткого цифрового кода, который отражает его визуальное содержание. Он позволяет находить похожие изображения, даже если они были изменены (например, сжаты, осветлены или слегка искажены).
Как это работает:
- Сжатие изображения — уменьшается размер, убираются мелкие детали.
- Перевод в оттенки серого — цвет не влияет на сравнение.
- Применение DCT (дискретное косинусное преобразование) — выделяются ключевые элементы.
- Создание хэша — получается 64-битная последовательность (нули и единицы), формирующая цифровой «отпечаток» изображения.
- Преобразование в шестнадцатеричный формат — удобное представление для хранения и сравнения.
Например, найденный угол при помощи поиска по хешу:
Если не удалось найти по хешу и в настройках включены соответствующие опции, то автоматически применяется выбранное голосование с фильтрами.
Не сохраняйте хеш для всех возможных углов изображения. Используйте его только в тех случаях, когда фильтры не смогли определить правильный угол.
Для работы в Zenno Poster была специально разработана библиотека TikTok Angle Solution, написанная на .NET Framework 4.7.2
Как подключать любую библиотеку, думаю, знают все уважающие себя пользователи форума zenno.club — этот вопрос уже не раз обсуждался на форуме.
Скопировать саму библиотеку TikTokAngleSolution в папку ExternalAssemblies
В Директивы using и общий код нужно прописать: using TikTokAngleSolution;
Выбрать библиотеку в Ссылки из GAC
Скопировать саму библиотеку TikTokAngleSolution в папку ExternalAssemblies
В Директивы using и общий код нужно прописать: using TikTokAngleSolution;
Выбрать библиотеку в Ссылки из GAC
Прошу обратить внимание на настройку settings.InnerRadiusFactor = 0.3
В файле TikTok_.html изображение делится в соотношении 70 на 30, где 70 — это кольцо, а 30 — круг. Это важно, поскольку в реальной капче TikTok внутренний радиус (круг) может отличаться. Настройка InnerRadiusFactor позволяет регулировать этот параметр и адаптировать алгоритм под различные варианты радиусов.
В библиотеке TikTokAngleSolution убрана настройка EnableManualCorrection (ручная корректировка при добавлении хеша) из-за соображений многопоточной работы. Если кому-то это действительно нужно, вы можете добавить её самостоятельно в исходнике. Хеш добавляется через консольное приложение, и формируется файл, который затем можно переместить в нужную папку и указать путь к этому файлу manual_corrections.json
Указываем настройки все как в консольном приложении в файлике config.json
Весь код кубика "Свой C# код" в Project Maker
C#:
// Создаем объект с настройками решения капчи
CaptchaSolverSettings settings = new CaptchaSolverSettings();
// Включаем режимы работы алгоритма
settings.DefaultToBaseline = true; // Если true — используем базовый угол, если false — перевернутый на 180°
settings.EnableFilters = true; // Включить или выключить использование фильтров для коррекции угла
settings.EnableHashLookup = true; // Использовать поиск хешей в словаре (сравнение по хешам)
settings.EnableVoting = true; // Включить систему голосования, если false то использует только список фильтров без голосования
settings.EnableMajorityVoting = true;// Если true — мажоритарное голосование, если false — комбинированное
settings.UseWinningAngle = true; // Включить использование угла, выбранного большинством голосов (true), или меньшинством голосов (false)
// Указываем путь к файлу (словарю) с корректировками, который используется для поиска изображений по хешу.
// Этот файл в формате JSON содержит данные, где для каждого хеша изображения указан соответствующий угол поворота,
// который используется для корректировки изображения, если его угол не удаётся определить автоматически.
//settings.FilePath = @"D:\ZennoTemplates\TikTokAngleSolver\manual_corrections.json";
settings.FilePath = $"{project.Directory}manual_corrections.json";
// Задаем коэффициент внутреннего радиуса, который определяет размер внутреннего круглого изображения
// относительно общего размера (например, процент от ширины или высоты изображения).
// Значение 0.3 означает, что внутренний круг будет занимать 30% от общего размера.
settings.InnerRadiusFactor = 0.3;
// Устанавливаем пороговые значения различных параметров обработки изображения
settings.PixelDifferenceThreshold = 130; // Минимальная разница пикселей для обнаружения изменений
settings.BrightnessThreshold = 10; // Порог яркости (насколько сильны изменения в освещении)
settings.ContoursThreshold = 1.5; // Порог обнаружения контуров (определяет резкость границ)
settings.VerticalGradientThreshold = 50; // Порог вертикального градиента (анализ вертикальных изменений)
settings.ColorHistogramThreshold = 1.5; // Порог цветовой гистограммы (различия в цветах)
settings.SymmetryThreshold = 1.2; // Порог симметрии (анализирует, насколько изображение симметрично)
settings.DarkPixelThresholdAtBottom = 50;// Порог темных пикселей внизу изображения
// Определяем список активных фильтров, которые будут применяться к изображению
settings.ActiveFilters = new List<CorrectionFilter>
{
CorrectionFilter.PixelDifference, // Фильтр по разнице пикселей
CorrectionFilter.Brightness, // Фильтр по яркости
CorrectionFilter.VerticalGradient, // Фильтр по вертикальному градиенту
CorrectionFilter.Contours, // Фильтр по контурам
CorrectionFilter.RotatedBrightness, // Фильтр яркости с учетом поворота
CorrectionFilter.Symmetry, // Фильтр симметрии
CorrectionFilter.DarkPixelsAtBottom // Фильтр темных пикселей внизу
};
// Определяем словарь весов для каждого фильтра, где ключ - название фильтра, а значение - его вес (значимость).
settings.FilterWeights = new Dictionary<string, double>
{
{ "PixelDifference", 1.0 }, // Разница пикселей
{ "Brightness", 1.0 }, // Яркость изображения
{ "Contours", 1.0 }, // Выявление контуров
{ "VerticalGradient", 1.0 }, // Вертикальный градиент яркости
{ "ColorHistogram", 1.0 }, // Гистограмма цветов
{ "Symmetry", 1.0 }, // Оценка симметрии
{ "RotatedBrightness", 1.0 }, // Яркость после поворота
{ "DarkPixelsAtBottom", 1.0 } // Количество тёмных пикселей в нижней части изображения
};
// Извлекаем изображение центра (круга) из HTML-элемента и преобразуем в строку Base64
HtmlElement htmlCenter = instance.ActiveTab.FindElementByXPath("//*[@id='center-image']", 0);
if (htmlCenter.IsVoid) throw new Exception("Не удалось найти элемент для получения центра изображения!");
string base64CenterImage = htmlCenter.GetAttribute("src").Replace("data:image/png;base64,", "");
// Извлекаем изображение внешней части (кольца) из HTML-элемента и преобразуем в строку Base64
HtmlElement htmlOuter = instance.ActiveTab.FindElementByXPath("//*[@id='outer-image']", 0);
if (htmlOuter.IsVoid) throw new Exception("Не удалось найти элемент для получения кольца изображения!");
string base64OuterImage = htmlOuter.GetAttribute("src").Replace("data:image/png;base64,", "");
// Создаем объект CaptchaSolver и передаем настройки через метод SetSettings
CaptchaSolver solver = new CaptchaSolver();
solver.SetSettings(settings);
// Передаем изображения в обработчик и получаем угол поворота
int angle = solver.FindTargetAngleFromBase64Async(base64CenterImage, base64OuterImage).GetAwaiter().GetResult();
// Сохраняем результат в переменную проекта
project.Variables["angle"].Value = angle.ToString();
// Возвращаем угол
return angle;
Также решил поделиться исходниками на случай, если кто-то захочет внести свои дополнения, расширить функционал или продолжить развитие проекта.
Вот такая интересная и полезная разработка у меня получилась. Уверен, что она найдет свое применение и сможет принести пользу.

Вложения
-
6,7 КБ Просмотры: 8
-
7,7 МБ Просмотры: 8
-
11 КБ Просмотры: 8
-
28 КБ Просмотры: 8
-
23 КБ Просмотры: 9
-
19,8 КБ Просмотры: 8
-
64,3 МБ Просмотры: 8
Последнее редактирование: