Ollama Web Scraping: Execute um Scraper LLM Local Sem Chave de API
Senior Web Scraping Engineer
TL;DR:
- Ollama executa o modelo de extração na sua própria máquina, portanto, a etapa LLM de um scraper não custa chave de API e nem cobrança por token.
- O que a Ollama não faz é buscar. Um modelo local não possui navegador e não tem acesso a uma página; ele estrutura o texto que você lhe fornece.
- A diferença se mostra em um script. Um GET simples em uma página de demonstração renderizada em JavaScript dá 0 blocos de citação; a mesma URL através da API Universal de Scraping Scrapeless com
js_renderdá todos os 10 — e esse HTML renderizado é o que o modelo lê. - A extração é real neste guia. Uma execução ao vivo alimentou três blocos de citação renderizados a um modelo local
qwen2.5:0.5be recebeu de volta um JSON limpo com o texto e o autor de cada um — sem chamadas para a nuvem em lugar algum. - Modelos pequenos querem menos ruído. Corte o HTML para a região de conteúdo antes que o modelo a veja; um modelo de 0,5B em um snippet focado é rápido e preciso, onde a página completa não caberia.
- Gratuito para começar do lado da busca. Crie sua chave API Scrapeless em app.scrapeless.com.
Por que executar o modelo do scraper localmente
Um scraper LLM transforma o conteúdo da página em registros estruturados, e esse modelo não precisa estar na nuvem de outra pessoa. Ollama executa modelos abertos no seu próprio hardware por trás de uma pequena API HTTP, então a etapa de extração não tem chave de API, nem limite de taxa, e nenhum custo por token — útil quando você está processando muitas páginas ou lidando com dados que prefere não enviar a terceiros.
O que um modelo local não pode fazer é buscar. Ele não possui navegador, não mantém sessão e, em uma página renderizada em JavaScript, uma simples solicitação HTTP retorna marcação sem nenhum conteúdo. Assim, um scraper web Ollama é composto por duas camadas: uma camada de busca que retorna HTML renderizado fiel, e o modelo local como a camada de extração que transforma isso em registros. Este guia utiliza a API Universal de Scraping Scrapeless para a primeira camada. Se em vez disso você deseja dar a um modelo local uma busca web ao vivo — o modelo chamando uma ferramenta de busca e raciocinando sobre os resultados — esse é um trabalho diferente, abordado pelo guia de busca web local LLM; esta postagem é sobre extrair dados estruturados de uma página específica.
Pré-requisitos
- Ollama instalado e em execução, com um pequeno modelo amigável a ferramentas baixado:
ollama pull qwen2.5:0.5b. - Python 3.9 ou posterior com
requests. - Uma chave API Scrapeless do painel, exportada como
SCRAPELESS_API_KEY.
Instalação
Baixe um modelo pequeno e instale a única dependência Python. O servidor Ollama escuta em localhost:11434 uma vez que está em funcionamento.
bash
ollama pull qwen2.5:0.5b
pip install requests
Mantenha sua chave no ambiente, nunca no código-fonte:
bash
export SCRAPELESS_API_KEY="sk_your_scrapeless_key"
Obtenha uma página que o modelo possa realmente ler
A qualidade da extração é limitada pela fidelidade da busca, então comece por aí. Em uma página renderizada em JavaScript, o documento que um cliente HTTP simples recebe não é o documento que um leitor vê — o conteúdo chega apenas depois que os scripts constroem o DOM, um ciclo de vida definido pela especificação de script HTML. Um script conta a diferença:
python
# fetch_rendered.py — GET simples vs renderização do lado do servidor, mesma URL
import os
import requests
URL = "https://quotes.toscrape.com/js/"
MARKER = '<div class="quote">'
plain = requests.get(URL, timeout=60).text
print("chars GET simples:", len(plain), "| blocos de citação:", plain.count(MARKER))
resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={"actor": "unlocker.webunlocker", "input": {"url": URL, "js_render": True}},
timeout=120,
)
resp.raise_for_status()
rendered = resp.json().get("data", "")
print("chars renderizados:", len(rendered), "| blocos de citação:", rendered.count(MARKER))
A execução imprime 0 blocos de citação para a busca simples e 10 para a renderizada:
text
chars GET simples: 5806 | blocos de citação: 0
chars renderizados: 8940 | blocos de citação: 10
Renderização, desbloqueio e roteamento proxy acontecem todos do lado do servidor em aquele único POST — a API Universal de Scraping é a camada de busca, e o HTML renderizado é o que o modelo local extrai.
Extraia com um modelo local
Agora entregue o conteúdo para Ollama. Duas coisas mantêm um modelo pequeno preciso: trimme o HTML para a região do conteúdo para que o modelo não leia o chrome da página e peça JSON com format: "json" para que a saída seja analisável. O endpoint /api/generate do Ollama aceita o nome do modelo e o prompt e retorna a conclusão, documentada em a referência da API do Ollama:
python
# extract_local.py — buscar, trimar e extrair com um modelo local do Ollama
import json
import os
import re
import requests
resp = requests.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
headers={"Content-Type": "application/json", "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
json={"actor": "unlocker.webunlocker", "input": {"url": "https://quotes.toscrape.com/js/", "js_render": True}},
timeout=120,
)
resp.raise_for_status()
html = resp.json().get("data", "")
# Trim para os primeiros três blocos de citações — um modelo local pequeno se sai melhor com menos ruído.
blocks = re.findall(r'<div class="quote">.*?</small>', html, re.S)[:3]
snippet = "\n".join(blocks)
completion = requests.post(
"http://localhost:11434/api/generate",
json={
"model": "qwen2.5:0.5b",
"prompt": 'Extraia cada citação deste HTML em JSON com o formato exato '
'{"quotes":[{"text":"...","author":"..."}]}. Responda SOMENTE com o JSON.\n\nHTML:\n' + snippet,
"stream": False,
"format": "json",
"options": {"temperature": 0, "num_predict": 400},
},
timeout=600,
)
data = json.loads(completion.json()["response"])
records = data["quotes"]
print("registros:", len(records))
print("primeiro autor:", records[0]["author"])
print("primeiro texto:", records[0]["text"])
A execução local retornou três registros, com o texto e o autor intactos no primeiro:
text
registros: 3
primeiro autor: Albert Einstein
primeiro texto: O mundo como o criamos é um processo do nosso pensamento. Não pode ser mudado sem mudar nosso pensamento.
Esse é o scraper completo, e a parte do modelo nunca tocou a rede: uma POST ao Scrapeless para buscar e renderizar, uma chamada para localhost para extrair. Escale o número de blocos por chamada para o que seu hardware suporta — um modelo de 0.5B na CPU é mais lento do que um endpoint na nuvem, portanto, lote pequeno e mantenha a entrada concentrada.
Obtenha sua chave API no plano gratuito: app.scrapeless.com
Padrões Avançados
- Combine o modelo com o hardware.
qwen2.5:0.5bé rápido o suficiente para demonstrações na CPU; um modelo 3B ou 7B extrai mais confiavelmente de páginas mais bagunçadas, se você tiver memória e paciência. A estrutura do pedido não muda — apenas a stringmodelmuda. - Trim antes de solicitar. Isolar o contêiner de conteúdo é o maior fator de qualidade para um modelo pequeno. Envie o bloco repetido, não o documento inteiro, e tanto o custo de token quanto a taxa de erro diminuem.
- Mantenha
format: "json"etemperature: 0. O modo JSON restringe a saída a JSON analisável, e a temperatura zero mantém a extração estável entre execuções; nenhum dos dois é opcional para um scraper. - Loop em Python, não no prompt. Uma região de conteúdo por solicitação mantém os registros de se misturarem e torna uma má extração atribuível a uma página específica.
Solução de Problemas
Conexão recusadaem localhost:11434. O servidor Ollama não está em funcionamento. Inicie-o (ollama serve) e confirme que o modelo foi baixado comollama list.- Zero blocos para extrair. Sua busca retornou o HTML pré-renderizado. Conte um elemento conhecido da mesma forma que o primeiro script faz; uma busca quase vazia é um problema de renderização, corrigido com
js_render, não um problema do modelo. - O modelo retorna prosa, não JSON. Você deixou de lado
format: "json". Com isso, o Ollama restringe a saída; sem isso, você está analisando boa vontade. - A extração é lenta ou perde registros. O modelo é pequeno demais para o tamanho da entrada. Trim para menos blocos por chamada, ou mude para um modelo maior — pequenos modelos locais trocam precisão por velocidade, e um prompt mais curto e limpo é como você retoma ambos.
Conclusão
Ollama ganha seu lugar como a camada de extração que roda onde você está: modelos abertos no seu próprio hardware, sem chave e sem conta por token, transformando o conteúdo da página em JSON. A camada que decide se tudo isso é possível é a busca — a contagem de 0 contra 10 do primeiro script resolve isso — e uma POST renderizada do servidor fecha a lacuna. Conecte os dois e uma página renderizada se torna registros estruturados, com a parte do modelo permanecendo inteiramente em localhost.
Crie uma conta gratuita no Scrapeless para obter uma chave de API, e a documentação para desenvolvedores cobre os parâmetros unlocker.webunlocker. Confira os preços do Scrapeless quando planejar um trabalho recorrente.
Perguntas Frequentes
P: O Ollama pode raspar sites por conta própria?
Não. O Ollama executa um modelo de linguagem localmente; ele não possui um cliente HTTP para páginas arbitrárias e não renderiza JavaScript. Ele estrutura o texto que você fornece. Combine-o com uma camada de recuperação — aqui, a API Universal Scraping do Scrapeless, que renderiza a página no lado do servidor — e o modelo local lida com a extração.
P: Como isso é diferente de dar a um LLM local uma pesquisa na web?
Direção. Uma configuração de pesquisa na web permite que o modelo chame uma ferramenta de busca e raciocine sobre os resultados para responder a uma pergunta; esta configuração busca uma página específica que você escolhe e faz com que o modelo extraia campos estruturados dela. Uma é resposta aumentada por busca, a outra é um pipeline de raspagem — o guia de pesquisa na web com LLM local mencionado acima cobre a primeira.
P: Qual modelo local devo usar para extração?
O menor que contenha seu esquema. A extração com um prompt JSON rigoroso e temperature: 0 não é pesada em raciocínio, então um modelo de 0,5B funciona em um trecho reduzido, como mostra a execução acima. Passe para um modelo de 3B ou maior somente quando as páginas estiverem bagunçadas o suficiente para que o pequeno não consiga extrair campos.
P: Preciso de uma GPU?
Não. A execução neste guia usou um modelo de 0,5B em CPU. Uma GPU torna modelos maiores práticos e tudo mais rápido, mas um modelo pequeno em CPU é suficiente para construir e testar o pipeline.
P: Raspar com um modelo local é legal?
Executar o modelo localmente não altera as regras de coleta. Busque apenas páginas públicas, respeite os termos do site e as diretrizes de robôs padronizadas pelo Protocolo de Exclusão de Robôs, mantenha os volumes limitados e trate qualquer dado pessoal sob as leis que se aplicam a você.
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.



