Llama Web Scraping: Por que a Renderização Decide os Dados
Senior Cybersecurity Analyst
TL;DR:
- A diferença entre "não pode extrair" e "extrai de forma limpa" é uma chamada de renderização, e este guia a mede exatamente. Um GET simples em um catálogo de produtos somente com JavaScript retorna um marcador de modelo não renderizado; a mesma URL através da Scrapeless Universal Scraping API com
js_renderretorna 13 spans de produtos reais, e o Llama extraiu corretamente todos os 12 produtos genuínos deles. - Llama 4 é a camada barata atual, não Llama 3.
meta-llama/llama-4-scouté o Llama da geração atual mais barato no catálogo ao vivo do OpenRouter — uma família diferente e mais nova do nome Llama 3.1 que a maioria dos tutoriais existentes ainda utiliza. - O modelo filtrou silenciosamente uma linha de modelo quebrada por conta própria. A página renderizada realmente contém 13 spans de
product-name; um é um marcador${product.name}não hidratado, e a extração do Llama retornou exatamente os 12 produtos reais, ignorando o falso sem ser instruído a fazê-lo. - Este é o caminho na nuvem, não o local. Um guia separado neste site, Web Scraping com LLaMA 3, cobre a execução do Llama localmente através do Ollama; este executa o Llama 4 através de uma API hospedada.
- Ainda não tem chave de API nativa do Llama? O pedido idêntico é realizado através do OpenRouter. Este guia executou ao vivo em
meta-llama/llama-4-scoute mostra a saída capturada. - Gratuito para começar do lado da busca. Crie sua chave da API Scrapeless em app.scrapeless.com.
O Llama pode raspar sites?
Um endpoint hospedado do Llama lê texto e retorna campos; ele não busca páginas, executa seu JavaScript ou mantém uma sessão. Isso é verdade tanto se o modelo rodar localmente através do Ollama quanto por meio de uma API na nuvem — os pesos do modelo não mudam nada sobre como o HTTP funciona. O que difere entre os caminhos local e na nuvem é apenas onde a inferência acontece.
Web Scraping com LLaMA 3, já disponível neste site, cobre a rota local: llama3.1:8b através do Ollama, pareado com Selenium em páginas de produtos. Este guia cobre a outra metade — um modelo Llama 4 hospedado acessado por meio de uma API, sem download de modelo local e sem requisitos de GPU, em um alvo de demonstração diferente escolhido especificamente para provar por que a camada de busca importa. Para a questão de categoria mais ampla, o explicador de scrapers LLM cobre ferramentas LLM como parser em geral.
Instalar
openai cobre o caminho OpenRouter (Llama é servido atrás de uma superfície compatível com OpenAI lá), e requests cobre a camada de busca:
bash
pip install "llama-api-client==0.6.0" "openai==2.48.0" requests
Configurar
bash
export LLAMA_API_KEY="sua_chave_api_llama"
export SCRAPELESS_API_KEY="sk_sua_chave_scrapeless"
Obter uma página que o Llama pode realmente ler
O alvo da demonstração é uma página pública de prática de renderização construída especificamente para demonstrar exatamente essa diferença: sua grade de produtos está vazia até que o JavaScript do lado do cliente a preencha, e o HTML bruto contém em vez disso uma string de literal de template não executada. Um script demonstra a diferença e salva a versão que vale a pena extrair:
python
# fetch_rendered.py — GET simples vs renderização do lado do servidor, mesma URL
import os
import requests
URL = "https://www.scrapingcourse.com/javascript-rendering"
MARKER = 'class="product-name"'
plain = requests.get(URL, timeout=60).text
print(f"GET simples: {len(plain):,} caracteres | spans de product-name: {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, "method": "GET", "js_render": True},
},
timeout=120,
)
resp.raise_for_status()
rendered = resp.json().get("data", "")
print(f"renderizado: {len(rendered):,} caracteres | spans de product-name: {rendered.count(MARKER)}")
with open("page.html", "w", encoding="utf-8") as f:
f.write(rendered)
A execução imprime product-name spans: 1 para a busca simples — aquela única ocorrência é um template não executado <span class="product-name">${product.name}</span>, não dados reais — e product-name spans: 13 para o renderizado. A diferença entre os dois é exatamente o ciclo de vida do documento que a especificação de script HTML define: conteúdo que só existe após a execução de scripts no DOM. A renderização e o roteamento proxy acontecem no lado do servidor naquela única POST — a Universal Scraping API é a camada de busca, e page.html agora é algo que um modelo pode extrair.
Implementação básica: Llama como extractor
A API oficial Llama da Meta aceita saída estruturada através de response_format={"type": "json_schema", "json_schema": {...}}, conforme o SDK enviado em repositório do cliente Python da API Llama da Meta — não há um modo json_object simples neste endpoint, apenas saída guiada por esquema. O catálogo atual do OpenRouter lista meta-llama/llama-4-scout como o modelo de Llama de 4ª geração mais barato; na própria API nativa da Meta, o ID do modelo equivalente possui a forma mais completa Llama-4-Scout-17B-16E-Instruct-FP8.
Nota: Este bloco precisa de uma
LLAMA_API_KEYcom crédito — o único pré-requisito que este guia não assume. A próxima seção executa a extração idêntica ao vivo através do OpenRouter, com a saída capturada.
python
# extract_llama.py — extração nativa da API Llama (requer LLAMA_API_KEY)
import json
import os
from llama_api_client import LlamaAPIClient
client = LlamaAPIClient(api_key=os.environ["LLAMA_API_KEY"])
page_html = open("page.html", encoding="utf-8").read()
response = client.chat.completions.create(
model="Llama-4-Scout-17B-16E-Instruct-FP8",
max_completion_tokens=2000,
response_format={
"type": "json_schema",
"json_schema": {
"name": "Products",
"schema": {
"type": "object",
"properties": {
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {"name": {"type": "string"}, "price_usd": {"type": "number"}},
"required": ["name", "price_usd"],
},
}
},
"required": ["products"],
},
},
},
messages=[
{"role": "system", "content": "Extraia todos os produtos reais desta página. Ignore quaisquer espaços reservados de template não renderizados."},
{"role": "user", "content": page_html},
],
)
data = json.loads(response.completion_message.content.text)
print(f"extraído {len(data['products'])} produtos")
Note a forma da resposta: o cliente nativo da Meta retorna a mensagem sob response.completion_message.content.text, não o caminho choices[0].message.content que os clientes compatíveis com OpenAI usam.
Sem chave nativa? Execute pelo OpenRouter
O OpenRouter disponibiliza Llama atrás da mesma interface de chat-completions compatível com OpenAI que os outros modelos desta série. Esta é a versão que este guia executou de verdade, busca e extração em um único script auto-contido:
python
# extract_openrouter.py — a mesma extração, executada via OpenRouter
import json
import os
import requests
from openai import OpenAI
URL = "https://www.scrapingcourse.com/javascript-rendering"
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, "method": "GET", "js_render": True}},
timeout=120,
)
resp.raise_for_status()
page_html = resp.json().get("data", "")
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"])
completion = client.chat.completions.create(
model="meta-llama/llama-4-scout",
temperature=0,
max_tokens=2000,
response_format={"type": "json_object"},
messages=[
{
"role": "system",
"content": 'Extraia todos os produtos. Responda SOMENTE com JSON: {"products":[{"name":str,"price_usd":number}]}.',
},
{"role": "user", "content": page_html},
],
)
data = json.loads(completion.choices[0].message.content)
print(f"extraído {len(data['products'])} produtos da página renderizada")
for row in data["products"]:
print(json.dumps(row, ensure_ascii=False))
A execução ao vivo extraiu exatamente os 12 produtos reais, nenhum dos espaços reservados:
text
extraído 12 produtos da página renderizada
{"name": "Moletom Chaz Kangeroo", "price_usd": 52}
{"name": "Moletom Teton Pullover", "price_usd": 70}
Ambos operam com a mesma arquitetura de buscar-depois-extrair. Localmente, através do Ollama, evita o custo por token, mas precisa de um host com capacidade de GPU e de um download de modelo; o caminho da nuvem deste guia não requer hardware local, mas cobra por token. O post complementar Raspagem da Web com LLaMA 3 cobre a rota local em profundidade.
Q: Por que o modelo pulou um dos produtos na página renderizada?
Porque não era um produto real. O HTML renderizado na execução ao vivo deste guia continha 13 spans de product-name, mas um deles era um espaço reservado de template ${product.name} não hidratado, sobrando do framework do lado do cliente da página — o modelo corretamente o excluiu dos 12 extraídos.
Q: Raspagem com Llama é legal?
A camada de extração não altera as regras de coleta, seja no caminho da nuvem ou local. Extraia 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 quaisquer dados pessoais de acordo com a lei aplicável.
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.



