API de Rastreador de Pesquisa do Google: Cinco Padrões que Retornam Dados Vazios
Lead Scraping Automation Engineer
TL;DR:
- Um
200do ator Google Search não é prova de dados: a resposta pode carregar um arrayorganic_resultsvazio, um espaço reservado de anúncio em vez de uma listagem, ou um campo que está em branco por design. - O Dify preenche dois padrões de chave de API que produzem
401com{"code":14404,"message":"invalid access token"}— o nome do cabeçalho padrão éAuthorizatione o prefixo do cabeçalho padrão éBasic, e o ator não aceita nenhum deles. - Um fluxo de trabalho n8n pode validar com zero erros e ainda falhar em tempo de execução, porque o sandbox do nó de Código na versão 2.34.4 não expõe o construtor global
URL. - Um agente que tem uma ferramenta de pesquisa pode responder sem chamá-la, produzindo texto fluente que nunca tocou a API; contar chamadas de ferramenta transforma essa ausência silenciosa em uma falha.
- Os registros de pacote local retornam
place_id,gps_coordinates, ethumbnailvazios, ephone,type, ehourscom um espaço inicial — ambos são comportamentos documentados, não falhas a debugar.
O que o ator Google Search retorna
O ator scraper.google.search recebe uma consulta e retorna um SERP analisado como JSON. É a superfície do Google do Deep SerpApi, e geralmente é o primeiro ator conectado a um construtor de fluxo de trabalho ou a um framework de agente, porque uma lista de resultados classificados alimenta igualmente o rastreamento de classificação e a pesquisa de leads.
As falhas abaixo não são exóticas. Elas vêm da lacuna entre uma solicitação que é aceita e um payload que é utilizável — e cada uma delas pode ser reproduzida a partir das quatro plataformas host que este artigo usa como exemplos: Dify, n8n, Activepieces e LangChain.
A solicitação: endpoint, ator e parâmetros
Cada chamada é um POST para um único endpoint com dois campos. actor seleciona o scraper e input carrega seus parâmetros:
bash
curl -sS -X POST https://api.scrapeless.com/api/v1/scraper/request \
-H 'Content-Type: application/json' \
-H "x-api-token: $SCRAPELESS_API_KEY" \
-d '{"actor":"scraper.google.search","input":{"q":"web scraping api"}}'
Três parâmetros cobrem a maior parte do trabalho:
| Parâmetro | Propósito |
|---|---|
q |
A string da consulta. |
tbm |
Tipo de resultado. lcl retorna o pacote local em vez de resultados da web. |
start |
Deslocamento de resultado para paginação — 20 por página no pacote local. |
O cabeçalho de autenticação é x-api-token. Esse nome é o campo que uma plataforma sem código é mais propensa a preencher com seu próprio padrão. A especificação de semântica HTTP para respostas 401 espera um desafio vinculado ao próprio esquema de autenticação do recurso, então uma plataforma que supõe Authorization está sendo razoável — ela simplesmente está assumindo o esquema errado para este endpoint.
O envelope da resposta
Leia o envelope antes de ler os dados. Uma chamada bem-sucedida do Google Search retorna essas chaves de nível superior:
json
// illustrative sample — key shape only; values omitted
{
"search_information": {},
"organic_results": [],
"related_searches": [],
"pagination": {},
"metadata": {}
}
Duas coisas seguem dessa forma. Não há bandeira success para ramificar, então a presença e o comprimento de organic_results é o sinal. E não há bloco People-Also-Ask neste envelope — uma consulta que mostra perguntas relacionadas em um navegador retorna related_searches aqui, então um fluxo de trabalho que espera um array de perguntas recebe None e escreve uma coluna em branco.
Com tbm configurado como lcl, os resultados se movem para local_results.places[] em vez de organic_results[]. Um pipeline que codifica duramente um caminho produz silenciosamente nada quando o outro é solicitado.
Lendo a resposta em código
A afirmação após a solicitação é a parte que vale a pena copiar. Este exemplo gera uma exceção em vez de retornar uma lista vazia, então uma falha aparece onde ocorreu ao invés de três etapas depois em uma planilha:
python
import json
import os
import urllib.request
ENDPOINT = "https://api.scrapeless.com/api/v1/scraper/request"
def search(query: str) -> dict:
payload = json.dumps({"actor": "scraper.google.search", "input": {"q": query}}).encode()
request = urllib.request.Request(
ENDPOINT,
data=payload,
headers={
"Content-Type": "application/json",
"x-api-token": os.environ["SCRAPELESS_API_KEY"],
},
)
# urlopen raises HTTPError on any 4xx or 5xx, so a rejected call never reaches the parser.
with urllib.request.urlopen(request, timeout=120) as response:
return json.loads(response.read())
serp = search("web scraping api")
organic = serp.get("organic_results") or []
if not organic:
raise SystemExit(f"no organic_results in the response; envelope was {sorted(serp)}")
print(f"organic_results: {len(organic)}")
print(f"first result: {organic[0]['title']}")
print(f"envelope keys: {sorted(serp)}")
Ausente e vazio são estados diferentes, e a especificação do formato de intercâmbio JSON não lhe ajuda a distinguir "a chave foi omitida" de "o valor é uma string vazia". Decida qual dos dois seu pipeline trata como um erro antes de escrever o primeiro insert.
Trabalhar através disso no plano gratuito é suficiente para ver todos os comportamentos descritos aqui — crie uma conta Scrapeless e use a mesma chave em todas as quatro plataformas abaixo.
Cinco padrões que retornam dados vazios
O cabeçalho da chave de API que sua plataforma preenche é o errado
No Dify 1.16.1, importar um esquema OpenAPI como uma ferramenta personalizada e escolher a autenticação API Key deixa dois campos nos padrões que o ator rejeita. O nome do cabeçalho padrão é Authorization, e o prefixo do cabeçalho padrão é Basic — que envia x-api-token: Basic <key> mesmo após você corrigir o nome. Ambos produzem a mesma resposta:
json
{ "code": 14404, "message": "invalid access token" }
Uma mensagem de erro, duas causas independentes, o que torna caro o diagnóstico. A configuração de trabalho nomeia os três:
| Campo | Valor |
|---|---|
| Tipo de autenticação | API Key |
| Nome do cabeçalho | x-api-token |
| Prefixo do cabeçalho | Custom |
Dify também achata um objeto requisição-corpo aninhado em um parâmetro de string, assim o campo input chega como texto em vez de um objeto estruturado. Tanto um objeto quanto uma string JSON são aceitos, e é por isso que este raramente é notado até que um nó subsequente tente ler input.q.
Um fluxo de trabalho que valida ainda pode falhar em tempo de execução
A validação estática e a execução discordam no nó de Código do n8n. Um fluxo de trabalho usando new URL(link).hostname para agrupar resultados por domínio valida sem erros, depois falha no primeiro item com URL is not defined. O sandbox na versão 2.34.4 não expõe esse global, mesmo que o Padrão de URL WHATWG o defina como um construtor de Web API e o próprio relato do nó de Código falhando sem o construtor de URL registre o sintoma.
Derive o hostname com operações de string em vez disso:
javascript
// The Code node sandbox does not expose the global URL constructor,
// so the hostname comes from string operations.
const hostname = (link) =>
link ? link.replace(/^[a-z]+:\/\//i, '').replace(/^www\./i, '').split(/[/?#]/)[0] : '';
const results = [
{ position: 1, link: 'https://www.scrapeless.com/pt/product/deep-serp-api' },
{ position: 2, link: 'https://docs.scrapeless.com/en/deep-serp-api/quickstart/introduction/' },
];
for (const result of results) {
console.log(result.position, hostname(result.link));
}
A validação em um construtor de fluxo de trabalho verifica o grafo, não o código dentro de um nó. Portanto, um check verde não diz nada sobre se um nó de Código será executado.
A referência de etapa que resolve para nada
Na versão 0.82.0 do Activepieces, o JSON analisado de uma etapa HTTP mora sob body. A referência é {{step_1.body.organic_results}}, e {{step_1.organic_results}} resolve para nada — sem erro, sem aviso, apenas um loop vazio e uma execução que reporta sucesso. Com tbm definido como lcl, o caminho é {{step_1.body.local_results.places}}.
Uma falha de referência ausente parece idêntica a um conjunto de resultados genuinamente vazio, então verifique o caminho da referência antes de começar a procurar por um problema de dados.
O agente que responde sem chamar a ferramenta
Dê a um agente uma ferramenta de busca e ele pode não usá-la. Um modelo pequeno que recebe tanto uma ferramenta de busca quanto uma ferramenta de busca frequentemente executará a busca, depois responderá a partir dos trechos de resultado enquanto descreve o que "a página diz" — nunca buscando a página. A prosa é fluente e a citação é implícita, então nada na saída marca a resposta como não fundamentada.
A correção é uma asserção, não um prompt melhor. Conte chamadas de ferramentas e trate zero como uma falha:
Nota: este trecho envolve um agente existente, então executá-lo requer um agente LangChain construído e uma chave de provedor de modelo. Tudo do qual depende é uma saída padrão
agent.stream(...).
python
tool_calls = 0
for chunk in agent.stream({"messages": [("human", question)]}, stream_mode="values"):
message = chunk["messages"][-1]
tool_calls += len(getattr(message, "tool_calls", None) or [])
if tool_calls == 0:
raise SystemExit("the model answered without calling a tool; the answer is not grounded")
Instruções de ferramenta única são confiáveis em modelos pequenos. Instruções encadeadas — buscar, depois buscar o resultado principal — são onde a chamada da ferramenta desaparece silenciosamente, então divida os passos no código e deixe o modelo lidar com uma chamada de cada vez.
Campos que estão vazios de propósito
Alguns valores em branco estão corretos. Nos resultados do pacote local, place_id, gps_coordinates, e thumbnail retornam vazios, e phone, type, e hours chegam com um espaço à frente. Nenhum é um erro, e ambos quebram código ingênuo: um desvio de espaço à direita transforma uma chave de deduplicação em uma duplicata, e tratar um place_id vazio como um erro faz com que você depure um comportamento que está funcionando conforme documentado.
Normalize ao entrar:
| Campo | Comportamento | Manipulação |
|---|---|---|
phone, type, hours |
Espaço à frente | Remova antes de armazenar ou comparar. |
place_id, gps_coordinates, thumbnail |
Vazio nos resultados locais | Trate como nullable; não bloqueie o registro com eles. |
organic_results vs local_results.places |
Depende de tbm |
Selecione o caminho da requisição, não adivinhando. |
A mesma disciplina se aplica ao contagem. Um array de resultados pode conter slots patrocinados e espaços reservados de layout ao lado de listagens, portanto o comprimento do array não é o número de resultados — filtre com base no próprio campo de tipo do registro antes de relatar uma contagem, ou cada número a montante herda qualquer carga publicitária que a página possa ter servido.
Conclusão
As falhas caras em uma configuração de scraping sem código terminam verdes sem nada nelas: um cabeçalho de autenticação que sua plataforma preencheu, um global de Web API que o sandbox omite, um caminho de referência faltando um segmento, um agente que pulou a ferramenta, ou um campo que sempre estaria em branco. Cada um tem uma correção de uma linha e nenhuma mensagem de erro apontando para isso.
Dois hábitos abrangem todos os cinco. Leia o envelope de resposta antes dos dados e afirme o que você espera — um array não vazio, uma chamada de ferramenta, um tipo de registro — para que uma falha silenciosa se torne uma falha barulhenta na etapa que a causou. O guia de fluxo de trabalho de scraping do n8n e o tutorial de integração do LangChain mostram o mesmo ator conectado de ponta a ponta assim que essas verificações estão em vigor.
Pronto para construir contra uma superfície SERP que retorna um envelope documentado? Confira a documentação da Deep SerpApi para o conjunto completo de parâmetros, revise planos e volume incluído e comece no plano gratuito.
FAQ
P: Por que a chamada do ator de Pesquisa do Google retorna 200 com um array organic_results vazio?
Um array organic_results vazio com uma 200 significa que a solicitação foi aceita e analisada, mas não produziu resultados web para aquele formato de consulta. Verifique três coisas em ordem: se tbm foi definido como lcl, o que move resultados para local_results.places[]; se a consulta em si tem intenção de resultado; e se sua plataforma está lendo o corpo analisado em vez do envelope. Não há uma flag success na resposta, então o comprimento do array é o único sinal.
P: O que causa {"code":14404,"message":"invalid access token"} quando a chave está correta?
Essa resposta significa que a chave nunca chegou na forma que o endpoint espera. O cabeçalho deve ser x-api-token carregando a chave simples. Plataformas que usam Authorization por padrão, ou que acrescentam Basic ou Bearer ao valor, enviam um cabeçalho que o endpoint não pode ler — e a mensagem é idêntica em todos os casos, então verifique o nome do cabeçalho e qualquer configuração de prefixo separadamente.
P: Por que meu nó de Código n8n falha com URL is not defined quando o fluxo de trabalho valida?
O sandbox do nó de Código no n8n 2.34.4 não expõe o construtor global URL, e a validação do fluxo de trabalho não executa código de nó, então o gráfico passa suas verificações e a execução falha no primeiro item. Análise o nome do host com operações de string, ou mova o manuseio da URL para um nó que fornece a API.
P: Como posso saber se um agente realmente usou a ferramenta de pesquisa?
Conte as chamadas da ferramenta nas mensagens transmitidas e falhe quando a contagem for zero. Um modelo pode produzir uma resposta completa e confiante sem invocar nenhuma ferramenta, e nada no texto distingue isso de uma resposta fundamentada. Trate a contagem de chamadas de ferramentas como um requisito rigoroso, em vez de inspecionar a prosa.
P: Valores vazios place_id e gps_coordinates são um bug?
Não. Registros de pacotes locais retornam place_id, gps_coordinates e thumbnail vazios, então esses campos são anuláveis por design. Mantenha o registro e preencha a localização a partir dos campos que estão presentes em vez de descartar linhas ou adicionar tratamento de erro ao redor do comportamento esperado.
P: Por que meu loop do Activepieces itera zero vezes quando a etapa HTTP foi bem-sucedida?
A resposta analisada está aninhada sob body, então {{step_1.organic_results}} resolve para nada enquanto {{step_1.body.organic_results}} resolve para o array. Uma referência ausente não produz erro no Activepieces 0.82.0 — o loop simplesmente não recebe nada e a execução ainda relata sucesso, o que a torna indistinguível de um conjunto de resultados vazio até que você verifique o caminho.
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.



