Web scraping sob seu controle

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
Leitura
8 min
Custo do crawl local
$0
Compatibilidade
Crawl4AI v0.9.5
scraper.pyexecução local
$ python scraper.py
PASS navegador headless iniciado
PASS conteúdo principal isolado
PASS output.json salvo
nomepreçodetalhes

Instale em três comandos

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.

Da página ao dado pronto

<nav> anúncio menu<main> produto…<script>…

HTML bruto

O endereço chega com estrutura, scripts e ruído.

JS executado

Navegador headless

O Chromium invisível renderiza o JavaScript do site.

# ProdutoPreço e detalhes úteisLinks preservados

Markdown limpo

O filtro reduz menus, anúncios e blocos pouco relevantes.

nome: strpreço: strdetalhes: list[str]

Schema Pydantic

Você define os campos antes de pedir a extração.

{"nome": "…","preco": "…"}

JSON validado

O resultado obedece ao formato; a veracidade ainda deve ser conferida.

Meça o corte de ruído

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.

Antesraw_markdown

Texto, navegação, avisos e blocos secundários.

Depoisfit_markdown

Conteúdo priorizado pelo filtro de densidade.

Contagens impressas na sua execução

O scraper completo

Troque a URL, execute e abra os dois arquivos Markdown. O programa falha com uma mensagem clara se o crawl não concluir.

scraper.pyCrawl + comparação raw/fit
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())

Escolha como extrair

Use um modelo quando a página varia. Use seletores CSS quando a estrutura é estável e você quer repetir sem chamadas de LLM.

Formato definido antes da extração

O Pydantic cria o schema. O provider padrão abaixo usa Ollama local; para uma API paga, altere as duas variáveis de ambiente.

extract_llm.pyPydantic + provider configurável
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())

Saída pronta para usar

O schema organiza o formato. O Pydantic valida os tipos antes de você salvar o arquivo.

output.jsonexemplo de estrutura
{
  "produtos": [
    {
      "nome": "Notebook Exemplo",
      "preco": "R$ 4.999",
      "detalhes": ["16 GB RAM", "1 TB SSD"]
    }
  ]
}

Limites honestos

Controle local não elimina as regras do site nem o custo do modelo que você escolher.

Crawl local

Instalação, navegador e limpeza rodam na sua máquina, sem mensalidade obrigatória. A oferta Cloud do Crawl4AI é opcional.

Extração por LLM

Ollama pode rodar localmente. Providers por API podem cobrar por uso. Configure o modelo de acordo com seu ambiente.

Robots e ritmo

Respeite o robots.txt, os termos do site e aplique rate limit responsável. Não tente contornar acesso proibido.

Validação não é verdade

O schema valida formato e tipos. Confira preços, nomes e detalhes antes de alimentar uma automação.

Continue na fonte

Os exemplos seguem o repositório e a documentação oficial. Consulte ambos quando atualizar a versão.

Código entregue. Próximo passo: rodar.

Este é o playbook enviado no Direct quando você comenta SCP: scraper completo, schema Pydantic e alternativa sem LLM.

Ver @herykrogues