Перейти до вмісту

Найкращі практики та непомітність

Це правила, які роблять автоматизацію Santiago одночасно швидкою та невиявлюваною. Дотримуйтесь їх — і типовий потік заповнення форми виконується за кілька сотень мілісекунд на сторінку з гуманізованим, довіреним введенням; знехтуйте ними — і ви або зливаєте події isTrusted: false антибот-системам, або марнуєте десятки секунд на сліпі очікування.

Усі приклади звертаються до локального демона. Задайте ID профілю один раз, потім викликайте лише дії /api/automation/$PROFILE/*:

Set the profile
PROFILE=<profile-id>

Оболонка відповіді завжди має вигляд { "ok": true, "data": {...} } або { "ok": false, "error": { "code", "message" } }.

Непомітність: evaluate лише для читання

Section titled “Непомітність: evaluate лише для читання”

evaluate виконує JavaScript сторінки через протокол налагодження. Сам протокол невидимий для сторінки, але те, що ваш код робить усередині evaluate, повністю видиме скриптам сайту. Використовуйте його для читання, ніколи для взаємодії.

Безпечно (невидимо для сторінки)Заборонено (виявлюване, обходить humanize)
document.titleelement.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, повністю його обходить.

Read coords with evaluate, then click them
# OK -- evaluate stays read-only
curl -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 read
curl -s localhost:7891/api/automation/$PROFILE/mouse/click -X POST \
-H 'Content-Type: application/json' -d '{"x":512,"y":340}'
FORBIDDEN -- detectable, bypasses humanize
# 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 — основний інструмент заповнення форм

Section titled “fill-page — основний інструмент заповнення форм”

fill-page — вибір за замовчуванням для будь-якої форми. Він повністю обходить локатори Playwright (evaluatemouse.clickkeyboard.type), тож працює на складних, анімованих сторінках та сторінках із переходами, де дії на основі ref застрягають на перевірках стабільності. Він обробляє текстові поля та випадні списки combobox і включає відправлення у тому ж виклику.

Fill all fields and submit in one call
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 (з відліком від 0): коли selector відповідає кільком видимим елементам, обирає N-й — [role=combobox] з nth: 0 це перший, nth: 1 — другий.

Використовуйте batch для неформних дій (кліки по посиланнях, hover, навігація, очікування) або коли потрібне націлювання на основі ref зі знімка. fill-form застарілий — він спершу пробує локатор (2с) і відкочується до координат; надавайте перевагу fill-page.

Дивіться Заповнення форм для повного робочого прикладу потоку.

Нативний <select> проти ARIA combobox

Section titled “Нативний <select> проти ARIA combobox”

Те, як випадний список з’являється у знімку, визначає ендпоінт.

Знімок показуєВикористовуйтеПоведінка
<select> (нативний елемент)select-option з values[]встановлює нативне значення напряму
роль combobox (ARIA)select-combobox з valueклік → очікування listbox → клік по опції, один виклик
Native select
curl -s localhost:7891/api/automation/$PROFILE/select-option -X POST \
-H 'Content-Type: application/json' -d '{"ref":"e2","values":["California"]}'
ARIA combobox
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 по цих координатах (довірений, гуманізований):

Detached-overlay dropdown fallback
# 1. Open the dropdown with a real click
curl -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-only
curl -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 — пересніміть лише при зміні сторінки

Section titled “Один знімок, один batch — пересніміть лише при зміні сторінки”

Зробіть один знімок, визначте всі потрібні елементи, потім надішліть один виклик batch з усіма діями. Ніколи не переснімайте між діями на тій самій сторінці.

The shape of a good flow
snapshot (~110ms) -> batch of N actions (N x ~200ms) -> done

Робіть новий знімок лише тоді, коли сторінка фундаментально змінюється:

  • навігація на новий URL,
  • відправлення форми, що завантажує нову сторінку,
  • модальне вікно чи оверлей, що замінює вміст сторінки.

Не переснімайте після заповнення полів, відкриття випадних списків, набору тексту чи hover. Ref’и (e1, e2, …) залишаються дійсними, доки сторінка не зміниться; вони стають недійсними лише після навігації, відправлення на новий URL, перезавантаження чи динамічного вмісту, що замінює DOM.

Batch зупиняється на першій помилці — якщо дія провалюється (неправильний ref, елемент не знайдено), решта дій пропускаються. Перевірте масив results ({ index, action, ok, data?, error? }), щоб знайти провалену дію, виправте її та перезапустіть із цієї точки.

Ніколи не додавайте sleep

Section titled “Ніколи не додавайте sleep”

Playwright автоматично очікує на елементи перед дією, а ендпоінт batch уже додає випадкові затримки 80–250мс між діями для людиноподібного темпу. Обгортання викликів у sleep 1 / sleep 2 && curl … — чисте марнування, яке накопичується у десятки секунд по всьому потоку.

Якщо потік відчувається повільнішим за очікуваний більш ніж у ~2 рази, причина майже завжди — доданий sleep або пересніма посеред сторінки — приберіть обидва.

Коли вам справді потрібно дочекатись конкретного сигналу, використовуйте wait з умовою, ніколи сліпий таймаут:

Wait for a real signal, not a clock
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"}'

Повтор має змінювати стратегію

Section titled “Повтор має змінювати стратегію”

Якщо дія провалилась, повтор із тими самими параметрами провалиться так само. Кожен повтор має щось змінювати — інший ендпоінт, інший селектор, клавіатуру замість миші. Повторне читання поточної помилки перед повтором обов’язкове.

Найочевидніший приклад: select-combobox завершується таймаутом на прихованому listbox #cN. Не запускайте його знову — перемкніться на стратегію відкриття-кліком → читання координат → mouse/click вище. Таймаут дії становить 2 секунди (не дефолтні 30с Playwright), тож провалені спроби дешеві; витрачайте цю дешевизну на новий підхід, а не на той самий п’ять разів.

Чекліст налагодження перед зміною стратегії

Section titled “Чекліст налагодження перед зміною стратегії”

Один evaluate лише для читання, що повертає ці чотири значення, підкаже, яка стратегія спрацює, перш ніж ви спалите повтори:

  1. document.activeElement — чи потрапив фокус туди, куди ви очікували?
  2. aria-expanded на combobox’і — чи він справді відкрився?
  3. aria-activedescendant — яка опція підсвічена?
  4. getBoundingClientRect().y проти window.innerHeight — чи ціль взагалі у видимій області?

Набір з клавіатури для впертих випадних списків

Section titled “Набір з клавіатури для впертих випадних списків”

Коли fill-page / select-combobox не підходять (кастомна розмітка combobox, прокручувані listbox’и, опції яких лежать поза видимою областю, кліки миші, що не дають фокус), спершу перемкніться на клавіатуру, а не на координатні хаки. Координатні кліки миші по опціях listbox мають бути крайнім засобом — вони вимагають, щоб опція була всередині видимої області та всередині власного clip rect listbox’а, а прокручування listbox ненадійне.

  • Набір з підказкою на 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).
Type-ahead a birth year into a combobox
# 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 time
for 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 selection
curl -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.