Agentes LangChain que Veem a Web Ao Vivo: Construindo Pipelines de Dados AI com Scrapeless
Web Data Collection Specialist
Principais ConclusÔes:
- Integração de LangChain de primeira mão. O pacote
langchain-scrapelessno PyPI fornece cinco ferramentas prontas para uso âScrapelessDeepSerpGoogleSearchTool,ScrapelessDeepSerpGoogleTrendsTool,ScrapelessUniversalScrapingTool,ScrapelessCrawlerCrawlTooleScrapelessCrawlerScrapeToolâ 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
PydanticOutputParsere, opcionalmente, incorpore em um armazenamento vetorial para RAG a jusante. - O agente decide quando raspar. O
create_agentdo 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 deProduto/Artigo/ListaDeEmpregonos 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
Produtocom 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
ScrapelessDeepSerpGoogleSearchToolparametrizado porglehl. - Acompanhamento de tendĂȘncias de mercado. Extraia
interest_over_timee consultas relacionadas comScrapelessDeepSerpGoogleTrendsToolpara 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
ScrapelessCrawlerScrapeToole 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) esessionNameâ disponĂvel ao acessar diretamente o endpoint WSS; as chamadas da ferramentalangchain-scrapelessalocam uma nova sessĂŁo porinvoke, o que Ă© o padrĂŁo certo para um pipeline de pesquisa. - Integração de primeira parte com LangChain â
pip install langchain-scrapelessexpÔ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 comlangchain-anthropic,langchain-google-genai,langchain-ollamaou qualquer modelo de chat do LangChain trocando a linhaChatOpenAI. - Familiaridade bĂĄsica com
pipevenv.
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
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
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
# 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 Ă©:
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):
- Chame
ScrapelessDeepSerpGoogleSearchToolcomq="melhores mĂĄquinas de espresso portĂĄteis abaixo de 150",gl="us",hl="en",num=5para obter URLs de resultados orgĂąnicos. - Para os 3 principais URLs de resultado, chame
ScrapelessUniversalScrapingToolcomresponse_type="markdown"para renderizar cada pĂĄgina como markdown limpo. - Passe cada pĂĄgina renderizada ao LLM com um
PydanticOutputParservinculado a um esquemaProduct; rejeite qualquer pĂĄgina onde o parser nĂŁo consiga extrairnomeepreço. - Agregue os trĂȘs registros
Productem um array JSON e retorne.
O que vocĂȘ recebe de volta:
json
[
{
"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
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â 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
# 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
# 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
# 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
# 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
# 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
@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
# 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
# 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
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
# 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
[
{
"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
domcontentloadedpor 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 pararesponse_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
nullcomo 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 wrapperlangchain-scrapelesslevantaValueErrorem 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.



