Найкращі практики та непомітність
Це правила, які роблять автоматизацію Santiago одночасно швидкою та невиявлюваною. Дотримуйтесь їх — і типовий потік заповнення форми виконується за кілька сотень мілісекунд на сторінку з гуманізованим, довіреним введенням; знехтуйте ними — і ви або зливаєте події isTrusted: false антибот-системам, або марнуєте десятки секунд на сліпі очікування.
Усі приклади звертаються до локального демона. Задайте ID профілю один раз, потім викликайте лише дії /api/automation/$PROFILE/*:
PROFILE=<profile-id>Оболонка відповіді завжди має вигляд { "ok": true, "data": {...} } або { "ok": false, "error": { "code", "message" } }.
Непомітність: evaluate лише для читання
Section titled “Непомітність: 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 — основний інструмент заповнення форм
Section titled “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(з відліком від 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 → клік по опції, один виклик |
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 — пересніміть лише при зміні сторінки
Section titled “Один знімок, один batch — пересніміть лише при зміні сторінки”Зробіть один знімок, визначте всі потрібні елементи, потім надішліть один виклик batch з усіма діями. Ніколи не переснімайте між діями на тій самій сторінці.
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 з умовою, ніколи сліпий таймаут:
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 лише для читання, що повертає ці чотири значення, підкаже, яка стратегія спрацює, перш ніж ви спалите повтори:
document.activeElement— чи потрапив фокус туди, куди ви очікували?aria-expandedна combobox’і — чи він справді відкрився?aria-activedescendant— яка опція підсвічена?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).
# 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"}'Швидка довідка
Section titled “Швидка довідка”| Симптом | Зробіть це |
|---|---|
| ”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. |
Пов’язані сторінки
Section titled “Пов’язані сторінки”- Огляд автоматизації — що таке API автоматизації та як він вписується у демон.
- Основи HTTP API — базовий URL, оболонка відповіді та область профілю.
- Довідник API — кожен ендпоінт та його параметри.
- Запуск профілів — запустіть профіль, перш ніж автоматизувати його.
- Заповнення форм — ці правила застосовані наскрізно.