🎯 Um navegador em nuvem personalizável e anti-detecção alimentado por Chromium desenvolvido internamente, projetado para rastreadores web e agentes de IA. 👉Experimente agora
De volta ao blog

Ollama Vision Web Scraping: Ler uma Captura de Tela Com um Modelo Local

Olivia Patel
Olivia Patel

Senior Cybersecurity Analyst

06-Aug-2026

TL;DR:

  • Esta é a combinação do modelo local-plus-captura de tela, e nenhum guia existente neste site cobre isso sozinho. Ollama Web Scraping executa um modelo local em texto HTML renderizado, não em uma captura de tela; uma API de visão na nuvem lê uma captura de tela, mas cobra por imagem e precisa de uma chave. Este guia executa um modelo local, capaz de visão, contra uma captura de tela real do navegador — sem chave na nuvem, sem cobrança por token e sem HTML.
  • Cada execução aqui usou o Ollama apenas na CPU, e ollama ps confirma isso. Nenhum desvio para GPU está disponível para o Ollama neste ambiente, e o tempo varia amplamente entre as chamadas — de segundos de dois dígitos a alguns minutos — dependendo de a modelo ainda estar residente na memória.
  • O campo de imagem do Ollama não é o formato da nuvem. O campo images no /api/generate do Ollama aceita uma lista de strings base64 brutas sem prefixo data:image/png;base64, — o oposto da convenção compatível com OpenAI que a maioria das APIs de visão na nuvem utiliza.
  • Um modelo de visão sub-2B é pouco confiável em ambas as extremidades da tarefa, de maneiras diferentes. Pedindo para descrever a página em uma frase, ele nomeou um detalhe estrutural que não corresponde à página real. Pedindo um registro JSON estruturado — a tarefa exata que o irmão da visão na nuvem manipula com precisão — ele ecoou o texto de espaço reservado do prompt, depois desviou para uma saída que não era JSON de forma alguma.
  • A captura de tela ainda vem de um navegador renderizado real. O Scrapeless Scraping Browser captura a página pelo CDP da mesma forma que um pipeline de visão na nuvem faria; apenas onde os pixels são lidos depois muda.
  • Gratuito para começar no lado da busca. Crie sua chave API do Scrapeless em app.scrapeless.com.

Por que emparelhar um modelo local com uma captura de tela

Duas coisas sobre "web scraping com IA" são geralmente verdadeiras separadamente, e raramente verdadeiras juntas. Um modelo local, executado através de Ollama, não custa nada por chamada e não envia nada para terceiros — mas o guia do modelo local neste site até agora lê texto HTML renderizado, não pixels. Um modelo de visão lê uma captura de tela em vez do DOM — mas o guia do modelo de visão neste site até agora chama uma API na nuvem que cobra por imagem e precisa de uma chave de provedor na nuvem. Este post é a combinação que nenhum deles cobre: um modelo capaz de visão que roda inteiramente na máquina à sua frente, lendo uma captura de tela real do navegador, sem cobrança de inferência na nuvem em nenhum lugar do pipeline.

Os dois guias existentes continuam úteis para o que cada um faz bem. Ollama Web Scraping é a escolha certa quando o valor que você precisa já está em texto no DOM renderizado — um modelo local é rápido e preciso em um trecho HTML reduzido. O guia de web scraping com GPT Vision deste site é a escolha certa quando o valor é genuinamente visual e você deseja um modelo pago capaz de lê-lo. Este guia é para um terceiro caso: o valor é visual, mas você deseja zero dependência da nuvem e está disposto a negociar capacidade por isso. Essa troca é real, e este guia a relata honestamente em vez de mostrar apenas a parte que funciona.

Pré-requisitos

  • Ollama instalado e em execução, com um modelo capaz de visão obtido: ollama pull moondream.
  • Python 3.9 ou posterior com playwright e requests.
  • Uma chave API do Scrapeless do painel, exportada como SCRAPELESS_API_KEY. Obtenha uma gratuitamente em app.scrapeless.com.
  • Nenhuma GPU é necessária. Cada execução neste guia usou o Ollama apenas na CPU.

Instalar

bash Copy
pip install playwright requests
ollama pull moondream

playwright conecta a um navegador remoto pelo CDP neste guia, então nenhum download local do Chromium é necessário. moondream é um modelo compacto capaz de visão — pequeno o suficiente para obter e executar sem uma GPU discreta, que é o objetivo deste guia.

Configurar

bash Copy
export SCRAPELESS_API_KEY="your_scrapeless_api_key"

Essa é a única chave que este pipeline precisa. A API local do Ollama não requer credenciais.

A captura de tela ainda precisa ser fiel, então ela vem de um navegador real. Conecte-se ao Scrapeless Scraping Browser através do Protocolo de DevTools do Chrome, abra a página e capture a área visível renderizada — o mesmo passo de captura que o irmão de visão na nuvem usa, através de o Protocolo de DevTools do Chrome:

python Copy
import os
from urllib.parse import urlencode
from playwright.sync_api import sync_playwright

def browser_url():
    return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
        {"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(browser_url())
    page = browser.new_page(viewport={"width": 1280, "height": 900})
    page.goto("https://quotes.toscrape.com/", wait_until="networkidle")
    png = page.screenshot()
    browser.close()

print("screenshot bytes:", len(png))
print("PNG signature ok:", png[:8] == b"\x89PNG\r\n\x1a\n")
text Copy
screenshot bytes: 55462
PNG signature ok: True

Obtenha sua chave de API no plano gratuito: app.scrapeless.com

Leia a Captura de Tela com um Modelo de Visão Local

Codifique em Base64 o PNG e envie-o diretamente para o endpoint local /api/generate da Ollama. É aqui que os dois eixos realmente se encontram: a imagem veio de um navegador renderizado na nuvem real, mas o modelo que a lê nunca sai desta máquina. A forma da solicitação está documentada em referência da API da Ollama — note que o campo images recebe uma string base64 pura, não uma URL data:image/png;base64,...:

python Copy
import base64, os, time
from urllib.parse import urlencode

import requests
from playwright.sync_api import sync_playwright

def browser_url():
    return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
        {"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})

t0 = time.time()
with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(browser_url())
    page = browser.new_page(viewport={"width": 1280, "height": 900})
    page.goto("https://quotes.toscrape.com/", wait_until="networkidle")
    png = page.screenshot()
    browser.close()
capture_s = round(time.time() - t0, 1)

img_b64 = base64.b64encode(png).decode()

t1 = time.time()
resp = requests.post(
    "http://localhost:11434/api/generate",
    json={
        "model": "moondream",
        "prompt": "Describe what this webpage shows in one sentence.",
        "images": [img_b64],
        "stream": False,
        "options": {"temperature": 0, "num_predict": 60},
    },
    timeout=300,
)
resp.raise_for_status()
data = resp.json()
inference_s = round(time.time() - t1, 1)

print("capture seconds:", capture_s)
print("vision inference seconds:", inference_s)
print("description:", data["response"].strip())
text Copy
capture seconds: 11.5
vision inference seconds: 54.7
description: A webpage titled "Quotes to Scrape" displays a list of quotes and their corresponding tags, organized into five sections.

O título, a presença de aspas e as tags abaixo de cada um são todos elementos reais da página renderizada. A estrutura específica que adiciona por cima, "organizada em cinco seções", não é verificável em relação à página real: quotes.toscrape.com renderiza dez blocos de citação na página inicial, sem agrupamento em cinco de nada. O modelo acerta o assunto geral da página, um site de citações com tags, e em seguida afirma um detalhe estrutural específico que não corresponde ao que realmente está lá.

ollama ps durante esta classe de chamada relata 100% CPU: não há offload de GPU disponível para a Ollama neste ambiente. O tempo de uma chamada como essa também varia com o estado do modelo. O endpoint /api/generate da Ollama mantém um modelo residente na memória por keep_alive após cada solicitação, 5 minutos por padrão, documentado na referência da API da Ollama acima; uma chamada enquanto o modelo ainda está residente ignora o reenvio do disco, e uma chamada fria, com nada residente, paga esse tempo de carga antes que o primeiro token retorne.

Onde a Extração Estruturada Falha

Uma descrição funcional não é a mesma coisa que extração confiável. Peça ao mesmo modelo pela tarefa exata que o irmão de visão na nuvem lida em uma única passagem limpa — um array JSON de registros de citações — e o resultado honesto pertence a este guia também:

python Copy
import base64, json, os, time
from urllib.parse import urlencode

import requests
from playwright.sync_api import sync_playwright

def browser_url():
    return "wss://browser.scrapeless.com/api/v2/browser?" + urlencode(
        {"token": os.environ["SCRAPELESS_API_KEY"], "sessionTTL": 180, "proxyCountry": "US"})

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(browser_url())
    page = browser.new_page(viewport={"width": 1280, "height": 900})
    page.goto("https://quotes.toscrape.com/", wait_until="networkidle")
    png = page.screenshot()
    browser.close()

img_b64 = base64.b64encode(png).decode()

t1 = time.time()
resp = requests.post(
    "http://localhost:11434/api/generate",
    json={
        "model": "moondream",
        "prompt": 'From this screenshot of a quotes page, return JSON '
                  '{"quotes":[{"author":"...", "text":"..."}]} for the first 3 quotes '
                  'you can see. Return ONLY JSON.',
        "images": [img_b64],
        "stream": False,
        "format": "json",
        "options": {"temperature": 0, "num_predict": 150},
    },
    timeout=600,
)
resp.raise_for_status()
data = resp.json()
inference_s = round(time.time() - t1, 1)

print("vision inference seconds:", inference_s)
print("raw response:", data["response"][:200])
try:
    parsed = json.loads(data["response"])
    print("parsed quotes:", len(parsed.get("quotes", [])))
except json.JSONDecodeError as e:
    print("JSON parse failed:", e)
text Copy
vision inference seconds: 79.6
raw response: {"quotes":[{"author":"...","text":"..."},{"author":"","text":"","}}] } [0.12, 0.13, 1.0, 0.87] ) ; return [0.12, 0.13, 1.0, 0.87] ; return [0.12, 0.13, 1.0, 0.87] ; return [0.12, 0.13, 1.0, 0.87] ; re
JSON parse failed: Unterminated string starting at: line 1 column 65 (char 64)

O primeiro objeto repete a sintaxe do próprio placeholder "..." do prompt verbatim, como se a reticência nas instruções fosse um valor a ser copiado, ao invés de um espaço a ser preenchido. O segundo objeto nunca se fecha corretamente, e a resposta então deriva em arrays de quatro números repetidos e declarações soltas return que não têm nada a ver com citações, um autor ou JSON — saída que parece restos de uma tarefa diferente do que uma tentativa quebrada nesta. Através de cada execução ao vivo por trás deste guia, o padrão subjacente se manteve mesmo enquanto o lixo exato mudava de forma: nenhum texto de citação real ou nome de autor jamais voltou, e a resposta nunca se fechou uma vez como JSON válido. Esse é um resultado genuíno, não um log truncado: moondream é um modelo de aproximadamente 1 bilhão de parâmetros, e o comportamento que segue o esquema que permite a um grande modelo de visão na nuvem retornar três registros limpos e corretamente atribuídos em poucos segundos não é algo que um modelo tão pequeno reproduz. Aumentar o limite de comprimento de saída não conserta o padrão; na maioria das vezes dá ao modelo mais espaço para divagar.

O guia de raspagem web GPT Vision deste site mostra o outro lado dessa troca. Um modelo multimodal hospedado, GPT-4o-mini, executado através da API da OpenAI, transforma uma captura de tela do Playwright em campos estruturados de produto e preço que realmente preenche. Essa comparação, um modelo pago muito mais capaz contra um local de 1 bilhão de parâmetros gratuito, é parte do ponto de executar isso localmente.

Visão Local vs. Visão na Nuvem vs. Texto Local

Três guias neste site agora cobrem três diferentes compensações para obter dados estruturados de uma página sem seletores escritos à mão:

Localização do modelo Custo por chamada Precisão do JSON estruturado
Raspagem Web Ollama Local Texto HTML renderizado Grátis Confiável em HTML cortado
Guia de raspagem web GPT Vision Nuvem Captura de tela Por imagem, chave de nuvem necessária Um modelo pago muito maior — não testado neste guia
Este guia Local Captura de tela Grátis Não confiável neste tamanho de modelo
Nenhuma das três é universalmente correta. Se o valor é texto no DOM, analise o DOM — um modelo de texto local ou um seletor simples é mais rápido e mais barato do que qualquer pipeline de visão. Se o valor é genuinamente visual e a precisão importa, um modelo de visão na nuvem justifica seu custo por imagem. Um modelo de visão local tão pequeno se encaixa em um caso mais restrito do que ambos: leituras exploratórias ou de baixo risco, onde um humano ou uma verificação posterior podem captar um detalhe errado ocasional, não um pipeline que confia na saída sem supervisão. Com base nas evidências acima, isso é verdade tanto para uma descrição solta de uma frase quanto para um esquema multi-campo estrito — o modo de falha apenas parece diferente em cada um.

Conclusão

Combinar um modelo local com uma captura de tela fecha uma lacuna real entre dois guias existentes deste site. Nada no pipeline toca um modelo na nuvem: o Scrapeless Scraping Browser ainda renderiza e captura a página da mesma forma que um pipeline de visão na nuvem faria, e o Ollama lê o PNG resultante completamente neste computador. Para o que essa combinação é realmente boa, com base nas evidências executadas aqui, é mais restrita do que um modelo de visão na nuvem em ambas as direções — uma descrição de uma frase adicionou um detalhe estrutural que a página não possui, e um esquema JSON estrito ecoou seu próprio texto de marcador antes de migrar para uma saída que não era JSON de forma alguma. Use um modelo deste tamanho para leituras exploratórias que você planeja verificar, não para um pipeline que confia no resultado sem supervisão, e recorra ao guia de visão na nuvem quando a extração precisa ser precisa.

Crie uma conta gratuita no Scrapeless para obter uma chave de API, verifique a página do produto Scraping Browser para saber o que a sessão do CDP suporta e revise os preços do Scrapeless antes de executar o lado do navegador em escala.

Junte-se à nossa comunidade para comparar anotações com outros desenvolvedores que estão construindo pipelines de extração local: Discord · Telegram.

FAQ

P: Qual é a diferença real entre este guia e o guia de visão GPT na nuvem?

Onde o modelo é executado e o que custa. O guia de scraping web com GPT Vision deste site envia a captura de tela para um modelo multimodal hospedado por meio de uma API e cobra por imagem; este guia envia o mesmo tipo de captura de tela para um modelo em execução em localhost através do Ollama, sem chave de API e sem custo por chamada. Ambos leem pixels, não HTML.

P: Qual é a diferença entre este guia e o guia de extração de texto local do Ollama?

O que o modelo lê. Ollama Web Scraping busca HTML renderizado e entrega ao modelo local o texto para análise. Este guia nunca envia HTML para o modelo — ele entrega ao modelo local uma captura de tela e pede para ler a imagem.

P: Preciso de uma GPU para executar um modelo de visão local?

Não, mas espere que o tempo de espera varie muito sem uma. Cada execução neste guia usou moondream apenas em CPU, confirmado por ollama ps relatando 100% CPU durante a inferência, e as chamadas por trás deste guia variaram de segundos de dois dígitos a alguns minutos para o mesmo tipo de solicitação. O Ollama mantém um modelo residente por keep_alive após cada solicitação (5 minutos por padrão), então uma chamada enquanto ainda está carregado ignora o tempo de carregamento do disco que uma chamada fria paga — isso sozinho explica a maior parte da variação. Uma GPU que o Ollama pode acessar reduziria cada caso substancialmente.

P: Por que o campo images na API do Ollama parece diferente de uma solicitação de visão na nuvem?

Porque usa uma convenção diferente. O /api/generate do Ollama utiliza images como uma lista de strings base64 brutas sem prefixo. A maioria das APIs de visão na nuvem compatíveis com a OpenAI, incluindo a do guia de scraping web com GPT Vision deste site, espera uma URL completa de data:image/png;base64,... dentro de uma parte de conteúdo image_url. Portar código entre os dois formatos sem ajustar isso é a primeira coisa que quebra.

P: Por que a extração estruturada retornou campos vazios em vez de um erro?
O pedido em si foi bem-sucedido — Ollama retornou um 200 com um campo response, então raise_for_status() nunca é acionado. O modelo preencheu a forma JSON que lhe foi dita para produzir, mas não preencheu os valores, e continuou repetindo aquela forma vazia até que o limite de comprimento de saída o interrompesse no meio da string. Isso é uma falha de capacidade do modelo, não uma falha de HTTP, e é exatamente por isso que o código acima verifica json.loads() separadamente em vez de assumir que um 200 significa dados válidos e completos.

P: Um modelo de visão local maior pode resolver o problema de extração estruturada?

Provavelmente, a um custo. Um modelo de visão local da classe 7B, como llava:7b, tem mais capacidade para manter um esquema JSON e preenchê-lo corretamente, mas também precisa de muito mais RAM ou VRAM e é mais lento por token no mesmo hardware. O comércio ao qual este guia é baseado — genuinamente gratuito, genuinamente local — se torna mais difícil de manter à medida que o modelo cresce; em algum momento, o custo por imagem de um modelo de visão na nuvem se torna mais barato do que o hardware necessário para um grande modelo local funcionar bem.

P: Devo usar isso para uma pipeline de scraping em produção?

Não de forma não supervisionada, neste tamanho de modelo. Com base nas evidências aqui, nem uma descrição de uma frase nem um esquema estruturado retornaram completamente confiáveis — a descrição acrescentou um detalhe estrutural que a página não possui, e o esquema ecoou seu próprio texto de espaço reservado antes de se desviar para uma saída não JSON. Direcione a extração de esquema rigoroso para o guia de visão na nuvem ou para análise DOM com Ollama Web Scraping em vez disso, e mantenha um modelo de visão local como este para leituras exploratórias a custo zero, onde um humano ainda verifica o resultado, ou mude para um modelo local maior se ele precisar permanecer local.

P: É legal ler uma captura de tela com um modelo local?

Executar o modelo localmente não altera as regras de coleta para a própria página. Capture apenas páginas públicas, respeite os termos do site e as diretivas de robôs padronizadas por o Protocolo de Exclusão de Robôs, e mantenha o volume de solicitações limitado, independentemente de onde o modelo que lê o resultado acontece a ser executado.

Na Scorretless, acessamos apenas dados disponíveis ao público, enquanto cumprem estritamente as leis, regulamentos e políticas de privacidade do site aplicáveis. O conteúdo deste blog é apenas para fins de demonstração e não envolve atividades ilegais ou infratoras. Não temos garantias e negamos toda a responsabilidade pelo uso de informações deste blog ou links de terceiros. Antes de se envolver em qualquer atividade de raspagem, consulte seu consultor jurídico e revise os termos de serviço do site de destino ou obtenha as permissões necessárias.

Artigos mais populares

Catálogo