Pular para o conteúdo principal

Guia de uso do computador Gemini 2.5 com projeto de demonstração: Crie um agente de busca de emprego

Aprenda a usar o Gemini 2.5 Computer Use para criar um agente de busca de emprego com inteligência artificial. Este tutorial prático mostra como automatizar navegadores com o Playwright e o Streamlit, sem precisar de APIs.
Atualizado 11 de out. de 2025  · 8 min lido

A equipe Gemini recentemente lançou o o Gemini 2.5 Computer Use, um modelo especializado que pode ver uma tela ao vivo e agir nela clicando, digitando, rolando e navegando na web como um operador humano.

Neste guia, vamos deixar de lado os benchmarks abstratos e criar algo prático. Um aplicativo Streamlit que usa o Computer Use para controlar um navegador de verdade, pesquisar vagas de emprego no Google, aplicar um filtro e exportar os resultados para CSV sem precisar de APIs de pesquisa de terceiros.

Neste tutorial, você vai aprender como:

  • Configure o loop de uso do computador Gemini 2.5
  • Execute o agente com o Playwright (Chromium), usando uma lista de permissões e confirmação humana opcional para etapas arriscadas.
  • Crie uma interface Streamlit com registros de ação ao vivo e capturas de tela após cada turno.
  • Raste os resultados orgânicos e baixe um CSV.

No final, você vai ter um agente de busca de emprego que vai selecionar vagas precisas para você.

Imagem de demonstração

Se você quiser saber mais sobre o Gemini 2.5, recomendo dar uma olhada no nosso tutorial do Gemini 2.5 Pro, que fala sobre recursos, testes, acesso, benchmarks e muito mais.

O que é o uso do computador Gemini 2.5?

O Gemini 2.5 Computer Use é um modelo e ferramenta especializados (pré-visualização) na API Gemini. API Gemini que permite criar agentes de controle de navegador. Em vez de chamar APIs específicas do site, o modelo funciona a partir de capturas de tela. Ele pode ver o que está na página e, em seguida, agir emitindo ações de interface do usuário, como navigate, click_at, scroll_document, etc.

O código do cliente pega essas ações sugeridas, faz o que tem que ser feito e manda de volta uma combinação nova de captura de tela e URL para que o modelo possa decidir o próximo passo. 

Como funciona o ciclo de uso do computador

loop do agente

Fonte: Documentação Gemini

Veja como o ciclo do agente acima funciona do início ao fim:

  1. Envie uma solicitação: Comece enviando uma solicitação que inclua a ferramenta Uso do Computador, uma sugestão de meta e uma captura de tela inicial da interface do usuário.
  2. Receba uma resposta: O modelo responde com narração e uma ou mais chamadas de função (como click_at ou type_text_at) e uma decisão de segurança.
  3. Execução: Depois, é só fazer o que foi proposto, ou seja, se a ação estiver marcada como regular/permitida, a gente pode executá-la; se precisar de confirmação, a gente avisa o usuário e só continua com a aprovação explícita dele.
  4. Estado de retorno: Depois de fazer a ação, a gente devolve o estado pro modelo mandando um FunctionResponse que tem uma captura de tela nova e a URL atual.
  5. Repita: A gente repete esse ciclo de “ see–decide–act–observe ” até que a tarefa seja concluída, ocorra um erro ou o usuário ou modelo decida parar.

Crie um agente de busca de empregos com o Gemini 2.5 Computer Use e o Streamlit

Nesta seção, vamos criar um Streamlitque aciona um navegador real usando Gemini 2.5 Computer Use e Playwright, e depois exporta os resultados para CSV.

Funciona assim:

  • O usuário coloca uma lista de palavras-chave de trabalho na barra lateral do Streamlit.
  • O agente diz ao Gemini para abrir o Google, fazer cada pesquisa e usar um filtro de tempo.
  • O agente para na primeira página dos resultados orgânicos e mostra capturas de tela ao vivo junto com registros de ação a cada passo.
  • Em seguida, ele extrai títulos, links e trechos da página 1 e os agrega em todas as palavras-chave.
  • Por fim, ele gera uma tabela de resultados junto com um arquivo CSV que dá pra baixar.

Nos bastidores, o aplicativo usa uma lista de domínios permitidos para uma navegação segura, oferece a opção de confirmação humana para etapas arriscadas e usa o loop de uso do computador para facilitar a depuração.

Antes de começarmos: 

Alguns casos de uso responsável e políticas do site incluem:

  • O que a automação pode fazer: Essa demonstração só automatiza a Pesquisa do Google (lista de permissões) e extrai os resultados orgânicos da página 1.
  • Respeite os termos do site: Não automatize sites com Termos de Serviço restritivos e nunca tente ignorar CAPTCHAs. Se aparecer um CAPTCHA, preencha-o manualmente e deixe o modelo continuar.
  • Segurança com intervenção humana: Se o Gemini sugerir uma ação arriscada (como interagir com um CAPTCHA ou fazer compras), o aplicativo para por padrão. Só vai rolar se você ativar explicitamente a confirmação automática.

Passo 1: Pré-requisitos

  • Python 3.10+
  • Uma chave API Gemini do Google AI Studio
  • macOS / Windows / Linux com o Playwright Chromium instalado

Passo 1.1: Importações 

Primeiro, certifique-se de que você tem as seguintes importações instaladas:

python -m venv .venv && source .venv/bin/activate
pip install streamlit google-genai playwright python-dotenv
playwright install chromium

Os comandos acima configuram um ambiente virtual e instalam todas as dependências essenciais necessárias para construir o aplicativo, ou seja, Streamlit para a interface do usuário, google-genai para chamar a API Gemini, Playwright para automação do navegador e python-dotenv para carregar variáveis de ambiente e Chromium para o Playwright.

Passo 1.2: Configurando a chave API do Gemini 

Agora que já instalamos as dependências, vamos configurar a chave API Gemini do AI Studio. 

  • Faça login no AI Studio e procure por “Obter chave API”.
  • Clique em Criar chave API
  • Escolha um projeto Google Nuvem que já existe ou crie um com o faturamento ativado.

Criar chave API

  • É só clicar em link "uma conta de cobrança" e adicione os dados do seu cartão para verificar.
  • Por fim, copie a chave API do AI Studio e salve-a.

Agora, crie um arquivo .env na pasta do seu projeto e coloque sua chave API lá:

GOOGLE_API_KEY=YOUR_REAL_KEY
ALLOWED_HOSTS=google.com

O pacote python-dotenv vai carregar GOOGLE_API_KEY na hora de rodar, pra que o aplicativo possa chamar o modelo Gemini 2.5 Computer Use.

Passo 2: Configurando o modelo

Agora, vamos nos preparar para o tempo de execução, que inclui importações, constantes, ID do modelo e autenticação. Isso garante que o aplicativo se comunique com o Gemini e que a navegação permaneça segura dentro de um domínio permitido.

import os, io, time, csv, base64, urllib.parse
from typing import List, Dict, Tuple
import streamlit as st
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright
from google import genai
from google.genai import types
from google.genai.types import Content, Part
W, H = 1440, 900
MODEL = "gemini-2.5-computer-use-preview-10-2025"  
load_dotenv()
API_KEY = os.getenv("GOOGLE_API_KEY")
if not API_KEY:
    st.stop()
ALLOWED_HOSTS = {h.strip().lower() for h in os.getenv("ALLOWED_HOSTS", "google.com").split(",") if h.strip()}
client = genai.Client(api_key=API_KEY)

Começamos importando as bibliotecas principais, como Streamlit, Playwright, google-genai e pequenos utilitários (dotenv, os, io, csv, time, urllib) para configuração e E/S.

Uma janela de visualização fixa (W, H = 1440 × 900) mantém as capturas de tela e o mapeamento de coordenadas consistentes para o uso do computador, e o modelo de visualização é definido como gemini-2.5-computer-use-preview-10-2025

A chave API é carregada com load_dotenv() e os.getenv("GOOGLE_API_KEY"). A navegação é configurada por uma lista de permissões (padrão google.com) por segurança. 

Por fim, genai.Client(api_key=API_KEY) inicializa o Gemini SDK para que o aplicativo possa executar o loop do agente e renderizar os resultados no Streamlit.

Passo 3: Criando funções auxiliares

Antes de entrarmos no cerne do aplicativo, precisamos configurar algumas funções auxiliares. Eles ajudam nas verificações de segurança, coordenam a conversão, executam ações para chamadas de função do Gemini, extraem dados do SERP e exportam os resultados como um CSV. 

Passo 3.1: Segurança e execução de ações

Começamos adicionando um auxiliar de back-end que permite o controle seguro do navegador. Isso inclui uma função de verificação da lista de domínios permitidos para restringir a navegação, uma função de conversão de coordenadas para mapear a grade 0–999 do modelo para a janela de visualização fixa e uma função de despachante de ações que interpreta as chamadas de função do Computer Use e as executa via Playwright.

def host_allowed(url: str) -> bool:
    try:
        netloc = urllib.parse.urlparse(url).netloc.lower()
        return any(netloc.endswith(allowed) for allowed in ALLOWED_HOSTS)
    except Exception:
        return False
def denorm(v: int, size: int) -> int:
    return int(v/1000*size)
def exec_calls(candidate, page, viewport, *, approve_all=False) -> List[Tuple[str, Dict]]:
    W, H = viewport
    results = []
    for part in candidate.content.parts:
        fc = getattr(part, "function_call", None)
        if not fc:
            continue
        name, args = fc.name, (fc.args or {})
        sd = args.get("safety_decision")
        if sd and sd.get("decision") == "require_confirmation":
            reason = sd.get("explanation", "Model flagged a risky action.")
            log_box.warning(f"[SAFETY requires confirmation] {reason}")
            if not approve_all:
                st.stop()
            results.append((name, {"safety_acknowledgement": "true"}))
        if name == "navigate":
            target = args.get("url", "")
            if target and not host_allowed(target):
                log_box.error(f"[BLOCKED] Non-allowlisted host: {target}")
                results.append((name, {"error": "blocked_by_allowlist"}))
                continue
        try:
            if name == "open_web_browser":
                pass
            elif name == "navigate":
                page.goto(args["url"], timeout=30000)
            elif name == "search":
                page.goto("https://www.google.com", timeout=30000)
            elif name == "click_at":
                page.mouse.click(denorm(args["x"], W), denorm(args["y"], H))
            elif name == "hover_at":
                page.mouse.move(denorm(args["x"], W), denorm(args["y"], H))
            elif name == "type_text_at":
                x, y = denorm(args["x"], W), denorm(args["y"], H)
                page.mouse.click(x, y)
                if args.get("clear_before_typing", True):
                    page.keyboard.press("Meta+A"); page.keyboard.press("Backspace")
                page.keyboard.type(args["text"])
                if args.get("press_enter", True):
                    page.keyboard.press("Enter")
            elif name == "scroll_document":
                page.mouse.wheel(0, 800 if args["direction"] == "down" else -800)
            elif name == "key_combination":
                page.keyboard.press(args["keys"])
            page.wait_for_load_state("networkidle", timeout=10000)
            results.append((name, {}))
            time.sleep(0.6)
        except Exception as e:
            results.append((name, {"error": str(e)}))
    return results

Vamos entender como cada função se encaixa no pipeline:

  • host_allowed() função: Essa função analisa a URL de destino, coloca o nome do host em minúsculas e vê se ela termina com algum domínio em ALLOWED_HOSTS que tá listado no arquivo .env
  • denorm() função: Esse utilitário transforma as coordenadas do ponteiro em unidades de pixel reais para a janela de visualização atual. É essencial para cliques, passagens do mouse e digitação precisos, principalmente quando você muda o tamanho da tela ou usa o modo sem monitor.
  • exec_calls() função: Por fim, a função execute calls verifica a resposta do modelo em busca de chamadas de função e envia cada uma delas para o Playwright. Ele bloqueia chamadas de navegação para hosts que não estão na lista de permissões, faz as ações que são suportadas, espera a rede ficar parada para estabilizar a página e registra o resultado de cada ação (incluindo erros). Esses resultados são então usados na próxima etapa para construir um FunctionResponses e ao modelo.

Juntas, essas funções reforçam os limites, mantêm a matemática dos ponteiros precisa e registram resultados detalhados.

Passo 3.2: Feedback pós-ação e coleta de dados

Depois de fazer as coisas, o agente precisa de feedback pra decidir o que fazer depois e mandar resultados úteis. Essa etapa oferece três funções auxiliares, como segue:

def fr_from(page, results):
    shot = page.screenshot(type="png")
    url = page.url
    frs = []
    for name, result in results:
        frs.append(types.FunctionResponse(
            name=name,
            response={"url": url, **result},
            parts=[types.FunctionResponsePart(
                inline_data=types.FunctionResponseBlob(mime_type="image/png", data=shot)
            )]
        ))
    return frs, shot
def scrape_google_serp(page, max_items=10):
    items = []
    anchors = page.locator('div#search a:has(h3)')
    count = min(anchors.count(), max_items)
    for i in range(count):
        a = anchors.nth(i)
        title = a.locator('h3').inner_text()
        link = a.get_attribute('href')
        snippet = ""
        snips = page.locator('div#search .VwiC3b')
        if snips.count() > i:
            snippet = snips.nth(i).inner_text()
        items.append({"title": title, "link": link, "snippet": snippet})
    return items
def to_csv_download(rows: List[Dict], name="results.csv"):
    if not rows:
        return None
    out = io.StringIO()
    writer = csv.DictWriter(out, fieldnames=["keyword", "title", "link", "snippet"])
    writer.writeheader(); writer.writerows(rows)
    b = out.getvalue().encode("utf-8")
    href = f"data:text/csv;base64,{base64.b64encode(b).decode()}"
    st.download_button("Download CSV", data=b, file_name=name, mime="text/csv")

Vamos ver como cada função auxiliar pós-ação funciona:

  • fr_from() função: Isso captura uma nova imagem PNG e a URL atual, e depois cria um FunctionResponse para cada ação executada. Isso coloca um contexto visual para a próxima rodada de inferências e mantém um registro auditável do que rolou.
  • scrape_google_serp() função: Depois, a gente pega os títulos, links e trechos da primeira página de resultados do Google usando seletores resilientes como a:has(h3) para títulos/links e .VwiC3b para trechos. O scraper capta os resultados em max_items e devolve linhas limpas e estruturadas, prontas para análise ou exportação.
  • to_csv_download() função: Essa função gera um CSV na memória com cabeçalhos consistentes e o expõe por meio da função ` download_button() ` do Streamlit.

Agora que já temos todas as funções auxiliares prontas, podemos criar uma aplicação Streamlit em torno delas.

Passo 4: Criando o aplicativo Streamlit

Essa etapa conecta a interface do usuário do Streamlit ao loop do agente de uso do computador. Ele mostra a interface, controla como o usuário interage com o agente e garante que o resultado seja do jeito que eles querem.

st.set_page_config(page_title="Jobs Search with Gemini Computer Use", layout="wide")
st.title("Jobs Search with Gemini 2.5 Computer Use")
with st.sidebar:
    st.markdown("**Search inputs**")
    default_kw = "data scientist remote\nml engineer \ngenai research india"
    kw_text = st.text_area("Job keywords", value=default_kw, height=120)
    query_mode = st.selectbox("Query style", ["<kw> jobs", 'site:linkedin.com/jobs "<kw>"'], index=0)
    use_past_week = st.checkbox('Ask agent to set "Past week" filter', value=True)
    turns = st.slider("Max agent turns per keyword", 3, 12, 6)
    auto_confirm = st.checkbox("Auto-approve risky actions", value=False, help="If model requests confirmation (e.g., CAPTCHA), auto-approve instead of pausing.")
    run_btn = st.button("Run search")
log_col, shot_col = st.columns([0.45, 0.55])
log_box = log_col.container(height=520)
shot_box = shot_col.container(height=520)
table_box = st.container()
if run_btn:
    keywords = [k.strip() for k in kw_text.splitlines() if k.strip()]
    all_rows = []
    log_box.write("Initializing browser...")
    pw = sync_playwright().start()
    browser = pw.chromium.launch(headless=False)
    ctx = browser.new_context(viewport={"width": W, "height": H})
    page = ctx.new_page()
    try:
        for kw in keywords:
            log_box.subheader(f"▶ {kw}")
            page.goto("https://www.google.com", timeout=30000)
            initial_shot = page.screenshot(type="png")
            base_query = f'{kw} jobs' if query_mode == "<kw> jobs" else f'site:linkedin.com/jobs "{kw}"'
            goal = (
                f'Search Google for "{base_query}". '
                f'{"Open Tools and set time filter to Past week. " if use_past_week else ""}'
                'Stop when first-page results are fully visible; do NOT open the Jobs panel.'
            )
            contents = [Content(role="user", parts=[Part(text=goal), Part.from_bytes(data=initial_shot, mime_type="image/png")])]
            cfg = types.GenerateContentConfig(
                tools=[types.Tool(computer_use=types.ComputerUse(
                    environment=types.Environment.ENVIRONMENT_BROWSER
                ))]
            )
            for turn in range(turns):
                log_box.caption(f"Turn {turn+1}: thinking…")
                resp = client.models.generate_content(model=MODEL, contents=contents, config=cfg)
                cand = resp.candidates[0]
                contents.append(cand.content)
                narr = " ".join([p.text for p in cand.content.parts if getattr(p, "text", None)])
                if narr:
                    log_box.info(narr[:400])
                fcs = [p.function_call for p in cand.content.parts if getattr(p, "function_call", None)]
                if not fcs:
                    log_box.success("Agent stopped proposing actions.")
                    break
                for fc in fcs:
                    log_box.write(f"→ {fc.name} {fc.args or {}}")
                results = exec_calls(cand, page, (W, H), approve_all=auto_confirm)
                frs, shot = fr_from(page, results)
                contents.append(Content(role="user", parts=[Part(function_response=fr) for fr in frs]))
                shot_box.image(shot, caption=page.url, width='stretch')
            rows = scrape_google_serp(page)
            for r in rows:
                r["keyword"] = kw
            all_rows.extend(rows)
            log_box.success(f"{kw}: collected {len(rows)} results")
        if all_rows:
            table_box.dataframe(all_rows, width='stretch')
            to_csv_download(all_rows, name="jobs_google_results.csv")
        else:
            st.warning("No rows collected. Try fewer keywords or fewer turns.")
    finally:
        browser.close()
        pw.stop()

Vamos entender esse pipeline em detalhes:

  • O aplicativo começa configurando a página com um layout amplo e definindo um título claro para que os usuários saibam imediatamente o que a ferramenta faz. 
  • Na barra lateral, os usuários colocam palavras-chave do trabalho, escolhem o estilo de consulta, um filtro de tempo, o número máximo de respostas do agente por palavra-chave e ativam ou desativam a confirmação automática para ações arriscadas. Então, o botão ” (Executar pesquisa) aciona o fluxo de trabalho.
  • A área principal é dividida em duas colunas, que incluem um contêiner “log” à esquerda que transmite atualizações textuais e um contêiner “captura de tela” à direita que exibe imagens ao vivo de cada turno. Abaixo deles, tem um contêiner separado para a tabela de resultados finais.
  • Quando o usuário clica em Executar pesquisa, a interface escreve mensagens de progresso no painel de log, atualiza o painel de capturas de tela à medida que novas imagens ficam disponíveis e, após processar todas as palavras-chave, renderiza os resultados agregados como uma DataFrame.

Pra rodar esse app, é só executar o seguinte comando bash no seu terminal:

python -m streamlit run app.py

Dica: Sempre inicie o Streamlit a partir do seu venv para evitar problemas de “ModuleNotFoundError”.

Conclusão

Esse tutorial mostra como criar um agente visual de busca de empregos usando o Gemini 2.5 Computer Use para controlar um navegador, aplicar filtros e exportar resultados usando uma interface Streamlit. 

A partir daqui, você pode estender o fluxo de trabalho adicionando paginação para percorrer mais páginas, ampliar os recursos do scraper com datas de publicação, locais e nomes de empresas ou incluir uma lista de permissões para um quadro de empregos sandbox. 

Se você quiser saber mais sobre o uso de computadores e IA agênica, não deixe de conferir o curso curso Introdução aos Agentes de IA.


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Sou Google Developers Expert em ML (Gen AI), Kaggle 3x Expert e Women Techmakers Ambassador com mais de 3 anos de experiência em tecnologia. Fui cofundador de uma startup de tecnologia de saúde em 2020 e estou fazendo mestrado em ciência da computação na Georgia Tech, com especialização em machine learning.

Tópicos

Cursos mais populares do DataCamp

Curso

Building AI Agents with Google ADK

1 h
3.3K
Build a customer-support assistant step-by-step with Google’s Agent Development Kit (ADK).
Ver detalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado
An avian AI exits its cage

blog

12 Alternativas de código aberto ao GPT-4

GPT-4 alternativas de código aberto que podem oferecer desempenho semelhante e exigem menos recursos computacionais para serem executadas. Esses projetos vêm com instruções, fontes de código, pesos de modelos, conjuntos de dados e interface de usuário do chatbot.
Abid Ali Awan's photo

Abid Ali Awan

9 min

cursor ai code editor

Tutorial

AI do cursor: Um guia com 10 exemplos práticos

Saiba como instalar o Cursor AI no Windows, macOS e Linux e descubra como usá-lo em 10 casos de uso diferentes.

Tutorial

DeepSeek-Coder-V2 Tutorial: Exemplos, instalação, padrões de referência

O DeepSeek-Coder-V2 é um modelo de linguagem de código de código aberto que rivaliza com o desempenho do GPT-4, Gemini 1.5 Pro, Claude 3 Opus, Llama 3 70B ou Codestral.
Dimitri Didmanidze's photo

Dimitri Didmanidze

Tutorial

Guia para iniciantes no uso da API do ChatGPT

Este guia o orienta sobre os conceitos básicos da API ChatGPT, demonstrando seu potencial no processamento de linguagem natural e na comunicação orientada por IA.
Moez Ali's photo

Moez Ali

Tutorial

Um guia para iniciantes na engenharia de prompts do ChatGPT

Descubra como fazer com que o ChatGPT forneça os resultados que você deseja, fornecendo a ele as entradas necessárias.
Matt Crabtree's photo

Matt Crabtree

Tutorial

Criando agentes LangChain para automatizar tarefas em Python

Um tutorial abrangente sobre a criação de agentes LangChain com várias ferramentas para automatizar tarefas em Python usando LLMs e modelos de bate-papo usando OpenAI.
Bex Tuychiev's photo

Bex Tuychiev

Ver maisVer mais