Лучшие практики и незаметность
Это правила, которые делают автоматизацию Santiago одновременно быстрой и необнаружимой. Следуйте им — и типичный поток заполнения формы выполняется за несколько сотен миллисекунд на страницу с очеловеченным, доверенным вводом; игнорируйте их — и вы либо отдаёте события isTrusted: false антибот-системам, либо тратите десятки секунд на слепые ожидания.
Все примеры обращаются к локальному демону. Задайте ID профиля один раз, затем вызывайте только действия /api/automation/$PROFILE/*:
PROFILE=<profile-id>Конверт ответа всегда имеет вид { "ok": true, "data": {...} } или { "ok": false, "error": { "code", "message" } }.
Незаметность: evaluate только для чтения
Заголовок раздела «Незаметность: evaluate только для чтения»evaluate выполняет JavaScript страницы через протокол отладки. Сам протокол невидим для страницы, но то, что делает ваш код внутри evaluate, полностью видно скриптам сайта. Используйте его для чтения, никогда — для взаимодействия.
| Безопасно (невидимо для страницы) | Запрещено (обнаружимо, обходит humanize) |
|---|---|
document.title | element.click() |
querySelectorAll, значения атрибутов | element.focus() |
getBoundingClientRect() (координаты элемента) | element.dispatchEvent(...) |
| вычисленные стили | присваивание element.value = ... |
чтение document.activeElement, aria-expanded | программный form.submit(), прокрутка |
Синтетический element.click() порождает MouseEvent с isTrusted: false, clientX/Y: 0 и без предшествующих mousemove / pointerdown / mouseover. Современные антибот-системы напрямую помечают isTrusted: false. Когда у профиля включён humanize, Camoufox добавляет движение курсора по кривой Безье только к нативным действиям Playwright — всё, что вы делаете через evaluate, обходит это полностью.
# OK -- evaluate stays read-onlycurl -s localhost:7891/api/automation/$PROFILE/evaluate -X POST \ -H 'Content-Type: application/json' \ -d '{"code":"JSON.stringify(document.querySelector(\"#btn\").getBoundingClientRect())"}'
# Trusted, humanized click on the coords you just readcurl -s localhost:7891/api/automation/$PROFILE/mouse/click -X POST \ -H 'Content-Type: application/json' -d '{"x":512,"y":340}'# curl ... /evaluate -d '{"code":"document.querySelector(\"#btn\").click()"}'# curl ... /evaluate -d '{"code":"document.querySelector(\"input\").value = \"x\""}'# curl ... /evaluate -d '{"code":"form.submit()"}'fill-page — основной инструмент заполнения форм
Заголовок раздела «fill-page — основной инструмент заполнения форм»fill-page — выбор по умолчанию для любой формы. Он полностью обходит локаторы Playwright (evaluate → mouse.click → keyboard.type), поэтому работает на сложных, анимированных и переходных страницах, где действия на основе ref застревают на проверках стабильности. Он обрабатывает текстовые поля и выпадающие списки combobox и включает отправку в том же вызове.
curl -s localhost:7891/api/automation/$PROFILE/fill-page -X POST \ -H 'Content-Type: application/json' -d '{ "fields": [ {"selector": "#firstName", "value": "Daniel"}, {"selector": "#lastName", "value": "Moreno"}, {"selector": "[role=combobox]", "value": "March", "type": "combobox", "nth": 0}, {"selector": "[role=combobox]", "value": "Male", "type": "combobox", "nth": 1} ], "submit": {"text": "Next"}, "waitAfterSubmit": 2500 }'# Response: { results: [{selector, type, ok, selectedValue?}], submit: {ok, url} }Типы полей:
"text"(по умолчанию): клик в центр → Ctrl+A → Backspace →keyboard.type."combobox": клик, чтобы открыть → поиск опции по тексту → клик по опции → проверка и авто-повтор.nth(с нуля): когдаselectorсовпадает с несколькими видимыми элементами, выбирает N-й —[role=combobox]сnth: 0это первый,nth: 1— второй.
Используйте batch для действий, не связанных с формами (клики по ссылкам, наведение, навигация, ожидание), или когда нужно нацеливание по ref из снимка. fill-form устарел — он сначала пробует локатор (2с) и откатывается на координаты; предпочитайте fill-page.
См. Заполнение форм для полного разобранного потока.
Нативный <select> vs ARIA combobox
Заголовок раздела «Нативный <select> vs ARIA combobox»То, как выпадающий список выглядит в снимке, определяет эндпоинт.
| Снимок показывает | Используйте | Поведение |
|---|---|---|
<select> (нативный элемент) | select-option с values[] | задаёт нативное значение напрямую |
роль combobox (ARIA) | select-combobox с value | клик → ожидание listbox → клик по опции, один вызов |
curl -s localhost:7891/api/automation/$PROFILE/select-option -X POST \ -H 'Content-Type: application/json' -d '{"ref":"e2","values":["California"]}'curl -s localhost:7891/api/automation/$PROFILE/select-combobox -X POST \ -H 'Content-Type: application/json' -d '{"ref":"e5","value":"March"}'Некоторые сайты рендерят listbox в отдельном оверлее вне цели aria-controls у combobox. Тогда select-combobox завершается по таймауту с “locator #cN is hidden”. Не повторяйте select-combobox — вместо этого откройте выпадающий список настоящим click, прочитайте координаты центра опции через evaluate (только чтение), затем сделайте mouse/click по этим координатам (доверенный, очеловеченный):
# 1. Open the dropdown with a real clickcurl -s localhost:7891/api/automation/$PROFILE/click -X POST \ -H 'Content-Type: application/json' -d '{"ref":"e102"}'
# 2. Read the target option's center -- evaluate stays read-onlycurl -s localhost:7891/api/automation/$PROFILE/evaluate -X POST \ -H 'Content-Type: application/json' \ -d '{"code":"const o = Array.from(document.querySelectorAll(\"li[role=option]\")).filter(e => e.offsetParent !== null).find(e => e.textContent.trim() === \"June\"); const r = o.getBoundingClientRect(); JSON.stringify({x: r.x + r.width/2, y: r.y + r.height/2})"}'
# 3. Click the coords with the mouse (trusted, humanized)curl -s localhost:7891/api/automation/$PROFILE/mouse/click -X POST \ -H 'Content-Type: application/json' -d '{"x":512,"y":340}'Один снимок, один batch — пересоздавайте снимок только при смене страницы
Заголовок раздела «Один снимок, один batch — пересоздавайте снимок только при смене страницы»Сделайте один снимок, определите все нужные элементы, затем отправьте один batch-вызов со всеми действиями. Никогда не пересоздавайте снимок между действиями на одной странице.
snapshot (~110ms) -> batch of N actions (N x ~200ms) -> doneДелайте новый снимок только когда страница фундаментально меняется:
- переход на новый URL,
- отправка формы, загружающая новую страницу,
- модальное окно или оверлей, заменяющие содержимое страницы.
Не пересоздавайте снимок после заполнения полей, открытия выпадающих списков, ввода или наведения. Ссылки (e1, e2, …) остаются валидными, пока страница не изменится; они устаревают только после навигации, отправки на новый URL, перезагрузки или динамического содержимого, заменяющего DOM.
Batch останавливается на первой ошибке — если действие провалилось (неверный ref, элемент не найден), оставшиеся действия пропускаются. Изучите массив results ({ index, action, ok, data?, error? }), чтобы найти провалившееся действие, исправьте его и перезапустите с этой точки.
Никогда не добавляйте sleep
Заголовок раздела «Никогда не добавляйте sleep»Playwright автоматически ждёт элементы перед действием, а эндпоинт batch уже добавляет случайные задержки 80–250мс между действиями для человекоподобного темпа. Оборачивание вызовов в sleep 1 / sleep 2 && curl … — чистая трата, которая складывается в десятки секунд на протяжении потока.
Если поток кажется более чем в ~2 раза медленнее ожидаемого, причина почти всегда в добавленном sleep или пересоздании снимка посреди страницы — уберите и то, и другое.
Когда вам действительно нужно дождаться конкретного сигнала, используйте wait с условием, никогда — слепой таймаут:
curl -s localhost:7891/api/automation/$PROFILE/wait -X POST \ -H 'Content-Type: application/json' -d '{"text":"Success"}'
curl -s localhost:7891/api/automation/$PROFILE/wait -X POST \ -H 'Content-Type: application/json' -d '{"selector":".loaded","state":"visible"}'
curl -s localhost:7891/api/automation/$PROFILE/wait -X POST \ -H 'Content-Type: application/json' -d '{"selector":".spinner","state":"hidden"}'Повтор должен менять стратегию
Заголовок раздела «Повтор должен менять стратегию»Если действие провалилось, повтор с теми же параметрами провалится так же. Каждый повтор должен что-то менять — другой эндпоинт, другой селектор, клавиатуру вместо мыши. Перечитывание текущей ошибки перед повтором обязательно.
Самый наглядный пример: select-combobox завершается по таймауту на скрытом listbox #cN. Не запускайте его снова — переключитесь на стратегию открытие-кликом → чтение-координат → mouse/click выше. Таймаут действия — 2 секунды (а не дефолтные 30с у Playwright), поэтому провальные попытки дёшевы; потратьте эту дешевизну на новый подход, а не на тот же самый пять раз.
Чек-лист отладки перед сменой стратегии
Заголовок раздела «Чек-лист отладки перед сменой стратегии»Один evaluate только для чтения, возвращающий эти четыре значения, скажет вам, какая стратегия сработает, прежде чем вы спалите повторы:
document.activeElement— приземлился ли фокус туда, куда вы ожидали?aria-expandedна combobox — действительно ли он открылся?aria-activedescendant— какая опция подсвечена?getBoundingClientRect().yvswindow.innerHeight— находится ли цель вообще во вьюпорте?
Ввод с упреждением (type-ahead) для упрямых выпадающих списков
Заголовок раздела «Ввод с упреждением (type-ahead) для упрямых выпадающих списков»Когда fill-page / select-combobox не подходят (нестандартная разметка combobox, прокручиваемые listbox с опциями за пределами вьюпорта, клики мыши не дают фокус), сначала переключайтесь на клавиатуру, а не на хаки с координатами. Клики мышью по опциям listbox должны быть последним средством — они требуют, чтобы опция была внутри вьюпорта и внутри собственной обрезающей области listbox, а прокрутка listbox ненадёжна.
- Type-ahead на combobox — откройте через
Enterили клик, затемpress-keyцелевое значение посимвольно (1,9,9,3для года1993). Большинство ARIA-combobox сразу прыгают к совпадению, минуя любую гимнастику соscrollTop. Подтвердите черезEnter. Tabдля перемещения фокуса — когда клик отказывается дать фокус элементу или кнопка отправки ниже вьюпорта, а прокрутка колесом перехватывается, делайтеTabот последнего известного сфокусированного элемента, покаdocument.activeElement.textContentне совпадёт, затем активируйте черезEnter.ArrowDown× N +Enter— работает для коротких списков опций (≤5 пунктов, например Gender: Female / Male / Custom).
# Open the combobox with a real click (trusted)curl -s localhost:7891/api/automation/$PROFILE/click -X POST \ -H 'Content-Type: application/json' -d '{"ref":"e12"}'
# Type-ahead the value, one key at a timefor k in 1 9 9 3; do curl -s localhost:7891/api/automation/$PROFILE/press-key -X POST \ -H 'Content-Type: application/json' -d "{\"key\":\"$k\"}"done
# Commit the selectioncurl -s localhost:7891/api/automation/$PROFILE/press-key -X POST \ -H 'Content-Type: application/json' -d '{"key":"Enter"}'Быстрая справка
Заголовок раздела «Быстрая справка»| Симптом | Что делать |
|---|---|
| ”Ref eN not found” | Страница изменилась. Пересоздайте снимок. |
select-option падает: “not a select element” | Это ARIA combobox — используйте select-combobox. |
select-combobox таймаутится на скрытом #cN | Отдельный оверлей. Не повторяйте — откройте через click, прочитайте координаты через evaluate, mouse/click. |
locator.scrollIntoViewIfNeeded: Timeout | Элемент анимируется. Используйте fill-page (по координатам); переключите всю страницу. |
| Снимок слишком большой | Ограничьте область: {"selector":"#main","depth":5}. |
| Элемент не виден | mouse/wheel {"deltaY":500}, затем пересоздайте снимок. |
| Поток кажется в >2 раза медленнее | Вы добавили sleep или пересоздали снимок посреди страницы. Уберите и то, и другое. |
Нужно кликнуть что-то, найденное через evaluate | Прочитайте getBoundingClientRect(), затем mouse/click {x, y}. Никогда .click() в evaluate. |
Связанные страницы
Заголовок раздела «Связанные страницы»- Обзор автоматизации — что такое API автоматизации и как он вписывается в демон.
- Основы HTTP API — базовый URL, конверт ответа и область профиля.
- Справочник API — каждый эндпоинт и его параметры.
- Запуск профилей — запустите профиль, прежде чем автоматизировать его.
- Заполнение форм — эти правила, применённые от начала до конца.