HTML bruto
O endereço chega com estrutura, scripts e ruído.
Código completo + modelo de extração. Abra páginas com JavaScript, limpe o conteúdo e devolva dados no formato que você definiu.
Ver o código completo$ python scraper.py
PASS navegador headless iniciado
PASS conteúdo principal isolado
PASS output.json salvo
O pacote, o navegador e o diagnóstico ficam na sua máquina. Rode na ordem abaixo.
pip install -U crawl4ai
crawl4ai-setup
crawl4ai-doctor
Os exemplos desta página foram conferidos com a API da versão 0.9.5. Se você chegar depois, compare a versão instalada com a documentação oficial.
O endereço chega com estrutura, scripts e ruído.
O Chromium invisível renderiza o JavaScript do site.
O filtro reduz menus, anúncios e blocos pouco relevantes.
Você define os campos antes de pedir a extração.
O resultado obedece ao formato; a veracidade ainda deve ser conferida.
O próprio script compara raw_markdown e fit_markdown. O resultado muda em cada página, por isso não publicamos um percentual inventado.
Texto, navegação, avisos e blocos secundários.
Conteúdo priorizado pelo filtro de densidade.
Troque a URL, execute e abra os dois arquivos Markdown. O programa falha com uma mensagem clara se o crawl não concluir.
import asyncio
from pathlib import Path
from crawl4ai import AsyncWebCrawler, BrowserConfig, CacheMode, CrawlerRunConfig
from crawl4ai.content_filter_strategy import PruningContentFilterLXML
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
URL = "https://example.com"
async def main() -> None:
run_config = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
markdown_generator=DefaultMarkdownGenerator(
content_filter=PruningContentFilterLXML(
threshold=0.45,
threshold_type="dynamic",
min_word_threshold=5,
)
),
)
async with AsyncWebCrawler(
config=BrowserConfig(headless=True)
) as crawler:
result = await crawler.arun(url=URL, config=run_config)
if not result.success:
raise RuntimeError(result.error_message)
raw = result.markdown.raw_markdown
fit = result.markdown.fit_markdown
Path("raw.md").write_text(raw, encoding="utf-8")
Path("fit.md").write_text(fit, encoding="utf-8")
print(f"raw_markdown: {len(raw)} caracteres")
print(f"fit_markdown: {len(fit)} caracteres")
if __name__ == "__main__":
asyncio.run(main())
Use um modelo quando a página varia. Use seletores CSS quando a estrutura é estável e você quer repetir sem chamadas de LLM.
O Pydantic cria o schema. O provider padrão abaixo usa Ollama local; para uma API paga, altere as duas variáveis de ambiente.
import asyncio
import json
import os
from pydantic import BaseModel, Field
from crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig
from crawl4ai import LLMConfig, LLMExtractionStrategy
class Produto(BaseModel):
nome: str = Field(description="Nome do produto")
preco: str = Field(description="Preço como aparece na página")
detalhes: list[str] = Field(description="Detalhes técnicos")
class Catalogo(BaseModel):
produtos: list[Produto]
async def main() -> None:
provider = os.getenv("LLM_PROVIDER", "ollama/qwen2.5:7b")
token = os.getenv("LLM_API_TOKEN", "no-token")
strategy = LLMExtractionStrategy(
llm_config=LLMConfig(provider=provider, api_token=token),
schema=Catalogo.model_json_schema(),
extraction_type="schema",
instruction="Extraia todos os produtos com nome, preço e detalhes técnicos.",
)
config = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
extraction_strategy=strategy,
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
url="https://example.com/produtos",
config=config,
)
if not result.success:
raise RuntimeError(result.error_message)
data = Catalogo.model_validate_json(result.extracted_content)
with open("output.json", "w", encoding="utf-8") as file:
json.dump(data.model_dump(), file, ensure_ascii=False, indent=2)
if __name__ == "__main__":
asyncio.run(main())
Crie o schema uma vez para a estrutura real do site. Depois cada execução usa apenas seletores CSS.
import asyncio
import json
from crawl4ai import AsyncWebCrawler, CacheMode, CrawlerRunConfig
from crawl4ai import JsonCssExtractionStrategy
SCHEMA = {
"name": "Produtos",
"baseSelector": ".product-card",
"fields": [
{"name": "nome", "selector": ".title", "type": "text"},
{"name": "preco", "selector": ".price", "type": "text"},
{"name": "detalhes", "selector": ".details", "type": "text"},
],
}
async def main() -> None:
config = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
extraction_strategy=JsonCssExtractionStrategy(SCHEMA),
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
url="https://example.com/produtos",
config=config,
)
if not result.success:
raise RuntimeError(result.error_message)
with open("output.json", "w", encoding="utf-8") as file:
json.dump(json.loads(result.extracted_content), file, ensure_ascii=False, indent=2)
if __name__ == "__main__":
asyncio.run(main())
O schema organiza o formato. O Pydantic valida os tipos antes de você salvar o arquivo.
{
"produtos": [
{
"nome": "Notebook Exemplo",
"preco": "R$ 4.999",
"detalhes": ["16 GB RAM", "1 TB SSD"]
}
]
}
Controle local não elimina as regras do site nem o custo do modelo que você escolher.
Instalação, navegador e limpeza rodam na sua máquina, sem mensalidade obrigatória. A oferta Cloud do Crawl4AI é opcional.
Ollama pode rodar localmente. Providers por API podem cobrar por uso. Configure o modelo de acordo com seu ambiente.
Respeite o robots.txt, os termos do site e aplique rate limit responsável. Não tente contornar acesso proibido.
O schema valida formato e tipos. Confira preços, nomes e detalhes antes de alimentar uma automação.
Os exemplos seguem o repositório e a documentação oficial. Consulte ambos quando atualizar a versão.
Este é o playbook enviado no Direct quando você comenta SCP: scraper completo, schema Pydantic e alternativa sem LLM.