🎯 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

Agentes LangChain que Veem a Web Ao Vivo: Construindo Pipelines de Dados AI com Scrapeless

Isabella Garcia
Isabella Garcia

Web Data Collection Specialist

05-May-2026

Principais Conclusões:

  • Integração de LangChain de primeira mão. O pacote langchain-scrapeless no PyPI fornece cinco ferramentas prontas para uso — ScrapelessDeepSerpGoogleSearchTool, ScrapelessDeepSerpGoogleTrendsTool, ScrapelessUniversalScrapingTool, ScrapelessCrawlerCrawlTool e ScrapelessCrawlerScrapeTool — que podem ser usadas diretamente em um agente LangChain ou LangGraph. Sem encadeamentos de subprocessos, sem fiação personalizada de CDP.
  • O pipeline consiste em quatro etapas: Descobrir → Renderizar → Extrair → Armazenar. Pesquise no Google com a ferramenta deep-SERP, renderize qualquer URL com a ferramenta de raspagem universal (Scraping Browser por trás dos panos), extraia registros tipados com PydanticOutputParser e, opcionalmente, incorpore em um armazenamento vetorial para RAG a jusante.
  • O agente decide quando raspar. O create_agent do LangChain (runtime do LangGraph por trás dos panos) permite que o LLM escolha entre responder a partir do contexto anterior e chamar a ferramenta Scrapeless — o navegador em nuvem só é ativado quando dados novos são realmente necessários, o que mantém custo e latência controlados em turnos de rotina.
  • Registros tipados, não HTML bruto. Combinar ScrapelessUniversalScrapingTool (resposta em markdown) com um schema Pydantic transforma as páginas raspadas em registros validados de Produto / Artigo / ListaDeEmprego nos quais o código a jusante pode confiar sem a necessidade de colas de parsing extras.
  • Navegador em nuvem anti-detecção, proxies residenciais em mais de 195 países. O Scrapeless Scraping Browser lida com renderização em JavaScript, saída de proxy residencial e randomização de impressões digitais (UA, fuso horário, WebGL, canvas) em cada sessão, de modo que o agente permaneça focado na lógica em vez de na evasão.

Introdução: Pipelines de dados de IA que veem a web ao vivo

Um LLM básico responde a partir de dados de treinamento. Para a maioria dos fluxos de trabalho agentais que realmente funcionam — inteligência de preços competitiva, pesquisa de leads, monitoramento de mercado, ingestão estruturada de notícias, RAG sobre a web ao vivo — o modelo precisa ver a página agora mesmo. Limites de treinamento, paywalls, SPAs carregadas de forma lenta e renderização personalizada empurram a resposta para um território que o LLM nunca viu, e a resposta cita um número desatualizado ou recusa educadamente.

LangChain mais um navegador em nuvem é a resposta padrão. O modelo raciocina; o navegador busca; o agente costura os dois juntos. O ponto de fricção que a maioria das equipes enfrenta está abaixo do agente: proxies residenciais, renderização em JavaScript, impressão digital anti-detecção e ciclo de vida da sessão precisam ser resolvidos antes que o agente possa fazer algo útil. Playwright direto sobre uma VPN residencial funciona para uma execução em laptop única; não sobrevive a um cronograma de produção.

O Scrapeless Scraping Browser lida com essas quatro preocupações em nível de plataforma, e o pacote langchain-scrapeless no PyPI os expõe como ferramentas nativas do LangChain. Este post orienta a composição dessas ferramentas em um pipeline de dados de IA de quatro etapas Descobrir → Renderizar → Extrair → Armazenar, com um exemplo prático de pesquisa competitiva, saída tipada em Pydantic, concorrência controlada e ganchos de observabilidade. Para o mesmo primitivo sobre um protocolo diferente, consulte o post de integração MCP.


O que você pode construir

As cinco ferramentas enviadas pelo langchain-scrapeless cobrem os padrões mais comuns de pipeline de dados de IA:

  • Inteligência de preços competitiva. Pesquise uma categoria, renderize as páginas dos principais varejistas, extraia um registro tipado de Produto com preço, classificação e contagem de avaliações.
  • Monitoramento de SERP. Acompanhe o ranking de palavras-chave e a variação de snippets em diferentes regiões com ScrapelessDeepSerpGoogleSearchTool parametrizado por gl e hl.
  • Acompanhamento de tendências de mercado. Extraia interest_over_time e consultas relacionadas com ScrapelessDeepSerpGoogleTrendsTool para dimensionamento de categorias (o acesso ao endpoint Trends depende do seu nível de plano Scrapeless).
  • Extração de detalhes de produtos em escala. Insira uma lista de URLs no ScrapelessCrawlerScrapeTool e receba de volta markdown pronto para um extrator LLM.
  • Geração de leads a partir de diretórios. Raspagem de sites de listas de negócios com ScrapelessCrawlerCrawlTool, analise linhas de contato em registros tipados e remova duplicatas por domínio.
  • Ingestão estruturada de notícias para RAG. Renderize páginas de editores para markdown limpo, extraia registros de Artigo, incorpore em um armazenamento vetorial do LangChain e consulte com cadeias aumentadas de recuperação.

Todos os seis pipelines compõem os mesmos primitivos — buscar, renderizar, extrair, armazenar — e o exemplo prático abaixo cobre toda a cadeia de ponta a ponta.


Por que o Scrapeless Scraping Browser

O Scrapeless Scraping Browser é um navegador em nuvem anti-detecção e personalizável, projetado para raspadores da web e agentes de IA. Para agentes do LangChain especificamente, ele traz:

  • Proxies residenciais em mais de 195 países — consultas geolocalizadas retornam as listagens que um usuário local veria, e a rotação é automática em cada sessão.
  • Renderização JavaScript do lado da nuvem — Chromium completo com a página hidratada antes da extração, então SPAs, feeds de rolagem infinita e painéis carregados de forma preguiçosa são alvos de primeira classe.
  • Fingerprinting anti-detecção em cada sessão — UA, fuso horário, idioma, resolução de tela, WebGL e canvas são randomizados por sessão, com uma API de impressão digital personalizada para identidades fixas quando a consistência é importante.
  • Persistência de sessão na camada do navegador em nuvem via sessionTTL (60–900s) e sessionName — disponível ao acessar diretamente o endpoint WSS; as chamadas da ferramenta langchain-scrapeless alocam uma nova sessão por invoke, o que é o padrão certo para um pipeline de pesquisa.
  • Integração de primeira parte com LangChainpip install langchain-scrapeless expõe o navegador em nuvem como ferramentas nativas do LangChain; sem wrappers de subprocesso, sem encanamentos de CDP, sem serializadores personalizados.

Obtenha sua chave de API no plano gratuito em Scrapeless. A integração completa está documentada em github.com/scrapeless-ai/langchain-scrapeless.

Reivindique seu plano gratuito e comece a extrair:

Junte-se à vibrante comunidade do Scrapeless para reivindicar um plano gratuito de $5-10 e conectar-se com outros inovadores:

Comunidade Oficial do Discord do Scrapeless
Comunidade Oficial do Telegram do Scrapeless


Pré-requisitos

  • Python 3.10 ou mais recente.
  • Uma conta Scrapeless e chave de API — inscreva-se em Scrapeless e copie a chave em Configurações → Gerenciamento de Chaves de API.
  • Uma chave de API de modelo de chat — os exemplos abaixo utilizam OpenAI (OPENAI_API_KEY); o mesmo código de agente funciona com langchain-anthropic, langchain-google-genai, langchain-ollama ou qualquer modelo de chat do LangChain trocando a linha ChatOpenAI.
  • Familiaridade básica com pip e venv.

Instalação

A configuração completa consiste em quatro sub-etapas. Cada uma é verificável de forma independente, para que você possa pausar e confirmar antes de seguir em frente.

1. Crie um venv e instale os pacotes

bash Copy
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install langchain langchain-scrapeless langchain-openai langgraph pydantic

langchain-scrapeless puxa langchain-core e o SDK Python do Scrapeless como dependências transitivas. O pacote meta langchain fornece langchain.agents.create_agent, o moderno runtime de agente ReAct (não depreciado); langgraph fornece o runtime subjacente CompiledStateGraph; langchain-openai é o provedor de modelo de chat usado nos exemplos. Troque para langchain-anthropic ou outro provedor, se preferir.

2. Configure suas chaves de API

Exporte ambas as chaves para a sessão de shell atual:

bash Copy
export SCRAPELESS_API_KEY="sua_chave_api_aqui"
export OPENAI_API_KEY="sua_chave_openai_aqui"

Para uma instalação permanente, adicione as mesmas linhas em ~/.bashrc / ~/.zshrc, ou use um carregador .env (python-dotenv) e carregue o arquivo no início do processo. As ferramentas Scrapeless leem SCRAPELESS_API_KEY do ambiente automaticamente — você não deve passá-la como um argumento de construtor.

3. Verifique a instalação

Um curto teste de fumaça que exerce a ferramenta de pesquisa e imprime um resultado de uma linha. A API do Scrapeless ocasionalmente retorna um 400 transitório na primeira chamada após uma inicialização a frio; o teste faz até três tentativas para que uma única reexecução resgate esses casos:

python Copy
# verify.py
import time
from langchain_scrapeless import ScrapelessDeepSerpGoogleSearchTool

tool = ScrapelessDeepSerpGoogleSearchTool()
for attempt in range(3):
    try:
        result = tool.invoke({"q": "navegador de raspagem scrapeless",
                              "hl": "pt", "gl": "br"})
        print(str(result)[:300])
        break
    except ValueError as e:
        print(f"transitório (tentativa {attempt + 1}): {e}")
        time.sleep(3)

Execute: python verify.py. Uma execução bem-sucedida imprime uma string de resultados de pesquisa em poucos segundos. Se as três tentativas levantarem ValueError com falhou com status 401, a chave da API está faltando ou incorreta; verifique novamente echo $SCRAPELESS_API_KEY no mesmo shell. 400s persistentes após três tentativas indicam que a conta pode não ter acesso ao endpoint solicitado — veja a FAQ sobre erros transitórios.

4. (Opcional) Fixe as versões das dependências

Para construções reprodutíveis, fixe as versões que você testou. A combinação resolvida por pip install langchain langchain-scrapeless langchain-openai langgraph pydantic em um ambiente Python 3.12 limpo é:

Copy
langchain==1.2.17
langchain-core==1.3.2
langchain-openai==1.2.1
langchain-scrapeless==0.1.3
langgraph==1.1.10
pydantic==2.13.3
scrapeless==1.1.1

Nota: os metadados do pacote langchain-scrapeless 0.1.3 declaram langchain-core <0.4.0, mas pip resolve para langchain-core 1.3.2 porque langchain-openai o requer; a importação em tempo de execução ainda funciona. Para evitar completamente o aviso do resolvedor, instale langchain-scrapeless e apenas o provedor de modelo de chat que você precisa (por exemplo, não use langchain-openai e passe uma instância de ChatAnthropic em vez disso). LangGraph 1.0 foi lançado em outubro de 2025; a série 1.1.x é a versão estável atual.


Como você realmente usa isso: instrua seu agente

Após a instalação, você constrói pipelines conversando com o agente — não rederivando seletores CSS toda vez que o site-alvo muda seu DOM. O agente controla o loop de descobrir → renderizar → extrair e o LLM escolhe a ferramenta certa para cada interação.

Prompts que você pode colar

Você digita O que o agente faz
"Encontre os 5 melhores máquinas de espresso portáteis e retorne nome, preço, avaliação como JSON." Busca no Google, renderiza os principais resultados, extrai um Product[] digitado.
"Dê-me o interesse atual do Google Trends nos últimos 12 meses para banco de dados vetorial nos EUA." Chama ScrapelessDeepSerpGoogleTrendsTool com data_type="interest_over_time" (requer acesso ao nível de plano do ponto final de Trends).
"Navegue https://example.com/docs até a profundidade 2 e retorne markdown para cada página." Chama ScrapelessCrawlerCrawlTool com limit=....
"Renderize https://www.amazon.com/dp/B08N5WRWNW como markdown." Chama ScrapelessUniversalScrapingTool com response_type="markdown".
"Pesquise por startups série A em fintech 2026, liste as empresas e o tamanho de sua rodada de financiamento." Busca → renderiza → extrai digitado em cadeia automaticamente.
"Pegue a página inicial e a página de preços desses três concorrentes de SaaS e resuma as diferenças." Multi-URL ScrapelessCrawlerScrapeTool → resumo do LLM.
"Observe esta página de carreiras da Greenhouse e me diga quais funções correspondem a engenheiro de equipe ou infra." Renderiza → filtro de palavras-chave → linhas JSON.
"Quais são os 10 melhores resultados orgânicos para tutorial langchain scrapeless de uma saída do Reino Unido?" ScrapelessDeepSerpGoogleSearchTool com gl="uk", hl="en".

Exemplo prático

Você digita:

Encontre as 3 melhores máquinas de espresso portáteis para viagem abaixo de $150. Para cada uma, retorne nome, preço, avaliação média, contagem de avaliações e três recursos principais. Fixe a pesquisa a uma saída dos EUA.

O plano do agente (em linguagem simples):

  1. Chame ScrapelessDeepSerpGoogleSearchTool com q="melhores máquinas de espresso portáteis abaixo de 150", gl="us", hl="en", num=5 para obter URLs de resultados orgânicos.
  2. Para os 3 principais URLs de resultado, chame ScrapelessUniversalScrapingTool com response_type="markdown" para renderizar cada página como markdown limpo.
  3. Passe cada página renderizada ao LLM com um PydanticOutputParser vinculado a um esquema Product; rejeite qualquer página onde o parser não consiga extrair nome e preço.
  4. Agregue os três registros Product em um array JSON e retorne.

O que você recebe de volta:

json Copy
[
  {
    "name": "Wacaco Nanopresso",
    "price": 79.95,
    "rating": 4.7,
    "review_count": 12483,
    "key_features": [
      "Operação manual por bomba de mão",
      "Até 18 bar de pressão de extração",
      "Compatível com café moído ou cápsulas NS via adaptador"
    ],
    "url": "https://example.com/p/wacaco-nanopresso"
  },
  {
    "name": "Flair NEO Flex",
    "price": 119.00,
    "rating": 4.5,
    "review_count": 2104,
    "key_features": [
      "Acionamento por alavanca, sem eletricidade necessária",
      "Pressão de nível de espresso com porta-filtro sem fundo",
      "Destacável para viagem"
    ],
    "url": "https://example.com/p/flair-neo-flex"
  },
  {
    "name": "Outin Nano",
    "price": 129.99,
    "rating": 4.6,
    "review_count": 5871,
    "key_features": [
      "Elemento de aquecimento embutido",
      "Ciclo de auto-limpeza",
      "Carregamento USB-C, ~3 minutos para aquecer"
    ],
    "url": "https://example.com/p/outin-nano"
  }
]
// O esquema reflete exatamente o que o parser da Etapa 4 emite. Os valores dos campos são ilustrativos.

Formulando prompts

Formulação Efeito
"Use uma saída alemã (gl=de)." Fixa a região do proxy da ferramenta de busca; os resultados retornam o que um usuário de Berlim veria.
"Busque como markdown." response_type="markdown" na ferramenta de raspagem universal — contexto LLM mais barato, mais estável em seletores do que HTML.
"Limite a navegação a 25 páginas." limit=25 na ScrapelessCrawlerCrawlTool.
"Ignore páginas que não tenham preço." O parser retorna None para campos ausentes; o agente filtra.
"Execute três URLs em paralelo." Entrega ao padrão de concorrência limitada na Etapa 6 abaixo.

As Etapas 1–6 abaixo são a referência interna. Leia-as uma vez para ver como o padrão de descobrir → renderizar → extrair → armazenar se compõe; depois confie no agente para aplicá-lo a qualquer consulta que o operador entregar.


Arquitetura

Copy
┌──────────────────────────────────────────────────────────────────────┐
│  LangChain create_agent  (tempo de execução do LangGraph)             │
│                                                                      │
│  ┌───────────────────────┐     ┌────────────────────────────────┐    │
│  │  Modelo de chat       │ ──► │  Ferramentas (langchain-scrapeless)  │    │
│  │  (OpenAI / Anthropic  │     │   • DeepSerpGoogleSearch       │    │
│  │   / Gemini / Ollama)  │ ◄── │   • UniversalScraping          │    │
│  └───────────────────────┘     │   • CrawlerCrawl               │    │
│            ▲                   │   • CrawlerScrape              │    │
│            │                   │   • DeepSerpGoogleTrends       │    │
│            │                   └──────────────┬─────────────────┘    │
│            │                                  │                      │
│            │           PydanticOutputParser   │                      │
│            │           (registros tipados)     ▼                      │
│            │                ┌──────────────────────────────────┐     │
│            │                │  Navegador em nuvem sem raspagem │     │
│            │                │  • proxies residenciais (195+)    │     │
│            │                │  • impressão digital anti-deteção │     │
│            │                │  • renderização de JS Chromium     │     │
│            │                │  • TTL de sessão 60–900s           │     │
│            │                └──────────────────────────────────┘     │
│            │                                  │                      │
│            └──────────────────────────────────┘                      │
│            registros tipados fluem de volta para o agente              │
└──────────────────────────────────────────────────────────────────────┘
                              │
                              ▼ (opcional)
                  ┌───────────────────────────┐
                  │  Armazenamento vetorial    │
                  │  (Chroma / PGVector / pgvector)  │
                  └───────────────────────────┘

Três camadas, separação limpa: o LLM raciocina sobre a conversa, as ferramentas langchain-scrapeless envolvem o navegador em nuvem através de interfaces nativas do LangChain, e o navegador em nuvem lida com todas as preocupações que não envolvem raciocínio. Cada camada pode ser trocada — modelo de chat, prompt, até mesmo a ferramenta subjacente — sem reescrever as outras.


Etapa 1 — Definir o esquema de saída tipado

Pydantic é o elemento primário que suporta a carga que transforma markdown raspado em algo que o código subsequente pode confiar. Defina o registro-alvo uma vez e vincule-o ao extrator LLM na Etapa 4.

python Copy
# schema.py
from typing import Optional
from pydantic import BaseModel, Field, HttpUrl

class Product(BaseModel):
    name: str = Field(...,
        description="Nome do produto. Sempre obrigatório — use o título da página ou H1 se não houver um nome claro do produto.")
    price: Optional[float] = Field(None, description="Preço numérico em USD; nulo se ausente")
    rating: Optional[float] = Field(None, description="Avaliação média, 0–5; nulo se ausente")
    review_count: Optional[int] = Field(None, description="Número de avaliações; nulo se ausente")
    key_features: list[str] = Field(default_factory=list, description="3–5 bullets de recursos curtos")
    url: HttpUrl = Field(..., description="URL canônica do produto")

Marque cada campo que pode estar ausente como Optional e defina listas vazias por padrão — intersticiais anti-bot, diferenças de layout regionais e nós DOM hidratados preguiçosamente significam que as páginas rotineiramente omitem um ou dois campos, e um esquema não opcional rejeita linhas que poderiam ser úteis. Mantenha name como obrigatório e forneça uma alternativa em sua descrição (título da página, H1) para que o extrator nunca retorne null para o campo obrigatório; essa única dica permite que o esquema absorva páginas barulhentas sem levantar erros.


Etapa 2 — Descobrir com ScrapelessDeepSerpGoogleSearchTool

A ferramenta deep-SERP retorna resultados orgânicos do Google para uma consulta, parametrizada por idioma (hl), país (gl) e contagem de resultados (num). É o elemento primário de descoberta — a busca amplia o universo de URLs antes que você comprometa qualquer orçamento de renderização por página.

python Copy
# discover.py
from langchain_scrapeless import ScrapelessDeepSerpGoogleSearchTool

search = ScrapelessDeepSerpGoogleSearchTool()
results = search.invoke({
    "q": "melhores máquinas de espresso portáteis 2026 abaixo de 150",
    "hl": "pt",
    "gl": "br",
    "num": 5,
})
print(results)

hl controla o idioma do resultado e gl controla o país de saída — eles são as alavancas regionais. Para monitoramento de SERP em diferentes regiões, execute a mesma consulta com diferentes valores de gl (us, de, jp, br) e compare as listas de resultados. Respostas transitórias de ValueError (HTTP 400/503 encapsuladas pela ferramenta) ou de TimeoutError são normais no alto volume de consultas; envolva a chamada com o decorador de tentativas da Etapa 6 antes de escalar.


Etapa 3 — Renderizar com ScrapelessUniversalScrapingTool

A ferramenta universal de scraping é o Scrapeless Scraping Browser. Ela aceita uma URL e retorna a página renderizada como markdown (ou HTML, ou captura de tela). O Markdown é o formato mais barato para alimentar um extrator LLM — ele remove anúncios, navegação e estilos inline, deixando apenas o conteúdo sobre o qual a página realmente trata.

python Copy
# render.py
from langchain_scrapeless import ScrapelessUniversalScrapingTool

scrape = ScrapelessUniversalScrapingTool()
markdown = scrape.invoke({
    "url": "https://example.com/p/wacaco-nanopresso",
    "response_type": "markdown",
})
print(markdown[:600])

Cada invoke aloca uma nova sessão de navegador na nuvem, que é a configuração padrão ideal para um pipeline de pesquisa — sessões novas por URL são mais simples e mais resilientes ao estado anti-bot de cada sessão. (A reutilização de sessão entre chamadas via sessionName é um recurso a nível de CDP; se o seu fluxo de trabalho precisar de cookies quentes e estado de login entre páginas, acesse diretamente o navegador na nuvem via o endpoint WSS em vez de usar esta ferramenta do LangChain.) A ferramenta também aceita response_type="html" quando você precisa executar seus próprios seletores, response_type="plaintext" para o contexto LLM mais barato, ou response_type="png" / "jpeg" para pipelines de regressão visual.


Etapa 4 — Extrair com PydanticOutputParser

O esquema definido na Etapa 1 conecta-se diretamente a uma cadeia da Linguagem de Expressão LangChain (LCEL), que recebe o markdown renderizado e retorna um Product tipado. O parser injeta o esquema JSON no prompt e valida a resposta do LLM em relação a ele.

python Copy
# extract.py
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

from schema import Product

parser = PydanticOutputParser(pydantic_object=Product)

prompt = ChatPromptTemplate.from_messages([
    ("system",
     "Você extrai registros de produtos de páginas web renderizadas.\n"
     "A saída deve corresponder estritamente a este esquema:\n{format_instructions}"),
    ("human",
     "URL de origem: {url}\n\nMarkdown renderizado:\n{markdown}\n\n"
     "Retorne um registro de Produto. O campo `name` é obrigatório — use o título da página "
     "ou H1 se não houver um nome de produto claro. Defina SOMENTE os campos opcionais "
     "(preço, classificação, contagem de avaliações) como nulos quando ausentes."),
]).partial(format_instructions=parser.get_format_instructions())

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
extract_chain = prompt | llm | parser

product = extract_chain.invoke({"url": "https://example.com/p/wacaco-nanopresso",
                                "markdown": "<markdown renderizado da Etapa 3>"})
print(product.model_dump())

Falhas do parser são raras quando três coisas são válidas: (1) cada campo incerto é marcado como Optional[...], (2) o prompt informa explicitamente ao modelo que apenas os campos opcionais podem ser null, e (3) cada campo obrigatório tem uma alternativa em sua descrição (por exemplo, name usa o título da página ou H1). Com esses três aspectos em vigor, o contrato nulo do esquema gerencia campos opcionais ausentes, e a instrução do prompt impede que o LLM nulifique campos obrigatórios em páginas ruidosas — assim, a cadeia opera de forma limpa sem qualquer invólucro de retry.


Etapa 5 — Compor em um create_agent

O agente conecta as três ferramentas e permite que o LLM decida qual delas chamar em resposta a qualquer mensagem do usuário. langchain.agents.create_agent é a execução canônica a partir do langchain 1.2 (substitui o langgraph.prebuilt.create_react_agent obsoleto e usa a mesma grafo de estado LangGraph por trás).

python Copy
# agent.py
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain_scrapeless import (
    ScrapelessDeepSerpGoogleSearchTool,
    ScrapelessUniversalScrapingTool,
    ScrapelessCrawlerCrawlTool,
)
from tenacity import (retry, stop_after_attempt,
                       wait_exponential, retry_if_exception_type)

# Ferramentas de primeira linha subjacentes
_search   = ScrapelessDeepSerpGoogleSearchTool()
_scrape   = ScrapelessUniversalScrapingTool()
_crawl    = ScrapelessCrawlerCrawlTool()

# O decorador de retry que o agente verá em cada chamada de ferramenta.
# Ferramentas Scrapeless expõem erros de API transitórios como ValueError, então esse é o filtro.
_retry = retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=15),
    retry=retry_if_exception_type(ValueError),
)

def _check(payload: str) -> str:
    # O navegador na nuvem às vezes retorna HTTP 200 com um JSON ERR_ incorporado.
    # Exiba como ValueError para que o decorador @_retry acima entre em ação.
    if isinstance(payload, str) and payload.startswith('{"statusCode"') and "ERR_" in payload:
        raise ValueError(f"Erro do navegador na nuvem: {payload[:200]}")
    return payload

@tool
@_retry
def google_search(q: str, hl: str = "en", gl: str = "us", num: int = 5) -> str:
    """Procure no Google e retorne os principais resultados orgânicos como JSON."""
    return _check(str(_search.invoke({"q": q, "hl": hl, "gl": gl, "num": num})))
python Copy
@ferramenta
@_tentar
def renderizar_pagina(url: str) -> str:
    """Renderiza uma URL com o navegador em nuvem Scrapeless e retorna markdown limpo."""
    return _verificar(_raspar.invocar({"url": url, "response_type": "markdown"}))

@ferramenta
@_tentar
def rastrear_site(url: str, limite: int = 10) -> str:
    """Rastreia um site até um número limitado de páginas, retornando markdown para cada página."""
    return _verificar(str(_rastrear.invocar({"url": url, "limite": limite})))

llm = ChatOpenAI(modelo="gpt-4o-mini", temperatura=0)

prompt_do_sistema = (
    "Você é um agente de pesquisa que constrói conjuntos de dados de produtos tipados. "
    "Dada uma consulta de categoria, você: "
    "(1) chama google_search para as principais URLs orgânicas, "
    "(2) chama renderizar_pagina com cada URL promissora, "
    "(3) extrai um registro de Produto por página usando o esquema, "
    "(4) retorna um array JSON de registros. "
    "Defina gl='us' e hl='en' a menos que o usuário peça o contrário. "
    "Se uma página não tiver um preço, omita a linha do array final."
)

agente = criar_agente(llm,
                      [google_search, renderizar_pagina, rastrear_site],
                      prompt_do_sistema=prompt_do_sistema)

for pedaço in agente.stream(
    {"messages": [("humano",
                   "Encontre os 3 melhores fabricantes de espresso portáteis abaixo de $150 "
                   "e retorne nome, preço, classificação, contagem_de_avaliações, principais_recursos, url.")]},
    modo_stream="valores",
):
    pedaço["messages"][-1].imprimir_bonito()

O empilhamento de decoradores @ferramenta + @tentar é a peça fundamental para a produção. As ferramentas langchain-scrapeless envolvem erros subjacentes ScrapelessErrors como ValueError antes de levantar, então respostas 400/503 transitórias dentro do loop de chamada de ferramentas do agente sobem como ValueError. Sem a tentativa, uma única falha transitória derruba toda a execução do agente; com o empilhamento de decoradores, cada chamada de ferramenta tenta até três vezes com retrocesso exponencial e com jitter antes de desistir. (O Runnable.with_retry() do langchain-core retorna um RunnableRetry, que criar_agente não aceita — a função decorada com @ferramenta acima é o caminho que produz uma verdadeira StructuredTool dentro do shell de tentativa.)

agente.stream(..., modo_stream="valores") emite o estado completo da mensagem em cada etapa, para que o operador possa observar as chamadas de ferramentas do agente e o raciocínio intermediário em tempo real. Para uma única resposta final, troque por agente.invoke(...). Para passar o Product[] tipado da Etapa 4 através do agente, exponha a cadeia de extração como outra função @ferramenta e adicione-a à lista — o agente a chamará após cada renderização. O README do langchain-scrapeless ainda demonstra from langgraph.prebuilt import create_react_agent; esse caminho funciona, mas emite um aviso LangGraphDeprecatedSinceV10, então a importação moderna acima é o caminho recomendado.


Etapa 6 — Fortalecimento da produção

Um script de pesquisa que funciona em três URLs em um notebook não sobrevive a trinta mil. Quatro padrões de fortalecimento transformam o pipeline acima em algo que um agendador pode executar de forma não assistida.

Concurrência limitada

python Copy
# render_concorrente.py
import asyncio
from langchain_scrapeless import ScrapelessUniversalScrapingTool

raspar = ScrapelessUniversalScrapingTool()
SEM = asyncio.Semaphore(3)            # limite de 3 renderizações concisas por host

async def renderizar(url: str) -> str:
    async with SEM:
        return await raspar.ainvocar({"url": url, "response_type": "markdown"})

async def renderizar_tudo(urls: list[str]) -> list[str]:
    return await asyncio.gather(*(renderizar(u) for u in urls))

Três renderizações concisas por host é o ponto ideal — alto o suficiente para amortizar o custo de aquecimento por sessão, baixo o suficiente para permanecer abaixo dos limites de taxa por IP da maioria dos sites. Limite no nível do host, não globalmente; dez hosts diferentes com três trabalhadores cada é aceitável, dez trabalhadores todos atingindo o mesmo varejista não é.

Tentar em erros transitórios

python Copy
# tentar.py
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from langchain_scrapeless import ScrapelessUniversalScrapingTool

raspar = ScrapelessUniversalScrapingTool()

def _levantar_em_erro_embutido(payload: str) -> str:
    # O Scrapeless às vezes retorna HTTP 200 com um corpo JSON descrevendo um
    # erro interno do lado do navegador (reset de túnel, ERR_CONNECTION_RESET, ...).
    # A ferramenta não levanta isso; superficializa como ValueError para que a tentativa entre em ação.
    if payload.startswith('{"statusCode"') and "ERR_" in payload:
        raise ValueError(f"Erro do navegador em nuvem: {payload[:200]}")
    return payload

@retry(
    stop=stop_after_attempt(4),
    wait=wait_exponential(multiplier=1, min=2, max=20),
    retry=retry_if_exception_type((ValueError, TimeoutError)),
)
def renderizar_com_tentativa(url: str) -> str:
    return _levantar_em_erro_embutido(
        raspar.invocar({"url": url, "response_type": "markdown"}))

A sessão do navegador de raspagem ocasionalmente falha em duas formas distintas: uma falha de camada HTTP 400/503 (o wrapper langchain-scrapeless levanta isso como ValueError) e um HTTP 200 com um corpo JSON descrevendo um erro do lado do navegador, como ERR_TUNNEL_CONNECTION_FAILED (o wrapper não levanta — o JSON de erro retorna como uma string). O guardião _raise_on_embedded_error acima captura a segunda forma e a converte em ValueError, para que a mesma política de repetição se aplique. Com ambas as formas cobertas, o retrocesso exponencial com quatro tentativas cobre o percentil alto dos 90 sem enterrar falhas genuínas (bloqueios anti-bot, 404s) sob repetições. Para chamadas dirigidas por agentes, use a pilha de decoradores @tool + @retry da Etapa 5 — as funções de wrapper lá devem aplicar a mesma verificação _raise_on_embedded_error antes de retornar.

Observabilidade com LangSmith

bash Copy
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY="seu_langsmith_key"
export LANGCHAIN_PROJECT="agente_de_pesquisa_scrapeless"

Com essas três variáveis de ambiente definidas, cada chamada de ferramenta, cada chamada de LLM e cada falha de parser aparece no LangSmith com tempo, custo e o prompt exato que o modelo viu. Para uma execução em produção, esta é a mudança de maior alavancagem única — transforma "o agente fez algo estranho" em uma trilha clicável.

Persistir em um armazenamento vetorial

python Copy
# embed.py
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document

docs = [Document(page_content=p.model_dump_json(), metadata={"url": str(p.url)})
        for p in products]
vs = Chroma.from_documents(docs, OpenAIEmbeddings(), persist_directory=".chroma")

O armazenamento vetorial é a quarta etapa opcional do pipeline. Ele compensa quando o agente é um serviço RAG de longa duração que responde a perguntas subsequentes sobre o conjunto de dados; é exagero para um script de pesquisa pontual. Escolha o armazenamento com base na preferência de operações — langchain_chroma para arquivos locais, langchain_postgres para um Postgres gerenciado + pgvector, langchain_pinecone para um banco de dados vetorial hospedado.


O que você recebe de volta

json Copy
[
  {
    "name": "Wacaco Nanopresso",
    "price": 79.95,
    "rating": 4.7,
    "review_count": 12483,
    "key_features": [
      "Operação manual com bomba de mão",
      "Até 18 barras de pressão de extração",
      "Compatível com café moído ou cápsulas NS via adaptador"
    ],
    "url": "https://example.com/p/wacaco-nanopresso"
  },
  {
    "name": "Flair NEO Flex",
    "price": 119.00,
    "rating": 4.5,
    "review_count": 2104,
    "key_features": [
      "Acionamento por alavanca, sem necessidade de eletricidade",
      "Pressão de nível de espresso com portafiltre sem fundo",
      "Desmontável para viagem"
    ],
    "url": "https://example.com/p/flair-neo-flex"
  },
  {
    "name": "Outin Nano",
    "price": 129.99,
    "rating": 4.6,
    "review_count": 5871,
    "key_features": [
      "Elemento de aquecimento embutido",
      "Ciclo de auto-limpeza",
      "Carregamento USB-C, aquecimento em ~3 minutos"
    ],
    "url": "https://example.com/p/outin-nano"
  }
]
// O esquema reflete exatamente o que o parser da Etapa 4 emite. Os valores dos campos são amostras ilustrativas.

Algumas observações honestas sobre o que esperar quando isso é executado na web ao vivo:

  • O tempo de hidratação varia por site. A ferramenta de raspagem universal aguarda domcontentloaded por padrão; para SPAs que hidratam preços por meio de um segundo XHR, a marcação pode chegar antes que o preço seja renderizado. Re-renderize uma vez com um breve atraso ou recue para response_type="html" e um seletor personalizado se o campo for consistentemente nulo.
  • Campos opcionais permanecem opcionais. Algumas páginas de produtos omitem avaliações explícitas ou contagens de revisão, especialmente em sites diretos ao consumidor. Trate valores null como informativos em vez de um modo de falha e filtre a jusante.
  • A extração de LLM domina a latência. No total, o pipeline leva aproximadamente 1–3 segundos para a chamada de busca, 2–4 segundos por renderização de página e 3–5 segundos por extração de LLM. A concorrência nas etapas de renderização e extração é a maior alavanca.
  • Interstitials anti-bot aparecem como ValueError. Quando um site carrega um desafio da Cloudflare ou Akamai que o navegador em nuvem não consegue completar de forma transparente, o wrapper langchain-scrapeless levanta ValueError em vez de retornar silenciosamente uma página de espaço reservado. O decorador de repetição captura os casos transitórios; os casos persistentes são melhor tratados alargando a impressão digital ou fixando uma região de proxy diferente.
  • A etapa do armazenamento vetorial é opcional. Para um pipeline de pesquisa que retorna registros tipados para um consumidor a jusante, pule totalmente. Adicione-o quando o mesmo conjunto de dados responder a várias perguntas a jusante ao longo do tempo.

FAQ

Preciso de um proxy residencial?
Sim, para qualquer site com proteção anti-bot significativa, que é a maioria dos varejistas, marketplaces e pontos finais de SERP. ScrapelessUniversalScrapingTool e as ferramentas de deep-SERP passam pelo pool de proxies residenciais do Scrapeless por padrão; o parâmetro gl na ferramenta de busca fixa o país de saída.

E quanto a erros transitórios como 400 ou 503?
As ferramentas langchain-scrapeless exibem erros de API transitórios como ValueError (o ScrapelessError subjacente é encapsulado antes de ser re-lançado). Para chamadas diretas, use o decorador tenacity da Etapa 6 com retry_if_exception_type=(ValueError, TimeoutError). Para chamadas impulsionadas por agentes dentro de create_agent, envolva cada ferramenta com a pilha de decoradores @tool + @retry da Etapa 5 — isso produz um verdadeiro StructuredTool que o agente aceita e aplica a política de re-tentativa em cada chamada de ferramenta. Sem um destes, um único 400 transitório quebra toda a execução do agente.

Um site retorna Acesso Negado. E agora?
Primeiro, tente novamente com o decorador da Etapa 6. Se a página bloquear persistentemente, amplie a sessão mudando gl para um país diferente ou adicione um breve await asyncio.sleep(...) entre as tentativas para deixar o estado da sessão esfriar. Para sites com bloqueios consistentes em nível de IP, entre em contato com o suporte do Scrapeless para confirmar se o bloqueio é a nível de plataforma e não a nível de conta.

Os seletores continuam quebrando. Como sobrevivo à rotação do DOM?
Use response_type="markdown" no ScrapelessUniversalScrapingTool em vez de analisar HTML com seletores CSS. Markdown colapsa o chrome de navegação e a maior parte da deriva de layout, então o extrator LLM na Etapa 4 vê uma representação estável do conteúdo mesmo quando o DOM subjacente muda.

Quantos trabalhadores concorrentes por host?
Três é o teto documentado para execuções estáveis. Limite ao nível do host (asyncio.Semaphore(3) na Etapa 6); trabalhadores em diferentes hosts podem ser executados independentemente.

Posso usar isso sem LangGraph?
Sim. ScrapelessUniversalScrapingTool().invoke({...}) é uma chamada simples — chame-a de qualquer script Python, rota FastAPI ou tarefa Celery. LangGraph adiciona o loop agêncial por cima, mas as ferramentas em si são agnósticas em relação ao framework.

Posso trocar OpenAI por Claude, Gemini ou um modelo local?
Sim. Substitua ChatOpenAI(model="gpt-4o-mini") por ChatAnthropic(model="claude-sonnet-4-6"), ChatGoogleGenerativeAI(model="gemini-2.5-pro"), ChatOllama(model="llama3.1"), ou qualquer outro modelo de chat LangChain. A lista tools, o prompt e o parser permanecem inalterados.

Como adiciono memória de múltiplas interações?
Passe um MemorySaver checkpointer para create_agent(llm, tools, checkpointer=MemorySaver()) e forneça um thread_id em cada invocação. LangGraph persiste o estado da conversa entre as interações, para que o agente possa se referir a buscas anteriores sem reexecutá-las.

Onde vejo os rastros das requisições?
Defina LANGCHAIN_TRACING_V2=true, LANGCHAIN_API_KEY e LANGCHAIN_PROJECT (Etapa 6). Cada chamada de ferramenta, chamada LLM e execução de parser aparece no LangSmith com tempos, custos e o prompt exato — a única mudança de observabilidade com maior impacto para uma implementação em produção.

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