Saltar para o conteúdo
Comece grátis
Voltar ao blogue

Guia da API de extração de resultados de pesquisa (SERP): Google, Bing, DuckDuckGo, Yandex

Suciu DanÚltima atualização em 25 min read
Guia da API de extração de resultados de pesquisa (SERP): Google, Bing, DuckDuckGo, Yandex
Resumo: Para utilizar a SERP Scraping API, envie um pedido GET para https://serpapi.webscrapingapi.com/v2 com api_key, engine e a sua consulta (q para a maioria dos motores, text para o Yandex). O Google e o Bing devolvem JSON já analisado, enquanto o DuckDuckGo e o Yandex devolvem o HTML da página de resultados para o seu código extrair, por isso planeie a análise e os testes em função disso. Este guia aborda também localização, tarefas assíncronas, erros e preços.

Precisas de resultados de pesquisa para um conjunto de palavras-chave, em países e idiomas específicos, em dispositivos específicos, como dados que o teu código possa armazenar e comparar semana a semana. Utilizar o teu próprio scraper de pesquisa implica lidar com bloqueios e reescrever analisadores sempre que uma página de resultados muda; por isso, este guia utiliza, em vez disso, a API SERP da WebScrapingAPI. No final, irá enviar um primeiro pedido com a sua chave numa variável de ambiente, escolher o motor certo, definir o mercado que está a medir, analisar o JSON do Google e do Bing de forma defensiva, extrair o HTML do DuckDuckGo e do Yandex por conta própria, executar pesquisas no Google de forma assíncrona, repetir tentativas de acordo com o contrato de erros documentado e dimensionar um plano.

Início rápido

  • Ponto de extremidade: https://serpapi.webscrapingapi.com/v2 (GET)
  • Obrigatório: api_key, engine, e a consulta (q para a maioria dos motores de busca, text para o Yandex)
  • Resultado: O Google e o Bing devolvem JSON analisado. O DuckDuckGo e o Yandex devolvem o HTML da página de resultados dentro de um invólucro JSON
  • Teste gratuito: 100 pesquisas no Google

O que é a API de extração de SERP e o que é que ela devolve?

A API SERP da WebScrapingAPI é um ponto de extremidade do lado do servidor que recebe uma consulta de pesquisa, um motor de busca e o contexto de mercado, devolvendo depois a página de resultados como dados. O Google e o Bing devolvem coleções JSON analisadas. O DuckDuckGo e o Yandex devolvem um invólucro JSON cujo search_results contém o HTML da SERP para que o seu código o extraia.

Essa divisão é o aspeto mais importante a compreender antes de escrever qualquer código. Com o Google e o Bing, lê-se coleções nomeadas, tais como organic[] e related[]. Com o DuckDuckGo e o Yandex, recebe-se a página em bruto e decide-se o que extrair dela. O seu modelo de armazenamento, os seus testes e o seu trabalho de manutenção dependem todos do lado em que cada motor de pesquisa se situa nessa linha divisória.

A API abrange quatro famílias de motores de busca: Google, Bing, DuckDuckGo e Yandex. O Google também dispõe de sete motores especializados para além da pesquisa padrão: pesquisa assíncrona, Maps, Avaliações do Maps, Hotéis, Voos, Tendências e Pesquisa reversa de imagens. As equipas utilizam-nos para monitorizar classificações e funcionalidades da SERP, a presença de marcas e editores, os resultados de anúncios pagos e a pesquisa de mercado em diversos tópicos e editores.

  • A WebScrapingAPI opera: validação de pedidos e execução dos motores de busca, a infraestrutura de acesso à pesquisa, coleções de resultados analisados onde estão documentados, entrega do envelope JSON para motores de busca HTML e manutenção do comportamento dos endpoints suportados.
  • A sua equipa é responsável por: grupos de consultas, mercados, idiomas e dispositivos, além de agendamento, novas tentativas ao nível da API, extração de envelopes HTML, armazenamento, cálculos de classificação, alertas e política de utilização e retenção de dados.

Há mais um aspeto importante para a análise. A API não define uma classificação universal. Cada resultado descreve uma consulta, num mercado, num dispositivo, num determinado momento; por isso, mantenha esse contexto associado a cada linha que armazenar. Está a comparar-na com outras APIs de tempo de pedido? Veja como a API SERP se enquadra ao lado das outras APIs de acesso à Web.

Como enviar a sua primeira solicitação à API SERP?

Crie uma conta, subscreva a API SERP no painel de controlo e copie a sua chave de API para uma variável de ambiente. Em seguida, envie uma solicitação GET para https://serpapi.webscrapingapi.com/v2 com api_key, engine=google, e q defina a sua palavra-chave. Deixe que a sua biblioteca HTTP codifique os parâmetros e mantenha a chave no servidor.

  1. Registe-se na WebScrapingAPI.
  2. Subscreva a API SERP no painel de controlo. O período de avaliação inclui 100 pesquisas no Google.
  3. Guarde a chave no seu shell ou gestor de segredos: export WSA_API_KEY=...
  4. Envie o pedido utilizando um dos trechos de código abaixo.

A solicitação tem o mesmo formato para todos os motores de busca. Apenas engine, o campo de consulta e os parâmetros de contexto é que mudam; assim, assim que esta chamada funcionar, qualquer outro motor será apenas uma questão de ajustar os parâmetros.

curl. Os --data-urlencode flags codificam cada valor e --max-time 120 definem um tempo limite explícito para o cliente:

# Google, parsed JSON, US English, mobile
EP="https://serpapi.webscrapingapi.com/v2"
curl --get --fail-with-body --max-time 120 "$EP" \
  --data-urlencode "api_key=$WSA_API_KEY" \
  --data-urlencode "engine=google" \
  --data-urlencode "q=running shoes" \
  --data-urlencode "gl=us" --data-urlencode "hl=en" --data-urlencode "device=mobile"

Python. Este pequeno cliente lê a chave do ambiente, passa todos os valores através do params argumento para que o Requests o codifique por si, tenta novamente de acordo com o contrato de erros e regista os cabeçalhos de utilização. As secções sobre o Bing e o tratamento de erros abaixo reutilizam-no.

"""Minimal WebScrapingAPI SERP API client: env-var key, jittered retries, usage headers.

Usage:
  export WSA_API_KEY=...                       # never hardcode the key
  python wsa_serp.py google "running shoes" gl=us hl=en device=mobile
  python wsa_serp.py bing "coffee roasters" mkt=en-US cc=us lang=en
  python wsa_serp.py yandex "pizza" lr=213 p=0
  python wsa_serp.py google "running shoes" gl=us --dry-run   # print the request, no call
"""
import os
import random
import sys
import time

import requests

ENDPOINT = "https://serpapi.webscrapingapi.com/v2"
# Most engines take their main input in q. These don't (see the engine table).
QUERY_FIELD = {"yandex": "text", "google_maps_reviews": "fid", "google_reverse_image": "url"}
RETRYABLE = {429, 500, 502, 503}   # back off with jitter, then retry
FINAL = {400, 401}                 # fix the key, plan, or parameters; never retry


def build_params(engine, query, **extra):
    params = {"engine": engine, QUERY_FIELD.get(engine, "q"): query}
    params.update({k: str(v) for k, v in extra.items()})
    return params


def search(engine, query, api_key, max_attempts=4, **extra):
    params = {"api_key": api_key, **build_params(engine, query, **extra)}
    for attempt in range(1, max_attempts + 1):
        resp = requests.get(ENDPOINT, params=params, timeout=120)
        usage = {k: v for k, v in resp.headers.items() if k.lower().startswith("searchdata-")}
        if resp.ok:
            return resp.json(), usage
        if resp.status_code in FINAL:
            # 401: missing, invalid, or unentitled key. 400: "Parameter '<name>' not allowed." etc.
            raise SystemExit(f"{resp.status_code}: {resp.text[:300]}")
        retry_422 = resp.status_code == 422 and attempt == 1   # target-side failure: one retry only
        if resp.status_code in RETRYABLE or retry_422:
            time.sleep(random.uniform(0, min(2 ** attempt, 30)))   # full jitter
            continue
        raise SystemExit(f"Unexpected {resp.status_code}: {resp.text[:300]}")
    raise SystemExit(f"Gave up after {max_attempts} attempts")


def organic(data):
    """Product pages document organic[]; some docs pages show organic_results[]. Accept both."""
    return data.get("organic") or data.get("organic_results") or []


def main():
    args = [a for a in sys.argv[1:] if a != "--dry-run"]
    if len(args) < 2:
        sys.exit(__doc__)
    engine, query = args[0], args[1]
    extra = dict(a.split("=", 1) for a in args[2:])

    if "--dry-run" in sys.argv:
        prepared = requests.Request(
            "GET", ENDPOINT, params={"api_key": "REDACTED", **build_params(engine, query, **extra)}
        ).prepare()
        print(prepared.url)
        return

    api_key = os.environ.get("WSA_API_KEY")
    if not api_key:
        sys.exit("Set WSA_API_KEY first (dashboard -> SERP API).")

    data, usage = search(engine, query, api_key, **extra)
    print("usage headers:", usage)
    if "search_results" in data:          # DuckDuckGo and Yandex: SERP HTML inside a JSON envelope
        print("search_parameters:", data.get("search_parameters"))
        print("html chars:", len(data["search_results"]))
    else:                                  # Google and Bing: parsed JSON
        for row in organic(data)[:10]:
            print(row.get("rank") or row.get("position"), row.get("title"), row.get("link"))


if __name__ == "__main__":
    main()

Execute python wsa_serp.py google "running shoes" gl=us hl=en device=mobile --dry-run primeiro. Imprime o URL exato da solicitação com a chave substituída por REDACTED, para que possa verificar os parâmetros antes de efetuar uma pesquisa.

Node.js (versão 18 ou posterior). O `URLSearchParams` trata da codificação e AbortSignal.timeout define o mesmo limite de 120 segundos:

// Build and (optionally) send a SERP API request in Node 18+.
// URLSearchParams handles encoding; the key comes from the environment.
const ENDPOINT = "https://serpapi.webscrapingapi.com/v2";
const QUERY_FIELD = { yandex: "text", google_maps_reviews: "fid", google_reverse_image: "url" };

export function buildSerpUrl(apiKey, engine, query, extra = {}) {
  const url = new URL(ENDPOINT);
  url.searchParams.set("api_key", apiKey);
  url.searchParams.set("engine", engine);
  url.searchParams.set(QUERY_FIELD[engine] ?? "q", query);
  for (const [k, v] of Object.entries(extra)) url.searchParams.set(k, String(v));
  return url;
}

export async function search(engine, query, extra = {}) {
  const apiKey = process.env.WSA_API_KEY;
  if (!apiKey) throw new Error("WSA_API_KEY is required");
  const res = await fetch(buildSerpUrl(apiKey, engine, query, extra), {
    signal: AbortSignal.timeout(120_000),
  });
  if (!res.ok) throw new Error(`SERP API ${res.status}: ${(await res.text()).slice(0, 300)}`);
  const data = await res.json();
  return { data, organic: data.organic ?? data.organic_results ?? [] };
}

// Dry run: show the encoded URL and prove the query survives the round trip.
if (process.argv[1]?.endsWith("build_serp_request.mjs")) {
  const q = 'site:example.com "running shoes" & socks?';
  const u = buildSerpUrl("REDACTED", "google", q, { gl: "us", hl: "en", device: "mobile" });
  console.log(u.toString());
  console.log("round trip ok:", new URL(u).searchParams.get("q") === q);
  const y = buildSerpUrl("REDACTED", "yandex", "pizza", { lr: 213, p: 0 });
  console.log(y.toString());
}

A simulação mostra porque é que a codificação é importante. A consulta site:example.com "running shoes" & socks? torna-se q=site%3Aexample.com+%22running+shoes%22+%26+socks%3F e é descodificada sem alterações (round trip ok: true). Se inserires essa consulta manualmente numa URL, o & termina o seu q e dá início a um novo parâmetro denominado socks?. O /v2 ponto de extremidade valida os parâmetros por motor e rejeita nomes que não reconhece, pelo que um URL criado manualmente falha de formas confusas. Deixa que a biblioteca aplique a codificação por por cento sempre.

Trate a chave como uma palavra-passe. Guarde-a em variáveis de ambiente do lado do servidor ou num gestor de segredos, e nunca a coloque no código do front-end, em repositórios públicos, registos ou capturas de ecrã. Qualquer pessoa com a chave pode esgotar as suas pesquisas.

Documentação: Aceder à API

Que motores de pesquisa e motores do Google pode consultar?

A referência atual da API lista onze motores: google, google_async, google_maps, google_maps_reviews, google_flights, google_hotels, google_trends, google_reverse_image, bing, duckduckgo, e yandex. Cada um tem os seus próprios parâmetros de entrada obrigatórios e permitidos. Considere apenas estes como suportados, mesmo que páginas de documentação mais antigas descrevam outros motores do Google.

Mecanismo

Entrada obrigatória

O que obtém em resposta

Preços

google

q

JSON analisado (general, input, navigation[], organic[], módulos opcionais)

Planos do Google

google_async

q

response_id, e, em seguida, a carga útil final da SERP

Planos do Google

google_maps

type=search + q, ou type=place + data

Resultados de locais analisados

Planos do Google

google_maps_reviews

fid

Avaliações analisadas

Planos do Google

google_hotels

type=search + q, ou type=place + pid; datas de chegada e partida

overview, organic[]

Planos do Google

google_flights

q (token codificado do Google Flights)

search_parameters, search_results[]

Planos do Google

google_trends

q

widgets[] (TIMESERIES, GEO_MAP)

Planos do Google

google_reverse_image

url

general, images[], exact_matches[]

Planos do Google

bing

q

JSON analisado (general, organic[], related[])

Citação

duckduckgo

q

Envelope JSON: search_parameters + search_results (HTML)

Citação

yandex

text

Envelope JSON: search_parameters + search_results (HTML)

Citação

Três motores não recebem a sua entrada principal em q. O Yandex recebe a consulta em text, o Google Maps Reviews recebe a fid, e o Google Reverse Image aceita uma imagem url. Os clientes Python e Node acima já mapeiam esses campos por si. O Google Maps e o Google Hotels também precisam de type=search ou type=place, o que altera o outro campo obrigatório.

«Planos do Google» refere-se aos planos mensais publicados do Google abordados na secção de preços. O Bing, o DuckDuckGo e o Yandex têm preços definidos por orçamento.

Poderá encontrar páginas de documentação para outros motores do Google, tais como autocompletar, eventos, finanças, empregos, serviços locais, fotos do Maps, Play, produtos e Scholar. Estes não constam da lista de serviços suportados, pelo que não deve criar um pipeline com base neles.

Documentação: Referência das APIs SearchData e SERP

Como localizar os resultados do Google por país, idioma e dispositivo?

Defina gl para o código de duas letras do país, hl para o idioma da interface e device em desktop, mobile, ou tablet. Adicione domain para um host específico do Google e uule para uma localização codificada quando o contexto ao nível da cidade for relevante. Guarde estes valores com cada resultado, porque a mesma pesquisa pode ter uma classificação diferente em cada mercado.

O próprio Google afirma que os resultados dependem do local de onde se faz a pesquisa, pelo que uma classificação sem indicar o mercado em questão é apenas metade da informação. Esta pesquisa canadiana, em inglês e no computador, pelo termo «história» no google.ca é executada através do cliente Python, conforme descrito na secção «primeira solicitação»:

python wsa_serp.py google history gl=ca hl=en domain=google.ca device=desktop

Se precisar de uma cidade específica, como London, Ontário, adicione o seu uule valor como mais um uule=... argumento. Utilize apenas os parâmetros documentados pelo seu motor de pesquisa. Exemplos mais antigos que ordenam por data ou filtram por período de tempo não se aplicam ao /v2 Pesquisa do Google, e o endpoint rejeita os parâmetros que não permite.

O tipo de resultados e a paginação também alteram o que obtém:

  • Exibe: tbm altera o tipo de resultados: isch para imagens, vid para vídeos, nws para notícias e shop para compras. Para resultados do Google Jobs, utilize ibp=htl;jobs.
  • Paginação: start define quantos resultados ignorar e num define quantos resultados devem ser apresentados por página.

O hábito mais útil aqui é o planeamento do mercado. Antes de recolher quaisquer dados, escolha uma grelha pequena e fixa de consulta × país × idioma × dispositivo e não a altere entre as execuções. Se a execução de uma semana utilizar gl=us&device=mobile e a seguinte utilizar gl=us&device=desktop, uma «queda na classificação» pode ser apenas uma mudança de dispositivo. Cada resposta é uma observação de um mercado, não uma verdade universal, pelo que as comparações só fazem sentido dentro da mesma célula da grelha.

A lista completa de campos de pedido e blocos de resposta encontra-se na página de controlos da API de Pesquisa do Google.

Motor

Localização / mercado

Idioma

Dispositivo

Paginação / hora

Filtros e superfícies

Google

gl (país), domain (servidor do Google), uule (localização codificada)

hl

device = computador, telemóvel, tablet

start (ignorar), num (por página)

tbm = isch, vid, nws, shop; ibp=htl;jobs

Bing

mkt (por exemplo, en-US), cc, location, lat, lon

lang

—

first (desvio), count

safesearch = desativado, moderado, rigoroso

DuckDuckGo

kl (por exemplo, en_US)

kad (interface)

device

df = d, w, m, y

kp = 1, -1, -2

Yandex

lr (ID da região, por exemplo, 213), yandex_domain

lang

device

p (com base em zero), within = 77 (24 h), 1 (2 semanas)

—

Documentação: Parâmetros da API de Pesquisa do Google

Como se lêem e armazenam os resultados analisados do Google e do Bing?

Leia a matriz «organic» para obter os resultados classificados, cada um com um título, link, link de exibição, descrição e classificação. Trate todos os outros módulos, tais como pesquisas relacionadas, navegação, anúncios ou resultados locais, como opcionais. Armazene cada linha com a consulta, o mercado, o dispositivo e a hora de captura, para que as comparações de classificação posteriores continuem a fazer sentido.

Uma resposta do Google contém alguns blocos de nível superior. general descreve o pedido (motor de busca, idioma, localização, indicador de dispositivo móvel e tipo de pesquisa), input contém o URL de pesquisa original, navigation[] enumera outras superfícies do Google para a consulta e organic[] contém os resultados classificados. Uma resposta do Bing contém general, organic[]e related[].

Tudo o resto é condicional. Anúncios, resultados locais, compras, multimédia e pesquisas relacionadas só aparecem quando a página de resultados os apresenta, e os recursos da SERP que o Google mostra variam consoante a consulta, a localização e o dispositivo. Por isso, distingue dois casos no teu código: um pedido que falhou (um erro HTTP) e um pedido que foi bem-sucedido, mas com um módulo ausente. O segundo é uma observação normal, não um bug.

Escreva o analisador de forma defensiva. Algumas páginas de documentação mostram a lista ordenada como organic_results[] com position em vez de organic[] com rank, por isso leia qualquer uma das duas. Este script transforma uma resposta em linhas de classificação. O ficheiro de entrada é uma amostra rotulada, não uma saída real:

"""Flatten a Google or Bing SERP API response into rank rows.

Organic results may arrive as organic[] (product pages) or organic_results[] (some docs pages),
and modules such as related[] or navigation[] are optional, so read them defensively.
"""
import json
import sys
from datetime import datetime, timezone


def rank_rows(data, query, market):
    rows = []
    captured = datetime.now(timezone.utc).isoformat(timespec="seconds")
    for item in data.get("organic") or data.get("organic_results") or []:
        rows.append({
            "captured_at": captured,
            "engine": data.get("general", {}).get("search_engine"),
            "query": query,
            "market": market,
            "rank": item.get("rank") or item.get("position"),
            "title": item.get("title"),
            "link": item.get("link"),
        })
    return rows


if __name__ == "__main__":
    data = json.load(open(sys.argv[1] if len(sys.argv) > 1 else "sample_google.json"))
    for row in rank_rows(data, "running shoes", "us/en/mobile"):
        print(row)
    print("optional modules present:", [k for k in ("navigation", "related", "related_questions") if k in data])

No ficheiro de amostra, imprime uma linha por resultado orgânico e lista quais os módulos opcionais que estavam presentes:

{'captured_at': '2026-10-29T12:03:56+00:00', 'engine': 'google', 'query': 'running shoes', 'market': 'us/en/mobile', 'rank': 1, 'title': 'Example result one', 'link': 'https://example.com/a'}
{'captured_at': '2026-10-29T12:03:56+00:00', 'engine': 'google', 'query': 'running shoes', 'market': 'us/en/mobile', 'rank': 2, 'title': 'Example result two', 'link': 'https://example.org/b'}
optional modules present: ['navigation']

Uma linha de classificação deve conter, no mínimo, captured_at: motor de busca, consulta, mercado, dispositivo, classificação, título e link. Com esses campos, pode comparar execuções, traçar gráficos de evolução e alertar sobre quedas. Esse é o cerne da monitorização das classificações e das características da SERP ao longo do tempo. Se os seus links armazenados incluírem redirecionamentos do Google, leia sobre os links de redirecionamento «Google /goto» nos URLs dos resultados antes de deduplicar por URL.

Como se faz uma pesquisa no Bing com a API da SERP?

Defina engine=bing e passe a consulta em q. Controle o mercado com mkt, como en-US, além de cc para o país e lang para o idioma. Adicione location, ou lat e lon, para uma origem precisa, safesearch para filtrar, e first com count para percorrer os resultados. As respostas do Bing chegam como JSON analisado.

A versão curl para o mercado dos EUA, primeira página de 10 resultados:

curl --get --fail-with-body --max-time 120 "https://serpapi.webscrapingapi.com/v2" \
  --data-urlencode "api_key=$WSA_API_KEY" \
  --data-urlencode "engine=bing" \
  --data-urlencode "q=coffee roasters" \
  --data-urlencode "mkt=en-US" --data-urlencode "cc=us" --data-urlencode "lang=en" \
  --data-urlencode "first=0" --data-urlencode "count=10"

Com o cliente Python da secção «primeira solicitação», a mesma chamada cabe numa única linha:

python wsa_serp.py bing "coffee roasters" mkt=en-US cc=us lang=en first=0 count=10

O Bing devolve general, organic[], e related[]. Anúncios e imagens são módulos opcionais, pelo que se aplicam as mesmas regras de segurança: leia organic[], trate tudo o resto como presente ou ausente e armazene cada linha com o seu mercado. safesearch aceita off, moderate, ou strict.

Mantenha mkt, cc, e lang consistente entre execuções, tal como faria com o gl e hl. O Bing tem preços definidos por cotação, e a versão de avaliação de 100 pesquisas abrange o Google. Os campos de pedido e os blocos de resposta encontram-se na página da API de Pesquisa do Bing.

Documentação: Pedidos básicos da API do Bing

Como se lida com os resultados HTML do DuckDuckGo e do Yandex?

Ambos os motores devolvem JSON com search_parameters, que descreve a solicitação, e search_results, uma cadeia de caracteres que contém o HTML da SERP de origem. A WebScrapingAPI não analisa esse HTML, pelo que a sua aplicação extrai os campos de que necessita. Associe os seus seletores a uma captura real, atribua-lhes versões, armazene o envelope bruto e avise quando um seletor deixar de corresponder.


Google, Bing

DuckDuckGo, Yandex

Resposta

Metadados JSON + coleções analisadas

Metadados JSON + código HTML da SERP de origem em search_results

Análise efetuada pela

WebScrapingAPI, onde está documentado

A sua aplicação

O seu código faz

Lê coleções de forma defensiva; armazena linhas

Selecione e utilize seletores de versão; extraia; alerte em caso de desvio

Armazenar

Linhas + contexto da solicitação

Envelope bruto + linhas extraídas + versão do seletor

Campos de pedido do DuckDuckGo: q para a consulta, kl para a região e o idioma (por exemplo, en_US), kad para o idioma da interface, kp para a pesquisa segura (1 ativada, -1 moderada, -2 desativada), df para a hora (d, w, m, y) e device.

campos de solicitação do Yandex: text para a consulta, lr para o ID da região (por exemplo, 213), lang, device, yandex_domain, p para a página (contagem a partir de zero, pelo que p=0 é a primeira página) e within para a hora (77 nas últimas 24 horas, 1 nas últimas duas semanas).

# DuckDuckGo, SERP HTML in a JSON envelope
curl --get --fail-with-body --max-time 120 "https://serpapi.webscrapingapi.com/v2" \
  --data-urlencode "api_key=$WSA_API_KEY" \
  --data-urlencode "engine=duckduckgo" \
  --data-urlencode "q=privacy research" \
  --data-urlencode "kl=en_US" --data-urlencode "df=w"

# Yandex, SERP HTML in a JSON envelope (query parameter: text)
curl --get --fail-with-body --max-time 120 "https://serpapi.webscrapingapi.com/v2" \
  --data-urlencode "api_key=$WSA_API_KEY" \
  --data-urlencode "engine=yandex" \
  --data-urlencode "text=pizza" \
  --data-urlencode "lr=213" --data-urlencode "p=0"

O padrão de extração é o mesmo para ambos os motores: validar o envelope, analisar o HTML, selecionar os links de resultados, ignorar os links de navegação próprios do motor, marcar cada linha com uma versão do seletor, sinalizar claramente quando não houver correspondência e guardar o HTML bruto para que possa ser reprocessado mais tarde. Este script utiliza o Beautiful Soup com seletores CSS:

"""Pull result links out of a DuckDuckGo or Yandex SERP API envelope.

These engines return {"search_parameters": {...}, "search_results": "<html>...</html>"}.
Your application owns extraction: pin the selector after inspecting a real capture,
version it, and alert when it stops matching. The selectors below fit the synthetic
fixtures only.
"""
import json
import sys
from urllib.parse import urlparse

from bs4 import BeautifulSoup

SELECTORS = {"duckduckgo": "div.result a.result-link", "yandex": "li.serp-item a.link"}
ENGINE_HOSTS = ("duckduckgo.com", "yandex.com", "yandex.ru")


def extract(envelope, selector_version="fixture-v1"):
    params = envelope.get("search_parameters", {})
    engine = params.get("search_engine")
    html = envelope.get("search_results")
    if not isinstance(html, str) or "<html" not in html.lower():
        raise ValueError("search_results is missing or is not HTML; store the raw envelope and alert")
    soup = BeautifulSoup(html, "html.parser")
    rows = []
    for pos, a in enumerate(soup.select(SELECTORS[engine]), start=1):
        host = urlparse(a.get("href", "")).hostname or ""
        if host.endswith(ENGINE_HOSTS):
            continue  # skip the engine's own navigation links
        rows.append({"engine": engine, "query": params.get("query"), "position": pos,
                     "title": a.get_text(strip=True), "link": a["href"],
                     "selector_version": selector_version})
    if not rows:
        raise ValueError(f"selector matched nothing for {engine}; markup may have changed")
    return rows


if __name__ == "__main__":
    for path in sys.argv[1:] or ["sample_ddg_envelope.json", "sample_yandex_envelope.json"]:
        for row in extract(json.load(open(path))):
            print(row)

Os seletores em SELECTORS se aplicam apenas aos ficheiros de amostra sintéticos. A marcação real do DuckDuckGo e do Yandex é diferente e está sujeita a alterações. Antes de executar isto em produção, guarde um envelope real, inspecione o seu HTML, defina os seus próprios seletores e atualize selector_version sempre que os alterar. Quando a marcação mudar, o ValueError é acionado, em vez de o seu pipeline armazenar silenciosamente zero resultados, e como guardou o HTML bruto, pode reextrair as execuções afetadas assim que os seletores forem corrigidos.

Os campos específicos de cada motor encontram-se nas páginas da API de Pesquisa do DuckDuckGo e da API de Pesquisa do Yandex.

Documentação: Parâmetros da API do DuckDuckGo · Parâmetros da API do Yandex

Utilize os motores especializados do Google quando a resposta se encontrar fora dos resultados normais da Web. O Google Maps localiza locais, o Maps Reviews apresenta as avaliações de um local por fid, o Trends apresenta widgets que mostram a evolução do interesse ao longo do tempo, o Hotels e o Flights apresentam resultados de viagens e o Reverse Image identifica uma imagem através do URL. Cada motor tem os seus próprios dados de entrada e parâmetros obrigatórios.

Todos utilizam o mesmo ponto final, chave e regras de codificação que a pesquisa padrão. Apenas o engine valor e os campos é que mudam:

  • google_maps: enviar type=search com q, ou type=place com data. ll=@lat,lon,zoom define a visualização do mapa, e place_type restringe a pesquisa a hotéis ou alojamentos para férias. Não há paginação documentada.
  • google_maps_reviews: envie o fid, que se obtém do knowledge.fid de uma resposta da Pesquisa do Google. Ordene com sort (qualityScore, newestFirst, ratingHigh, ratingLow) e a paginação com start e num.
  • google_trends: enviar q com geo, date (today 12-m, now 1-H, ou um YYYY-MM-DD YYYY-MM-DD intervalo), cat, e gprop (images, news, froogle, youtube). A resposta contém widgets[], tais como TIMESERIES e GEO_MAP.
  • google_hotels: enviar type=search com q, ou type=place com pid, mais check_in_date e check_out_date. Os filtros de ocupação, moeda e cancelamento gratuito são opcionais.
  • google_flights: q é um token de consulta codificado do Google Flights, não texto simples. Adicione curr, hl, e gl para a moeda e o mercado.
  • google_reverse_image: envie a imagem urle utilize lens (products, visual_matches, exact_matches, homework) para escolher o tipo de correspondência.

Se estiver a decidir entre a pesquisa reversa de imagens e tbm=isch resultados de imagens, consulte a comparação das APIs de pesquisa de imagens do Google.

Documentação: Motores de pesquisa do Google

Como é que se executam pesquisas no Google de forma assíncrona?

Envie a pesquisa com engine=google_async. A API coloca-a na fila e devolve um response_id imediatamente. Guarde esse ID com a sua tarefa e, em seguida, consulte o mesmo /v2 ponto final com snapshot_id definido para o ID e type=serp a cada 10 a 30 segundos até que a resposta SERP completa chegue. Limite o tempo total de espera.

O Async é adequado para grandes lotes e trabalhadores que não conseguem manter uma solicitação aberta durante 120 segundos. Aceita os campos habituais do Google, além de device e response=json. É exclusivo do Google: o Bing, o DuckDuckGo e o Yandex não dispõem de um motor assíncrono, pelo que não se deve conceber uma fila assíncrona partilhada à sua volta.

"""Submit a google_async job, then poll for the finished SERP payload.

Usage:
  export WSA_API_KEY=...
  python google_async.py "events in new york city"
  python google_async.py "events in new york city" --dry-run
"""
import os
import random
import sys
import time

import requests

ENDPOINT = "https://serpapi.webscrapingapi.com/v2"


def submit(api_key, query, **extra):
    r = requests.get(ENDPOINT, params={"api_key": api_key, "engine": "google_async", "q": query, **extra}, timeout=60)
    r.raise_for_status()
    return r.json()["response_id"]          # store this id with your job record


def poll(api_key, response_id, max_wait=600):
    deadline = time.monotonic() + max_wait
    while time.monotonic() < deadline:
        r = requests.get(ENDPOINT, params={"api_key": api_key, "snapshot_id": response_id, "type": "serp"}, timeout=60)
        if r.ok:
            body = r.json()
            if body.get("status") in (None, "finished"):
                return body                  # persist it; don't re-poll old ids later
        elif r.status_code not in (429, 500, 502, 503):
            raise SystemExit(f"{r.status_code}: {r.text[:300]}")
        time.sleep(random.uniform(10, 30))   # docs: poll every 10 to 30 seconds
    raise SystemExit(f"No result for {response_id} after {max_wait} s")


if __name__ == "__main__":
    query = sys.argv[1] if len(sys.argv) > 1 else "events in new york city"
    if "--dry-run" in sys.argv:
        for p in ({"api_key": "REDACTED", "engine": "google_async", "q": query},
                  {"api_key": "REDACTED", "snapshot_id": "<response_id>", "type": "serp"}):
            print(requests.Request("GET", ENDPOINT, params=p).prepare().url)
        sys.exit(0)
    key = os.environ.get("WSA_API_KEY") or sys.exit("Set WSA_API_KEY first.")
    rid = submit(key, query)
    print("response_id:", rid)
    print(str(poll(key, rid))[:500])

Guarde cada resultado concluído assim que chegar e não volte mais tarde para consultar novamente IDs antigas. O ciclo tem um prazo rígido e trata qualquer estado inesperado como uma paragem, pelo que uma tarefa bloqueada não pode manter um trabalhador ocupado para sempre.

Documentação: APIs assíncronas

Como deve o seu código lidar com erros e novas tentativas da API SERP?

Não repita tentativas em caso de erros 401 ou de validação. Corrija a chave, o plano ou os parâmetros. Refaça as tentativas para os códigos 429, 500, 502 e 503 algumas vezes com recuo exponencial e jitter, e diminua o ritmo no caso do 429. Um 422 significa que o motor de busca devolveu um erro, um tempo limite ou um desafio; por isso, tente novamente apenas uma vez, se a falha parecer transitória.

Estado

Significado

Ação

401

Sem chave, chave inválida ou chave sem autorização para a API SERP

Corrija a chave ou o plano. Não volte a tentar.

Erro de validação

Parâmetro desconhecido, em falta ou fora do intervalo para o motor selecionado

Corrija o pedido. Não tente novamente.

422 (error_type: "website")

O motor de pesquisa devolveu um corpo inválido, um desafio, um tempo limite esgotado ou um estado de erro

Tente novamente uma vez com intervalo de espera, se parecer transitório; depois, registe e ignore

429

Demasiadas solicitações simultâneas

Diminua o ritmo, aplique um backoff com jitter e tente novamente

500, 503

Erro inesperado do manipulador ou falha transitória do backend de autenticação

Reintente algumas vezes com intervalos de espera

502

O envio assíncrono recebeu uma resposta inválida

Refaça o envio com intervalo de espera

Os erros de autenticação são fáceis de reconhecer. Um pedido sem chave devolve um 401 com a mensagem «Acesso negado. Não foi fornecida nenhuma chave api_key fornecida.", e uma chave errada ou sem autorização devolve o código 401 com Authentication failure: Invalid API key…. Repetir qualquer uma das tentativas apenas repete a falha.

As mensagens de validação identificam o problema diretamente: Parameter '<name>' not allowed., Parameter '<name>' is required., Parameter '<name>' must be in range …, e Parameter '<a>' cannot be used with parameter '<b>'. É por isso que os parâmetros copiados de exemplos antigos falham em /v2: cada motor aceita apenas os seus próprios campos documentados.

Um erro 429 «Too Many Requests» significa que está a enviar demasiados pedidos de uma só vez. Reduza a sua concorrência e recue antes de tentar novamente. Para os códigos 500, 502 e 503, bastam algumas tentativas com recuo exponencial e jitter total, e os atrasos aleatórios impedem que um conjunto de trabalhadores tente novamente em sincronia. A search() função no cliente Python implementa toda esta política: interrompe-se no erro 401, tenta novamente os códigos que permitem repetição com intervalos aleatórios, tenta uma vez o erro 422 e desiste após quatro tentativas.

Registe dois cabeçalhos de resposta em cada chamada para acompanhamento de custos: Searchdata-Call-Credit-Usage (créditos utilizados por esta chamada) e Searchdata-Current-Credit-Usage (utilização atual da conta). O cliente devolve-os como usage. Registe o estado, os cabeçalhos e o contexto do pedido, mas nunca a chave.

Separe as falhas HTTP dos módulos vazios nas suas métricas. Uma resposta 200 sem related[] bloco é uma pesquisa bem-sucedida e não deve desencadear uma nova tentativa.

Documentação: Erros e cabeçalhos

Quanto custa a API SERP?

Os planos do Google são dimensionados com base no número de pesquisas mensais: o Starter custa 28 $ por 10 000, o Grow 130 $ por 50 000, o Business 550 $ por 250 000 e o Pro 1 600 $ por 1 000 000. A versão de avaliação inclui 100 pesquisas no Google por 0 $. O Bing, o DuckDuckGo e o Yandex têm preços definidos por orçamento, de acordo com a sua carga de trabalho, a partir de outubro de 2026.

Plano

Preço mensal

Pesquisas no Google

Custo efetivo por 1 000

Período de teste

0

100

—

Básico

28 $

10 000

2,80 $

Crescimento

130 $

50 000

2,60

Negócios

550 $

250 000

2,20

Profissional

1 600 $

1 000 000

1,60

Bing, DuckDuckGo, Yandex

Cotação

Com base na carga de trabalho

—

Os preços estão em USD, a partir de outubro de 2026. Todos os planos, incluindo o período de teste, incluem dados de produtos do Google, localizações globais, análise de SERP, processamento em massa, todos os dispositivos, saída em JSON, CSV e HTML, e pesquisa de imagens. Os planos diferem quanto ao limite mensal de pesquisas.

Para determinar o tamanho de um plano, multiplique os componentes da sua grelha de mercado:

Pesquisas mensais = palavras-chave × mercados × dispositivos × tipos de resultados × execuções de atualização por mês

Em seguida, acrescente uma margem para testes e para as palavras-chave que irá adicionar mais tarde. Por exemplo, 500 palavras-chave × 2 países × 2 dispositivos × 4 atualizações semanais = 8 000 pesquisas por mês, o que se enquadra no plano Starter com margem de manobra. Se passar o mesmo projeto para execuções diárias, o número de pesquisas passa a ser cerca de 60 000, o que o leva para o plano «Business». A frequência de atualização multiplica todos os outros fatores; por isso, defina-a de acordo com a frequência com que as decisões que dependem dos dados são efetivamente tomadas.

Utilize o período de avaliação para validar as suas consultas representativas, mercados, dispositivos e campos de saída antes de se comprometer com um determinado volume. Se também estiver a ponderar outros fornecedores, veja como os preços da API SERP se comparam entre os diferentes fornecedores.

O que é que a API SERP não faz e em que situações é que outra ferramenta é mais adequada?

A API SERP devolve páginas de resultados de pesquisa, não as páginas por trás de cada link, e não define uma classificação universal. A extração do DuckDuckGo e do Yandex é tarefa do seu código, a função assíncrona é exclusiva do Google e as respostas do Modo IA do Google são um produto separado. Utilize a API Scraper, a API Data ou um feed gerido quando esses limites forem relevantes.

  • A API limita-se à página de resultados. Para obter as páginas por trás dos links, utilize a API Scraper. Veja como utilizar a API Scraper.
  • O Modo IA é um produto separado. Para respostas, citações e menções a marcas do Modo IA do Google, utilize os dados do Modo IA do Google a partir da API de Dados.
  • Trata-se de um momento de pedido, não de um feed. Se precisar de registos recorrentes e controlados, entregues de acordo com um calendário, em vez de efetuar as chamadas por conta própria, consulte os feeds de dados de resultados de pesquisa.
  • Apenas os motores listados são suportados. Baseie-se nos onze motores indicados na referência, e não em páginas de documentação mais antigas.
  • Os motores HTML requerem manutenção. A manutenção dos seletores do DuckDuckGo e do Yandex é da sua responsabilidade quando a sua marcação for alterada.
  • O Async é exclusivo do Google. Planeie workers síncronos para o Bing, o DuckDuckGo e o Yandex.
  • Um resultado corresponde a uma observação. Uma classificação descreve uma consulta, um mercado, um dispositivo e um momento. Cabe a si, e não à API, decidir se a ausência de resultados tem importância comercial.
  • A utilização é regulamentada. Recolha resultados públicos elegíveis de acordo com o Contrato de Prestação de Serviços da WebScrapingAPI e com os requisitos que se aplicam a si.

Perguntas frequentes

O que é uma API SERP?

Uma API SERP é um serviço web que realiza uma pesquisa por si e devolve a página de resultados do motor de busca sob a forma de dados. Envia uma consulta, um motor de busca e contexto, como país, idioma e dispositivo. A API SERP da WebScrapingAPI devolve JSON analisado para o Google e o Bing e HTML num envelope JSON para o DuckDuckGo e o Yandex.

Como se utiliza uma API SERP?

Guarde a sua chave de API numa variável de ambiente e, em seguida, envie um pedido GET para https://serpapi.webscrapingapi.com/v2 com a chave de API, o motor de pesquisa e a sua consulta. Adicione controlos de mercado, como «gl» e «hl» para o Google, leia os resultados orgânicos da resposta JSON e guarde cada linha com a respetiva consulta, mercado, dispositivo e hora de captura.

Como obtenho uma chave da API SERP?

Registe uma conta na WebScrapingAPI e, em seguida, subscreva a API SERP a partir do painel de controlo para obter a sua chave. O período de avaliação inclui 100 pesquisas no Google. Guarde a chave numa variável de ambiente ou num gestor de segredos no seu servidor e nunca a coloque no código do navegador, em repositórios públicos, registos ou capturas de ecrã.

Existe um período de teste gratuito para a API SERP?

Sim. O período de avaliação da API SERP custa 0 $ e inclui 100 pesquisas no Google, o suficiente para testar as suas palavras-chave, mercados, dispositivos e resultados antes de escolher um plano. Os planos pagos do Google começam nos 28 $ por mês para 10 000 pesquisas. O Bing, o DuckDuckGo e o Yandex têm preços definidos por orçamento, de acordo com a sua carga de trabalho específica.

O que é o «scraping» de SERP?

O «scraping» de SERP consiste em recolher os resultados que um motor de busca apresenta para uma consulta, tais como títulos, links, posições e funcionalidades como pesquisas relacionadas. Fazer isso manualmente implica lidar com bloqueios e alterações de layout. Uma API SERP transfere esse trabalho para o fornecedor, pelo que o seu código envia um pedido e recebe os resultados sob a forma de dados.

Posso utilizar a API SERP com Python?

Sim. Instale o Requests, leia a sua chave a partir de uma variável de ambiente e passe api_key, engine e q no argumento params para que o Requests os codifique. Defina um tempo limite de cerca de 120 segundos, tente novamente em caso de respostas 429 e 5xx com backoff e leia a lista de resultados orgânicos a partir da resposta JSON do Google ou do Bing.

Que motores de busca são suportados pela API SERP?

Suporta o Google, o Bing, o DuckDuckGo e o Yandex. O Google também dispõe de motores especializados para pesquisa assíncrona, Maps, Avaliações do Maps, Hotéis, Voos, Tendências e Imagem Reversa. O Google e o Bing devolvem JSON analisado. O DuckDuckGo e o Yandex devolvem o HTML da página de resultados dentro de um envelope JSON, que a sua aplicação analisa.

A API SERP resolve CAPTCHAs?

Nenhuma página da API SERP promete isso. A WebScrapingAPI gere a infraestrutura de acesso à pesquisa por trás de cada pedido e, quando um motor de busca devolve uma página de desafio, um estado de erro ou um tempo limite esgotado, a API responde com um erro 422 do site, em vez de transmitir dados incorretos. Tente novamente uma vez se a falha parecer temporária e, em seguida, registe-a.

Por que razão o DuckDuckGo e o Yandex devolvem HTML em vez de resultados analisados?

Para estes dois motores de busca, a API SERP devolve a página de resultados original como HTML dentro de um envelope JSON, em vez de coleções analisadas. A sua aplicação escolhe o que extrair. Inspecione uma resposta real, associe-lhe seletores CSS, versione-os, guarde o HTML bruto e alerte quando um seletor deixar de corresponder após uma alteração no layout.

Como posso acompanhar as posições das palavras-chave com uma API SERP?

Escolha um conjunto fixo de palavras-chave, países, idiomas e dispositivos e, em seguida, faça consultas de acordo com um calendário. Guarde a classificação, o título e o link de cada resultado orgânico, juntamente com a hora da captura e o mercado. Compare resultados apenas dentro do mesmo mercado e dispositivo e trate as funcionalidades ausentes na SERP como uma observação, não como um erro.

Comece com 100 pesquisas gratuitas no Google

A API SERP devolve os resultados do Google e do Bing como JSON analisado e as páginas de resultados do DuckDuckGo e do Yandex como HTML num envelope JSON, com controlos de mercado, idioma e dispositivo em cada pedido. Quando souber as suas palavras-chave, mercados e calendário de atualização, compare os planos da API SERP e escolha o limite que melhor se adequa às suas necessidades.

Sobre o autor

Suciu Dan, Co-fundador @ WebScrapingAPI

Suciu Dan

Co-fundador

Suciu Dan é cofundador da WebScrapingAPI e escreve guias práticos, voltados para programadores, sobre web scraping em Python, web scraping em Ruby e infraestruturas de proxy.

Web Scraping com AWS Lambda: Guia para Python e Java 2026
Guias

Web Scraping com AWS Lambda: Guia para Python e Java 2026

TL;DR: Resumo: A extração de dados da Web com o AWS Lambda funciona melhor quando cada invocação é curta, delimitada e pode ser repetida de forma independente. Comece com HTTP direto, AWS SAM e S3 e, só depois, adicione SQS, contentores, renderização no navegador, proxies ou uma camada de recuperação gerida, apenas quando a carga de trabalho demonstrar que precisa deles.

Suciu Dan32 min read
Ler artigo
Como utilizar o GoSpider: rastrear, limpar URLs e extrair dados
Guias

Como utilizar o GoSpider: rastrear, limpar URLs e extrair dados

TL;DR: Resumo: O GoSpider é um rastreador de linha de comandos destinado a descobrir URLs, não um extrator completo de dados estruturados. Este guia sobre como utilizar o GoSpider mostra como realizar um rastreio limitado, gerir resultados de forma organizada, fazer a transferência de dados do Colly para CSV e seguir um percurso de diagnóstico para respostas 403 ou páginas que exijam renderização em JavaScript.

Suciu Dan23 min read
Ler artigo
Como fazer o Scrape Redfin: Guia Python para Dados de Propriedade
Guias

Como fazer o Scrape Redfin: Guia Python para Dados de Propriedade

TL;DR: A Redfin expõe pontos de extremidade de API ocultos que retornam JSON estruturado para listagens de propriedades, tornando possível ignorar totalmente a análise HTML frágil. Este guia orienta-o na construção de um scraper Python que extrai dados de aluguer e venda, pesquisa por localização, monitoriza novas listagens através de sitemaps XML e exporta resultados limpos para CSV ou JSON.

Suciu Dan14 min read
Ler artigo

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.