--- title: Обработать защитную проверку description: Распознайте challenge, получите решение и безопасно повторите запрос. freshness: false --- Guard нужен, когда сайт вместо обычного ответа возвращает защитную проверку. Он распознаёт помеху, вызывает типизированный solver, применяет решение и заново готовит исходный запрос в той же транспортной сессии. ## Выбрать готовую защиту Установите пакет с поддерживаемыми пресетами: ```bash uv add "eazy-sdk-core[presets]" ``` Готовые страницы описывают настройку {doc}`Cloudflare Challenge Pages `, {doc}`Turnstile ` и {doc}`reCAPTCHA `. Пресет устанавливается в корне SDK через `ClientConfig(security=Security.of(guard))`. ## Объявить свой guard Пример сайта требует captcha после отправки пароля. HTTP-клиент решает её cookie, а браузер нажимает кнопку внутри той же операции. :::::{tab-set} :sync-group: transport ::::{tab-item} HTTP :sync: http `detect(...)` возвращает `LoginCaptcha` только для знакомого ответа `403`. `solve(...)` получает `SolveContext` и создаёт решение с cookie через `self.solution(...)`. ```{literalinclude} ../../../../../examples/mail/http/captcha_probe.py :language: python :start-after: "# region docs: http-captcha-guard" :end-before: "# endregion docs: http-captcha-guard" ``` Guard устанавливается один раз в `ClientConfig`. После решения runtime повторяет отклонённый password-запрос в пределах бюджета `max_replays=1`. ```{literalinclude} ../../../../../examples/mail/http/captcha.py :language: python :start-after: "# region docs: http-captcha-flow" :end-before: "# endregion docs: http-captcha-flow" ``` ```{literalinclude} ../../../../../examples/docs/protection.py :language: python :start-after: "# region docs: protection-run" :end-before: "# endregion docs: protection-run" ``` :::: ::::{tab-item} Браузер :sync: browser Браузер видит настоящую страницу проверки: ```{literalinclude} ../../../../../examples/mail/site/app.py :language: html :start-after: "" :end-before: "" ``` `Handle` следит за элементом captcha, нажимает кнопку и возвращает управление исходной `BrowserOperation`. Для вызывающего переход к `OtpStep` остаётся одним методом. ```{literalinclude} ../../../../../examples/mail/browser/captcha.py :language: python :start-after: "# region docs: browser-captcha-operation" :end-before: "# endregion docs: browser-captcha-operation" ``` :::: ::::: | Ответ сайта | Что делает правило | Что получает вызывающий | |---|---|---| | Обычный ответ | `detect(...)` возвращает `None` | Результат операции | | Знакомая помеха | Solver создаёт `GuardSolution` | Результат повторённой операции | | Повреждённая помеха | Detector сообщает ошибку разбора | Типизированную ошибку стадии | | Бюджет исчерпан | Повтор запрещён | `ReplayDeniedError` | :::{dropdown} Запускаемый файл целиком ```{literalinclude} ../../../../../examples/docs/protection.py :language: python ``` ::: ```text challenge: mail-login password requests: 2 clearance cookie: login_clearance=solved result: OtpStep ``` ## Настроить область, хранение и повтор | Атрибут | Назначение | |---|---| | `scope` | Ограничивает правило хостом, операцией или другим `RequestScope` | | `cache="none"` | Решение не покидает текущую попытку | | `cache="call"` | Решение повторно используется только внутри одного вызова | | `cache="session"` | Решение разделяется вызовами одной транспортной сессии | | `replay` | Задаёт доказательство безопасности и число повторов | | `revision` | Отделяет новое правило от ранее сохранённых решений | `headers`, `query` и `body` объявляют назначения, которые разрешено менять решению. Для cookie отдельное разрешение не требуется. Кэш можно очистить методом `client.invalidate_protection(...)` для конкретного guard, имени политики или всей сессии. ## Решать в той же транспортной сессии `context.fetch(...)` загружает вспомогательный ресурс через тот же handler, proxy и cookie jar. Такой запрос обходит guards, middleware, rate limit и повтор, поэтому solver не вызывает сам себя. Каждый полученный `Set-Cookie` остаётся в сессии защищённого вызова. `context.identity` описывает `User-Agent`, объявленный proxy и метку impersonation. Сохранённое решение привязано к этому отпечатку и сбрасывается при смене сетевой личности. :::{warning} Если solver использует отдельный браузер или HTTP-клиент вместо `context.fetch(...)`, он сам должен сохранить тот же proxy, `User-Agent`, TLS-отпечаток и cookies. ::: ## Разобрать ошибку стадии | Ошибка | Стадия | |---|---| | `ProtectionConfigurationError` | Некорректная схема до транспортного вызова | | `ChallengeDetectionError` | Неожиданная ошибка detector | | `ChallengeParseError` | Помеха распознана, но её данные повреждены | | `ChallengeSolveError` | Solver не получил решение | | `ChallengeApplicationError` | Решение нельзя безопасно применить | | `ReplayDeniedError` | Нет доказанного или доступного повтора | Ошибки сохраняют исходное исключение в `__cause__`, но не включают тело ответа, cookies или credentials в собственное сообщение. Низкоуровневые контракты генераторов находятся в `eazy_sdk.protection.advanced`; прикладному SDK обычно достаточно `Guard` или готового пресета. ## Дальше - {doc}`Решить captcha в учебном SDK ` - {doc}`Подключить Cloudflare Challenge Pages ` - {doc}`Справочник защиты `