Como obter resultados de busca do Google em JSON (sem parsing de HTML)

O Google serve markup ofuscado e rotativo. Aqui está o contrato JSON do /serp: campos garantidos, blocos opcionais, testado em agosto de 2026.

Existem duas formas de extrair dados de uma página de resultados do Google: fazer parsing do HTML, ou pedir o JSON que descreve a mesma página. Só uma delas sobrevive a uma atualização de markup.

Por que o parsing de HTML não se sustenta

Abra o view-source de uma página de resultados e procure um nome de classe em que você gostaria de basear um seletor CSS. Você não vai encontrar nada parecido com result-title. Vai encontrar algo como MjjYud ou g6HRUb, gerado por máquina, e diferente da string que você viu na semana passada. O front-end do Google é compilado e ofuscado a cada build, e a build muda.

Mesmo que você fixe um seletor em algo estável, como um padrão de href, o layout por baixo muda de acordo com o tipo de consulta. Uma consulta informativa simples renderiza de forma diferente de uma que ativa um knowledge panel, um local pack, ou um carrossel de compras. Você acaba escrevendo um parser para cada formato de consulta, e reescrevendo todos eles no próximo redesign do Google.

Nada disso é um problema específico do Google, aliás: o JavaScript frequentemente renderiza partes da página depois do carregamento, então um requests.get simples com uma passada de BeautifulSoup pode perder conteúdo que um navegador de verdade mostraria. Esse é um custo separado, coberto no nosso artigo sobre quando o scraping precisa de rendering JS.

Como é de fato uma resposta JSON

Envie a mesma consulta para uma API que devolve o resultado já processado em vez da página, e você recebe um conjunto fixo de chaves em vez de um DOM para percorrer:

import requests

API_KEY = "faf_live_..."  # sua chave FastAF

resp = requests.get(
    "https://api.fastaf.co/v1/serp",
    params={
        "query": "best noise cancelling headphones",
        "country": "us",
        "language": "en",
        "device": "mobile",
    },
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=60,
)
resp.raise_for_status()
data = resp.json()

for result in data["organic_results"]:
    print(result["rank"], result["title"], result["link"], result["snippet"][:60])

Os campos com os quais você pode contar

organic_results é a única parte da resposta em que você pode se basear sem ressalvas: é uma lista, e cada item traz rank, title, link e snippet. Esse é o contrato, independente da consulta.

Campo O que é
rank Posição na página, começando em 1
title O texto do link azul
link A URL de destino
snippet O texto de descrição abaixo do resultado

Todo o resto da resposta é condicional ao que a consulta realmente produz, do mesmo jeito que é condicional à página ao vivo. Blocos como people_also_ask, um knowledge panel, anúncios ou buscas relacionadas aparecem como chaves extras de primeiro nível quando o Google os renderiza para aquela consulta, e simplesmente estão ausentes quando não. Escreva código que verifica a presença da chave antes de lê-la (data.get("people_also_ask")), não código que assume que ela está sempre lá.

Os parâmetros que moldam a requisição

A lista completa de parâmetros está na documentação, mas estes são os que você vai usar em quase toda requisição:

  • q (alias query): o termo de busca.
  • country: país de duas letras de onde buscar, muda o domínio do Google e o conjunto de resultados que você recebe.
  • language (alias lang): idioma da interface e dos resultados.
  • device: mobile ou desktop. Rankings e layout diferem entre os dois, e mobile é a maioria do tráfego real na maioria dos setores, então busque os dois se a posição no ranking importa para você.
  • page: para profundidade além da primeira página.
  • location: um sinal geográfico mais preciso do que só country, útil para consultas com intenção local.
  • safe: SafeSearch ligado ou desligado.
  • tbs: o próprio parâmetro de data e filtro do Google, para buscas restritas por data.

Alternar device entre requisições é a forma mais barata de pegar uma diferença de ranking que uma configuração só de desktop perderia completamente:

for device in ["desktop", "mobile"]:
    r = requests.get(
        "https://api.fastaf.co/v1/serp",
        params={"query": "project management software", "country": "us", "device": device},
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=60,
    )
    top = r.json()["organic_results"][0]
    print(device, "->", top["rank"], top["link"])

Quanto custa

Uma requisição /serp custa 5 créditos, independente de quantos blocos a consulta produz. Rodamos uma requisição enquanto escrevíamos este post (agosto de 2026) e ela retornou 10 resultados orgânicos por esses 5 créditos. O Google não respeita mais num=100, então se você precisa dos 100 melhores resultados de uma keyword, planeje 10 requisições paginadas, não uma; o detalhamento do custo por 1.000 buscas mostra o que isso faz com a sua fatura.

Requisições que falham não são cobradas: os créditos são reservados quando a requisição começa e devolvidos se nada voltar.

Resumo

organic_results com rank, title, link e snippet é a parte do contrato com a qual você sempre pode contar. Todo o resto da resposta, people_also_ask incluído, está lá quando o Google renderiza e ausente quando não, então condicione seu código à chave, não à consulta. Referência completa na documentação, ou comece com o plano gratuito, 500 créditos, sem cartão.