Automatizando perfis de navegador com uma API local

Inicie um perfil a partir de um script, receba um endpoint de depuração e conecte o Playwright ou o Puppeteer a um navegador que já tem identidade e proxy atribuídos.
Automatizar um navegador antidetect costuma ser apresentado como um problema difícil. Não é, desde que a ferramenta lhe entregue a única coisa que sua biblioteca de automação já sabe usar: um endpoint de depuração.
O desenho geral
O PowerOps executa uma API HTTP vinculada ao endereço de loopback. Seu script pede que ela inicie um perfil; ela abre o navegador com a identidade, o armazenamento e o proxy desse perfil já aplicados e devolve o endpoint WebSocket do navegador em execução. Seu script se conecta a esse endpoint com o Playwright, o Puppeteer ou qualquer outra coisa que fale o protocolo DevTools.
A biblioteca de automação nunca precisa saber o que é um fingerprint. Quando ela se conecta, o ambiente já está estabelecido.
Iniciando um perfil
curl -s -H "Authorization: Bearer $POWEROPS_API_KEY" \
http://127.0.0.1:50326/status
Toda rota, exceto a verificação de status, exige uma chave bearer. Iniciar um navegador devolve o endpoint ao qual se conectar:
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
Conectando sua biblioteca
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");
A linha importante é o comentário. Não há configuração de fingerprint no seu script, porque configurar o ambiente não é trabalho do seu script. Isso pertence ao perfil e permanece igual, seja o perfil aberto por uma pessoa clicando em uma linha ou por uma tarefa agendada às três da manhã.
O que a API cobre
- A rota de status é uma verificação de saúde e a única que não precisa de chave.
- As rotas de navegador iniciam, encerram e consultam os navegadores em execução no momento.
- As rotas de perfil criam, atualizam, consultam e excluem perfis.
- As rotas de proxy gerenciam a biblioteca de proxies e atribuem rotas.
- As rotas de grupo organizam perfis em massa.
- As rotas de extensão importam e atribuem extensões.
Como ela se mantém local
Uma API que controla navegadores com contas logadas merece uma palavra sobre seus limites.
- Ela se vincula a 127.0.0.1. Nenhuma configuração a faz escutar em outra interface.
- Uma chave bearer é exigida em toda rota, exceto na verificação de status.
- Ela valida o cabeçalho Host e não envia cabeçalhos CORS, então uma página web aberta no seu navegador do dia a dia não consegue alcançá-la.
- Os segredos são somente de escrita: senhas de perfil, segredos de autenticação em duas etapas e senhas de proxy nunca são devolvidos por uma rota de consulta.
Um padrão que vale copiar
Consulte os perfis de um grupo, inicie cada um, faça o trabalho, encerre-o. Execute alguns por vez, em vez de todos de uma vez. A restrição é a memória da sua própria máquina, já que cada perfil é um processo de navegador de verdade.
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 });
}
}));
}
Encerrar o perfil em um `finally` importa mais do que parece: fechar de forma limpa é o que grava o estado do navegador, e um perfil encerrado à força no meio da sessão pode perder a sessão que acabou de estabelecer.
