🎯 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

ScrapeGraphAI + Scrapeless: Aponte o SmartScraperGraph para um Navegador em Nuvem

Emily Chen
Emily Chen

Advanced Data Extraction Specialist

07-Aug-2026

TL;DR:

  • ScrapeGraphAI extrai com um prompt em vez de seletores, mas a busca por trás é um navegador Playwright comum lançado na sua própria máquina.
  • pip install scrapegraphai fornece a você o cliente Playwright e nenhum binário de navegador, então o carregador padrão falha em uma instalação nova até que você também execute playwright install chromium.
  • ChromiumLoader escolhe seu método de busca com getattr(self, f"ascrape_{self.backend}"), então backend nomeia um método em vez de escolher a partir de uma lista fixa — esse é o ponto em que um backend de busca personalizado se integra.
  • Uma subclasse curta com um método ascrape_scrapeless busca através do Scrapeless Scraping Browser por uma conexão CDP wss:// e não precisa de um navegador instalado localmente.
  • FetchNode importa ChromiumLoader pelo nome, então reatribuir fetch_node.ChromiumLoader é o que faz o gráfico realmente usar sua subclasse. Pule isso e um carregador que parece correto será ignorado silenciosamente.
  • Todo o pipeline roda em um modelo local: SmartScraperGraph com ollama/qwen2.5:0.5b retornando pares estruturados de autor e citação sem chave de modelo em nuvem.
  • Comece no plano gratuito Scrapeless e transfira a busca do seu laptop.

O Scrapeless Scraping Browser é um navegador em nuvem ao qual você se conecta em vez de lançar. Ele escuta em um ponto de extremidade CDP WebSocket seguro, o que é importante aqui porque a camada de busca do ScrapeGraphAI é Playwright por trás e o Playwright pode se conectar a um navegador que não iniciou.

ScrapeGraphAI é a parte do pipeline de que as pessoas falam: descreva o que você quer em uma frase, e um gráfico de nós transforma uma página em JSON estruturado sem um único seletor CSS. A parte que ninguém menciona é o primeiro nó. Antes que qualquer modelo veja algo, FetchNode precisa produzir HTML, e faz isso lançando o Chromium na máquina em que o script está sendo executado. Todo tutorial na primeira página dos resultados da busca configura esse nó exatamente de uma maneira, com um dicionário de proxy, e para por aí.

Este guia aborda a camada de busca: onde ela vive, qual é o verdadeiro ponto de extensão e como encaminhá-la através de um navegador em nuvem. Cada bloco abaixo foi executado ao vivo, incluindo a extração.

Onde a Camada de Busca do ScrapeGraphAI Realmente Vive

FetchNode é o nó de entrada de quase todo gráfico, e termina em um de poucos ramos. Se você definir browser_base, scrape_do ou plasmate na configuração do nó, ele passa para um carregador de fornecedor em scrapegraphai/docloaders/. Caso contrário, cai para ChromiumLoader, que é o caminho padrão e o que quase todos usam.

Essa queda é importante por duas razões. Os backends de busca do fornecedor já são uma forma estabelecida nesta base de código, em vez de algo que você esteja inventando — browser_base.py e scrape_do.py são enviados no repositório. E ChromiumLoader escolhe seu próprio método de busca pelo nome:

python Copy
scraping_fn = getattr(self, f"ascrape_{self.backend}")

backend não é validado contra uma enumeração fixa. É interpolação de string em uma busca de atributo, então qualquer método chamado ascrape_<something> se torna acessível definindo backend para <something>. Esse é o ponto de junção.

O ascrape_playwright padrão chama p.chromium.launch(...), que inicia um processo de navegador localmente. Trocar isso por uma conexão WebSocket para um navegador já em execução é uma mudança de uma chamada.

Pré-requisitos

  • Python 3.10 ou posterior.
  • Uma chave API Scrapeless do painel, exportada como SCRAPELESS_KEY.
  • Ollama executando localmente com um modelo baixado, se você quiser seguir o passo de extração sem uma chave de modelo em nuvem.
  • Nenhum binário de navegador local é necessário para o caminho em nuvem. Você só precisa de um se também quiser executar o carregador padrão.

Instalar

bash Copy
pip install "scrapegraphai==2.1.6" "langchain-ollama==1.1.0"

O Playwright chega como uma dependência, mas seus navegadores não. Essa distinção causa a primeira falha que a maioria das pessoas encontra.

bash Copy
export SCRAPELESS_KEY="your_api_key_here"

O que uma Instalação Nova Realmente Busca

Execute o carregador padrão imediatamente após a instalação e ele não alcança a página de jeito nenhum.

python Copy
from scrapegraphai.docloaders import ChromiumLoader

try:
    docs = ChromiumLoader(["https://quotes.toscrape.com/"], headless=True).load()
    print("chars:", len(docs[0].page_content))
except Exception as exc:
    print(f"{type(exc).__name__}: {str(exc).split(' at /')[0]}")
text Copy
RuntimeError: Failed to scrape after 1 attempts: BrowserType.launch: Executable doesn't exist

O cliente Playwright está instalado; o Chromium que ele deseja lançar não está. playwright install chromium corrige isso e custa algumas centenas de megabytes em cada máquina que executa o gráfico — uma imagem CI, um container, cada laptop de desenvolvedor. O caminho em nuvem ignora isso completamente, porque o navegador que ele controla já está em execução em outro lugar.

Subclasse ChromiumLoader, adicione um método nomeado para o backend que você deseja e reatribua self.backend após super().__init__ ser executado.

python Copy
import os

from scrapegraphai.docloaders import ChromiumLoader

CDP = (
    "wss://browser.scrapeless.com/api/v2/browser"
    f"?token={os.environ['SCRAPELESS_KEY']}&sessionTTL=180&proxyCountry=ANY"
)


class ScrapelessLoader(ChromiumLoader):
    """Fetch through a remote CDP browser instead of launching one locally."""

    def __init__(self, urls, **kwargs):
        kwargs.pop("backend", None)
        super().__init__(urls, backend="playwright", **kwargs)
        self.backend = "scrapeless"

    async def ascrape_scrapeless(self, url: str, browser_name: str = "chromium") -> str:
        from playwright.async_api import async_playwright

        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(CDP)
            page = await browser.new_page()
            await page.goto(url, wait_until=self.load_state)
            html = await page.content()
            await browser.close()
            return html


loader = ScrapelessLoader(["https://quotes.toscrape.com/"])
print("dispatches to:", getattr(loader, f"ascrape_{loader.backend}").__name__)
docs = loader.load()
print("chars:", len(docs[0].page_content))
print("Einstein present:", "Einstein" in docs[0].page_content)

Dois detalhes fazem o trabalho. super().__init__ é chamado com backend="playwright" porque o construtor executa uma verificação de importação contra essa string, e playwright é o nome que se resolve; self.backend é então reassigned para que a dispatch em lazy_load encontre ascrape_scrapeless. Mantenha browser_name na assinatura com um padrão — o dispatcher chama o método apenas com a URL.

text Copy
dispatches to: ascrape_scrapeless
chars: 10968
Einstein present: True

A página volta totalmente renderizada de um navegador que nunca existiu nesta máquina. proxyCountry aceita um código de duas letras quando você precisa que a solicitação saia de um país específico, e sessionTTL limita quanto tempo a sessão remota permanece aberta.

Faça o Gráfico Usar Isso

Instanciar a subclasse você mesmo prova que a busca funciona, mas o gráfico não irá capturá-la por conta própria. FetchNode faz from ..docloaders import ChromiumLoader e então chama esse nome diretamente, então a classe que o gráfico usa é a que está vinculada no espaço de nomes do módulo do nó. Revincule antes de construir o gráfico.

python Copy
import scrapegraphai.nodes.fetch_node as fetch_node

fetch_node.ChromiumLoader = ScrapelessLoader

Este é o passo que decide se algum dos itens acima tem um efeito. Uma subclasse que é escrita corretamente, mas nunca vinculada, produz um gráfico que roda, tem sucesso e busca discretamente através do navegador local o tempo todo.

Porque a substituição mantém a mesma assinatura do construtor, tudo que FetchNode já passa — headless, storage_state, e qualquer coisa que você colocar em loader_kwargs — continua a chegar intacto.

Pronto para mover a busca para fora das suas próprias máquinas? Crie uma conta gratuita no Scrapeless e aponte seu primeiro gráfico para isso.

Execute o Gráfico Todo em um Modelo Local

Com o carregador vinculado, SmartScraperGraph se comporta normalmente. Pontuar o bloco llm em Ollama mantém todo o pipeline longe de APIs pagas, o que torna a camada de busca barata para iterar.

python Copy
import os

import scrapegraphai.nodes.fetch_node as fetch_node
from scrapegraphai.docloaders import ChromiumLoader
from scrapegraphai.graphs import SmartScraperGraph

CDP = (
    "wss://browser.scrapeless.com/api/v2/browser"
    f"?token={os.environ['SCRAPELESS_KEY']}&sessionTTL=180&proxyCountry=ANY"
)


class ScrapelessLoader(ChromiumLoader):
    def __init__(self, urls, **kwargs):
        kwargs.pop("backend", None)
        super().__init__(urls, backend="playwright", **kwargs)
        self.backend = "scrapeless"

    async def ascrape_scrapeless(self, url: str, browser_name: str = "chromium") -> str:
        from playwright.async_api import async_playwright

        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(CDP)
            page = await browser.new_page()
            await page.goto(url, wait_until=self.load_state)
            html = await page.content()
            await browser.close()
            return html


fetch_node.ChromiumLoader = ScrapelessLoader

graph = SmartScraperGraph(
    prompt="List the quote authors on this page.",
    source="https://quotes.toscrape.com/",
    config={
        "llm": {
            "model": "ollama/qwen2.5:0.5b",
            "temperature": 0,
            "format": "json",
            "model_tokens": 4096,
        },
        "verbose": False,
        "headless": True,
    },
)
result = graph.run()
print("keys:", sorted(result))
print("authors:", [item["author"] for item in result["content"]][:4])
text Copy
keys: ['content']
authors: ['Albert Einstein', 'J.K. Rowling', 'Jane Austen', 'Marilyn Monroe']

Os autores retornam corretos e a estrutura está certa. O texto de citação deste modelo é menos confiável — um modelo de parâmetro 0.5B corta e mescla strings em uma longa lista — mas a camada de busca entregou a página inteira, e o modelo é o fator limitante, em vez do pipeline. Mova a chave model para um modelo local maior ou para um hospedado e o mesmo gráfico produz texto mais limpo através do mesmo carregador.

A saída estruturada é o objetivo aqui: o gráfico lê o documento HTML analisado que o navegador remoto renderizou, e não a marcação bruta que um cliente HTTP simples teria recebido. Definir format para json pede ao modelo uma saída que esteja em conformidade com o formato de intercâmbio JSON, que é o que torna o resultado diretamente subscritível em vez de uma string que você precisa analisar.

Conclusão

A camada de busca do ScrapeGraphAI é mais configurável do que os tutoriais sugerem, e o ponto de configuração não é loader_kwargs — é a string backend, que se resolve em um nome de método. Uma subclasse com um método ascrape_scrapeless move a busca para um navegador na nuvem, e um rebinding de fetch_node.ChromiumLoader faz o gráfico usá-lo.

Verifique o rebinding primeiro se os resultados parecem inalterados. Uma subclasse que nunca é vinculada falha silenciosamente em vez de alto, e o sintoma é um gráfico que funciona exatamente tão bem quanto antes. Confirmar o carregador por conta própria, como no passo médio acima, separa um problema de busca de um problema de modelo em uma execução.

Para onde o controle do navegador está se dirigindo como um padrão, a especificação WebDriver BiDi vale a pena acompanhar. O guia do Playwright e do Scraping Browser cobre a conexão em mais profundidade, detalhes do plano estão na página de preços do Scrapeless, e parâmetros de sessão estão na documentação do Scrapeless.

FAQ

Q: Eu preciso instalar um navegador para usar o caminho da nuvem?

Não. pip install scrapegraphai fornece o cliente Playwright, que é tudo que connect_over_cdp precisa, porque o navegador que está sendo acionado já está rodando remotamente. Você só precisa de playwright install chromium se também quiser executar o carregador local padrão.

Q: Por que meu carregador personalizado está sendo ignorado pelo gráfico?
Quase sempre porque fetch_node.ChromiumLoader nunca foi reatado. FetchNode importa a classe pelo nome e chama esse nome, portanto, apenas subclassear não muda nada — o nó continua construindo a classe original. Reate o atributo no módulo antes de construir o gráfico.

Q: Posso usar loader_kwargs em vez de uma subclasse?

Para proxies e opções de execução do navegador, sim — loader_kwargs flui diretamente para ChromiumLoader. No entanto, não pode redirecionar a busca para um navegador remoto, pois o método padrão chama chromium.launch(), que sempre inicia um processo local. Mudar o destino significa mudar o método, o que significa uma subclasse.

Q: Isso funciona com gráficos além do SmartScraperGraph?

Sim. O reatamento ocorre no nível do nó, e FetchNode é o nó de entrada para os outros tipos de gráfico também, portanto, qualquer gráfico que busque uma URL passa pelo mesmo carregador uma vez que o atributo esteja vinculado.

Q: O que controla sessionTTL?

Quanto tempo a sessão do navegador remoto permanece aberta, em segundos. Defina-o confortavelmente acima do tempo que uma única busca leva; a sessão fecha quando a conexão termina ou a janela expira, o que ocorrer primeiro.

Q: Posso manter cookies ou uma sessão logada entre as buscas?

storage_state já é passado por FetchNode e atinge o construtor da subclasse inalterado, portanto, o arquivo de estado de armazenamento padrão do Playwright funciona. Aplique-o ao criar o contexto no navegador remoto em vez de na execução, já que o navegador remoto não é iniciado pelo seu código.

Q: Um modelo local de 0,5B é bom o suficiente para extração real?

Para páginas curtas com uma forma simples, produz uma estrutura utilizável, como acima. Páginas mais longas e esquemas aninhados são onde ele degrada — o texto é cortado e os campos são mesclados. Trate um pequeno modelo local como uma maneira de iterar na camada de busca de forma barata, depois troque a chave model para execuções 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