Автоматизация профилей браузера через локальный API

Запустите профиль из скрипта, получите в ответ endpoint отладки и подключите Playwright или Puppeteer к браузеру, у которого уже есть своя идентичность и прокси.
Автоматизацию антидетект-браузера обычно подают как сложную задачу. Это не так, если инструмент отдаёт вам единственное, что ваша библиотека автоматизации и так умеет использовать: endpoint отладки.
Общая схема
PowerOps запускает HTTP API, привязанный к адресу loopback. Ваш скрипт просит его запустить профиль; он запускает браузер с уже подключёнными идентичностью, хранилищем и прокси этого профиля и возвращает WebSocket-endpoint запущенного браузера. Ваш скрипт подключается к этому endpoint через Playwright, Puppeteer или что-либо ещё, понимающее протокол DevTools.
Библиотеке автоматизации не нужно знать, что такое отпечаток. К моменту подключения среда уже готова.
Запуск профиля
curl -s -H "Authorization: Bearer $POWEROPS_API_KEY" \
http://127.0.0.1:50326/status
Каждый маршрут, кроме проверки состояния, требует ключа-носителя (bearer). Запуск браузера возвращает endpoint для подключения:
curl -s -X POST \
-H "Authorization: Bearer $POWEROPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profileId": "..."}' \
http://127.0.0.1:50326/browser/start
Подключение вашей библиотеки
import { chromium } from "playwright";
const res = await fetch("http://127.0.0.1:50326/browser/start", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.POWEROPS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ profileId }),
});
const { ws } = await res.json();
// The profile's identity, storage and proxy are already in place.
const browser = await chromium.connectOverCDP(ws);
const [context] = browser.contexts();
const page = context.pages()[0] ?? await context.newPage();
await page.goto("https://example.com");
Важная строка здесь — комментарий. В вашем скрипте нет настройки отпечатка, потому что настройка среды — не задача скрипта. Она принадлежит профилю и остаётся одной и той же, открывает ли профиль человек щелчком по строке или запланированное задание в три часа ночи.
Что покрывает API
- Маршрут состояния — проверка работоспособности, и единственный, которому не нужен ключ.
- Маршруты браузера запускают, останавливают и запрашивают браузеры, которые сейчас работают.
- Маршруты профилей создают, обновляют, запрашивают и удаляют профили.
- Маршруты прокси управляют библиотекой прокси и назначают маршруты.
- Маршруты групп организуют профили массово.
- Маршруты расширений импортируют и назначают расширения.
Как он остаётся локальным
API, управляющий браузерами с авторизованными аккаунтами, заслуживает слова о своих границах.
- Он привязан к 127.0.0.1. Нет настройки, которая заставила бы его слушать другой интерфейс.
- Ключ-носитель требуется на каждом маршруте, кроме проверки состояния.
- Он проверяет заголовок Host и не отправляет заголовков CORS, поэтому веб-страница, открытая в вашем обычном браузере, не может до него достучаться.
- Секреты только для записи: пароли профилей, секреты двухфакторной аутентификации и пароли прокси никогда не возвращаются маршрутом запроса.
Приём, который стоит скопировать
Запросите профили группы, запустите каждый, сделайте работу, остановите его. Запускайте их по несколько, а не все сразу. Ограничение — память на вашем компьютере, ведь каждый профиль — это настоящий процесс браузера.
const { profiles } = await api("/profiles?groupId=" + groupId);
for (const batch of chunk(profiles, 5)) {
await Promise.all(batch.map(async (profile) => {
const { ws } = await api("/browser/start", { profileId: profile.id });
try {
await doTheWork(ws);
} finally {
await api("/browser/stop", { profileId: profile.id });
}
}));
}
Остановка профиля в `finally` важнее, чем кажется: именно корректное закрытие записывает состояние браузера, а профиль, принудительно завершённый посреди сессии, может потерять только что установленную сессию.
