O que Habilidade de Navegador Dev faz?
Automação de navegador que mantém o estado da página entre execuções de script. Escreva scripts pequenos e focados para realizar tarefas incrementalmente. Depois de ter validado parte de um fluxo de trabalho e houver trabalho repetitivo a ser feito, você pode escrever um script para realizar o trabalho repetitivo em uma única execução.
Escolhendo Sua Abordagem
- Sites locais/com código-fonte disponível: Leia o código-fonte primeiro para escrever seletores diretamente
- Layouts de página desconhecidos: Use
getAISnapshot()para descobrir elementos eselectSnapshotRef()para interagir com eles - Feedback visual: Tire capturas de tela para ver o que o usuário vê
Configuração
Dois modos disponíveis. Pergunte ao usuário se não estiver claro qual usar.
Modo Independente (Padrão)
Inicia um novo navegador Chromium para sessões de automação novas.
./skills/dev-browser/server.sh &
Adicione a flag --headless se o usuário solicitar. Aguarde a mensagem Ready antes de executar scripts.
Modo de Extensão
Conecta-se ao navegador Chrome existente do usuário. Use quando:
- O usuário já está logado em sites e deseja que você execute ações atrás de uma experiência autenticada que não seja de desenvolvimento local.
- O usuário solicita que você use a extensão
Importante: O fluxo principal permanece o mesmo. Você cria páginas nomeadas dentro do navegador deles.
Inicie o servidor relay:
cd skills/dev-browser && npm i && npm run start-extension &
Aguarde a mensagem Waiting for extension to connect... seguida de Extension connected no console. Isso indica que um cliente se conectou e o navegador está pronto para ser controlado.
Fluxo de trabalho:
- Scripts chamam
client.page("nome")como no modo normal para criar novas páginas / conectar-se a páginas existentes. - A automação é executada na sessão real do navegador do usuário
Se a extensão ainda não tiver se conectado, informe ao usuário para iniciá-la e ativá-la. Link para download: https://github.com/SawyerHood/dev-browser/releases
Escrevendo Scripts
Execute todos os scripts a partir do diretório
skills/dev-browser/. O alias de importação@/requer a configuração deste diretório.
Execute scripts inline usando heredocs:
cd skills/dev-browser && npx tsx <<'EOF'
import { connect, waitForPageLoad } from "@/client.js";
const client = await connect();
// Cria página com tamanho de viewport personalizado (opcional)
const page = await client.page("exemplo", { viewport: { width: 1920, height: 1080 } });
await page.goto("https://exemplo.com");
await waitForPageLoad(page);
console.log({ titulo: await page.title(), url: page.url() });
await client.disconnect();
EOF
Escreva em arquivos tmp/ apenas quando o script precisar ser reutilizado, for complexo, ou o usuário solicitar explicitamente.
Princípios Chave
- Scripts pequenos: Cada script faz UMA coisa (navegar, clicar, preencher, verificar)
- Avalie o estado: Registre/retorne o estado no final para decidir os próximos passos
- Nomes de página descritivos: Use
"checkout","login", não"principal" - Desconecte para sair:
await client.disconnect()- as páginas persistem no servidor - JS puro no evaluate:
page.evaluate()é executado no navegador - sem sintaxe TypeScript
Ciclo de Fluxo de Trabalho
Siga este padrão para tarefas complexas:
- Escreva um script para realizar uma ação
- Execute-o e observe a saída
- Avalie - funcionou? Qual é o estado atual?
- Decida - a tarefa está concluída ou precisamos de outro script?
- Repita até a tarefa ser finalizada
Sem TypeScript no Contexto do Navegador
O código passado para page.evaluate() é executado no navegador, que não entende TypeScript:
// ✅ Correto: JavaScript puro
const texto = await page.evaluate(() => {
return document.body.innerText;
});
// ❌ Errado: a sintaxe TypeScript falhará em tempo de execução
const texto = await page.evaluate(() => {
const el: HTMLElement = document.body; // Anotação de tipo quebra no navegador!
return el.innerText;
});
Extraindo Dados
Para extrair grandes conjuntos de dados, intercepte e reproduza requisições de rede em vez de percorrer o DOM. Consulte references/scraping.md para o guia completo sobre captura de requisições, descoberta de esquemas e reprodução de APIs paginadas.
API do Cliente
const client = await connect();
// Obtém ou cria página nomeada (viewport se aplica apenas a páginas novas)
const page = await client.page("nome");
const pageComTamanho = await client.page("nome", { viewport: { width: 1920, height: 1080 } });
const pages = await client.list(); // Lista todos os nomes de páginas
await client.close("nome"); // Fecha uma página
await client.disconnect(); // Desconecta (páginas persistem)
// Métodos de captura ARIA
const snapshot = await client.getAISnapshot("nome"); // Obtém árvore de acessibilidade
const element = await client.selectSnapshotRef("nome", "e5"); // Obtém elemento por referência
O objeto page é uma Página padrão do Playwright.
Aguardando
import { waitForPageLoad } from "@/client.js";
await waitForPageLoad(page); // Após navegação
await page.waitForSelector(".resultados"); // Para elementos específicos
await page.waitForURL("**/sucesso"); // Para URL específica
Inspecionando o Estado da Página
Capturas de Tela
await page.screenshot({ path: "tmp/screenshot.png" });
await page.screenshot({ path: "tmp/full.png", fullPage: true });
Captura ARIA (Descoberta de Elementos)
Use getAISnapshot() para descobrir elementos da página. Retorna árvore de acessibilidade em formato YAML:
- banner:
- link "Hacker News" [ref=e1]
- navigation:
- link "new" [ref=e2]
- main:
- list:
- listitem:
- link "Título do Artigo" [ref=e8]
- link "328 comentários" [ref=e9]
- contentinfo:
- textbox [ref=e10]
- /placeholder: "Pesquisar"
Interpretando refs:
[ref=eN]- Referência de elemento para interação (apenas elementos visíveis e clicáveis)[checked],[disabled],[expanded]- Estados do elemento[level=N]- Nível de cabeçalho/url:,/placeholder:- Propriedades do elemento
Interagindo com refs:
const snapshot = await client.getAISnapshot("hackernews");
console.log(snapshot); // Encontre a ref necessária
const element = await client.selectSnapshotRef("hackernews", "e2");
await element.click();
Recuperação de Erros
O estado da página persiste após falhas. Depure com:
cd skills/dev-browser && npx tsx <<'EOF'
import { connect } from "@/client.js";
const client = await connect();
const page = await client.page("hackernews");
await page.screenshot({ path: "tmp/debug.png" });
console.log({
url: page.url(),
titulo: await page.title(),
textoCorpo: await page.textContent("body").then((t) => t?.slice(0, 200)),
});
await client.disconnect();
EOF