Volver al blog

API de Scraper de Búsqueda de Google: Cinco Valores Predeterminados Que Devuelven Datos Vacíos

Daniel Kim
Daniel Kim

Lead Scraping Automation Engineer

20-Aug-2026

TL;DR:

  • Un 200 del actor de Google Search no es prueba de datos: la respuesta puede llevar un array organic_results vacío, un marcador de anuncio en lugar de un listado, o un campo que está en blanco por diseño.
  • Dify pre-completa dos predeterminados de clave API que producen 401 con {"code":14404,"message":"invalid access token"} — el nombre del encabezado predeterminado es Authorization y el prefijo del encabezado predeterminado es Basic, y el actor no acepta ninguno.
  • Un flujo de trabajo n8n puede validar con cero errores y aún así fallar en tiempo de ejecución, porque el sandbox del nodo de Código en la versión 2.34.4 no expone el constructor URL global.
  • Un agente dotado de una herramienta de búsqueda puede responder sin llamarla, produciendo un texto fluido que nunca tocó la API; contar las llamadas a la herramienta convierte esa omisión silenciosa en un fallo.
  • Los registros de local-pack devuelven place_id, gps_coordinates, y thumbnail vacíos, y phone, type, y hours con un espacio al principio — ambos son comportamientos documentados, no fallos a depurar.

El actor scraper.google.search toma una consulta y devuelve un SERP parseado como JSON. Es la superficie de Google de Deep SerpApi, y generalmente es el primer actor conectado en un constructor de flujos de trabajo o en un marco de agente, porque una lista de resultados clasificados alimenta el seguimiento de clasificaciones y la investigación de leads igualmente bien.

Las fallas a continuación no son exóticas. Vienen de la brecha entre una solicitud que es aceptada y una carga útil que es utilizable — y cada una de ellas puede ser reproducida a partir de las cuatro plataformas anfitrionas que este artículo utiliza como ejemplos: Dify, n8n, Activepieces y LangChain.

La solicitud: endpoint, actor y parámetros

Cada llamada es un POST a un solo endpoint con dos campos. actor selecciona el scraper y input lleva sus parámetros:

bash Copy
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"}}'

Tres parámetros cubren la mayor parte del trabajo:

Parámetro Propósito
q La cadena de consulta.
tbm Tipo de resultado. lcl devuelve el pack local en lugar de resultados web.
start Desplazamiento de resultados para paginación — 20 por página en el pack local.

El encabezado de autenticación es x-api-token. Ese nombre es el campo que una plataforma sin código es más probable que complete con su propio valor predeterminado. La especificación de semánticas HTTP para respuestas 401 espera un desafío vinculado al propio esquema de autenticación del recurso, por lo que una plataforma que asume Authorization es razonable — simplemente está asumiendo el esquema equivocado para este endpoint.

El sobre de respuesta

Lee el sobre antes de leer los datos. Una llamada exitosa a Google Search devuelve estas claves de nivel superior:

json Copy
// illustrative sample — key shape only; values omitted
{
  "search_information": {},
  "organic_results": [],
  "related_searches": [],
  "pagination": {},
  "metadata": {}
}

Dos cosas siguen de esa forma. No hay una bandera success en la que ramificarse, así que la presencia y longitud de organic_results es la señal. Y no hay bloque de People-Also-Ask en este sobre — una consulta que muestra preguntas relacionadas en un navegador devuelve related_searches aquí, así que un flujo de trabajo que espera un array de preguntas recibe None y escribe una columna en blanco.

Con tbm configurado en lcl, los resultados se mueven a local_results.places[] en lugar de organic_results[]. Un pipeline que codifica una ruta en duro produce silenciosamente nada cuando se solicita la otra.

Leyendo la respuesta en código

La afirmación después de la solicitud es la parte que vale la pena copiar. Este ejemplo lanza en lugar de devolver una lista vacía, así que un fallo se presenta donde ocurrió en lugar de tres pasos después en una hoja de cálculo:

python Copy
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 y vacío son estados diferentes, y la especificación del formato de intercambio JSON no te ayuda a distinguir "la clave fue omitida" de "el valor es una cadena vacía". Decide cuál de los dos tu pipeline trata como un error antes de escribir la primera inserción.

Trabajar en esto en el plan gratuito es suficiente para ver cada comportamiento descrito aquí — crea una cuenta en Scrapeless y usa la misma clave en las cuatro plataformas a continuación.

Cinco predeterminados que devuelven datos vacíos

El encabezado de clave API que tu plataforma pre-completa es el incorrecto

En Dify 1.16.1, importar un esquema OpenAPI como una herramienta personalizada y elegir la autenticación API Key deja dos campos en los valores predeterminados que el actor rechaza. El nombre del encabezado predeterminado es Authorization, y el prefijo del encabezado predeterminado es Basic — que envía x-api-token: Basic <key> incluso después de que corrijas el nombre. Ambos producen la misma respuesta:

json Copy
{ "code": 14404, "message": "invalid access token" }

Un mensaje de error, dos causas independientes, que es lo que hace que sea costoso de diagnosticar. La configuración de trabajo enumera las tres:

Campo Valor
Tipo de autenticación API Key
Nombre del encabezado x-api-token
Prefijo del encabezado Custom

Dify también aplana un objeto de cuerpo de solicitud anidado en un parámetro de cadena, por lo que el campo input llega como texto en lugar de como un objeto estructurado. Se aceptan tanto un objeto como una cadena JSON, que es por lo que este rara vez se nota hasta que un nodo descendente intenta leer input.q.

Un flujo de trabajo que valida aún puede fallar en tiempo de ejecución

La validación estática y la ejecución no están de acuerdo en el nodo de código n8n. Un flujo de trabajo que utiliza new URL(link).hostname para agrupar resultados por dominio se valida sin errores, luego falla en el primer elemento con URL is not defined. El entorno en la versión 2.34.4 no expone ese global, aunque el Estándar de URL WHATWG lo define como un constructor de API web y el propio informe de n8n sobre el fallo del nodo de código sin el constructor de URL registra el síntoma.

Deriva el nombre de host con operaciones de cadena en su lugar:

javascript Copy
// 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/es/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));
}

La validación en un constructor de flujo de trabajo verifica el gráfico, no el código dentro de un nodo. Por lo tanto, una marca de verificación verde no dice nada sobre si un nodo de código se ejecutará.

La referencia de paso que no resuelve nada

En Activepieces 0.82.0, el JSON analizado de un paso HTTP vive bajo body. La referencia es {{step_1.body.organic_results}}, y {{step_1.organic_results}} no resuelve nada en absoluto: no hay error, ni advertencia, solo un bucle vacío y una ejecución que informa éxito. Con tbm configurado en lcl, la ruta es {{step_1.body.local_results.places}}.

Un fallo de referencia faltante se ve idéntico a un conjunto de resultados genuinamente vacío, así que verifica la ruta de referencia antes de buscar un problema de datos.

El agente que responde sin llamar a la herramienta

Dale a un agente una herramienta de búsqueda y puede que no la use. Un modelo pequeño que tenga tanto una herramienta de búsqueda como una herramienta de obtención a menudo ejecutará la búsqueda, luego responderá a partir de los fragmentos de resultados mientras describe lo que "la página dice", nunca obteniendo la página. La prosa es fluida y la cita está implícita, por lo que nada en la salida marca la respuesta como no fundamentada.

La solución es una afirmación, no un mejor aviso. Cuenta las llamadas a la herramienta y trata el cero como un fallo:

Nota: este fragmento envuelve un agente existente, por lo que su ejecución requiere un agente LangChain construido y una clave de proveedor de modelo. Todo lo que depende de él es la salida estándar de agent.stream(...).

python Copy
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")

Las instrucciones de herramienta única son confiables en modelos pequeños. Las instrucciones encadenadas —buscar, luego obtener el mejor resultado— son donde la llamada a la herramienta desaparece silenciosamente, así que divide los pasos en el código y deja que el modelo maneje una llamada a la vez.

Campos que están vacíos a propósito

Algunos valores en blanco son correctos. En los resultados de paquetes locales, place_id, gps_coordinates y thumbnail regresan vacíos, y phone, type y hours llegan con un espacio al principio. Ninguno es un error, y ambos rompen el código ingenuo: una discrepancia de espacio final convierte una clave de deduplicación en un duplicado, y tratar un place_id vacío como un error te envía a depurar un comportamiento que está funcionando como se documentó.

Normaliza en el camino de entrada:

Campo Comportamiento Manejo
phone, type, hours Espacio inicial Recorta antes de almacenar o comparar.
place_id, gps_coordinates, thumbnail Vacío en resultados locales Tratar como anulable; no bloquear el registro por ellos.
organic_results vs local_results.places Depende de tbm Selecciona la ruta de la solicitud, no adivinando.

La misma disciplina se aplica al conteo. Un array de resultados puede contener espacios patrocinados y marcadores de diseño junto a listados, por lo que la longitud del array no es el número de resultados: filtra según el propio campo de tipo del registro antes de informar un conteo, o cada número descendente hereda cualquier carga de anuncios que la página haya servido.

Conclusión

Los costosos fallos en una configuración de raspado sin código terminan en verde sin nada en ellos: un encabezado de autenticación que tu plataforma completó automáticamente, un global de API web que el entorno omite, una ruta de referencia que le falta un segmento, un agente que omite la herramienta, o un campo que siempre iba a estar en blanco. Cada uno tiene una solución de una línea y ningún mensaje de error que apunte a ello.
Dos hábitos abarcan los cinco. Lee el sobre de respuesta antes de los datos y afirma lo que esperas: un array no vacío, una llamada de herramienta, un tipo de registro; así, un fallo silencioso se convierte en un fallo estruendoso en el paso que lo causó. La guía de flujo de trabajo de raspado n8n y la guía de integración de LangChain muestran al mismo actor cableado de extremo a extremo una vez que esas verificaciones están en su lugar.

¿Listo para construir contra una superficie SERP que retorna un sobre documentado? Revisa la documentación de Deep SerpApi para el conjunto completo de parámetros, revisa planes y volumen incluido y comienza con el plan gratuito.

FAQ

P: ¿Por qué mi actor de búsqueda de Google devuelve 200 con un array organic_results vacío?

Un array organic_results vacío con un 200 significa que la solicitud fue aceptada y analizada, pero no produjo resultados web para esa forma de consulta. Verifica tres cosas en orden: si tbm se configuró en lcl, lo que mueve los resultados a local_results.places[]; si la consulta en sí tiene intención de resultado; y si tu plataforma está leyendo el cuerpo analizado en lugar del sobre. No hay ningún indicador success en la respuesta, así que la longitud del array es la única señal.

P: ¿Qué causa {"code":14404,"message":"invalid access token"} cuando la clave es correcta?

Esa respuesta significa que la clave nunca llegó en la forma que el endpoint espera. El encabezado debe ser x-api-token llevando la clave básica. Las plataformas que predeterminan Authorization, o que anteponen Basic o Bearer al valor, envían un encabezado que el endpoint no puede leer, y el mensaje es idéntico en cada caso, así que verifica el nombre del encabezado y cualquier ajuste de prefijo por separado.

P: ¿Por qué mi nodo de Código en n8n falla con URL is not defined cuando el flujo de trabajo valida?

El sandbox del nodo de Código en n8n 2.34.4 no expone el constructor global URL, y la validación del flujo de trabajo no ejecuta código del nodo, así que el gráfico pasa sus verificaciones y la ejecución falla en el primer elemento. Analiza el nombre de host con operaciones de cadena, o mueve el manejo de URL a un nodo que proporcione la API.

P: ¿Cómo sé si un agente realmente utilizó la herramienta de búsqueda?

Cuenta las llamadas a la herramienta en los mensajes transmitidos y falla cuando la cuenta es cero. Un modelo puede producir una respuesta completa y confiada sin invocar ninguna herramienta, y nada en el texto distingue eso de una respuesta fundamentada. Trata la cuenta de llamadas a la herramienta como un requisito estricto en lugar de inspeccionar la prosa.

P: ¿Son los valores vacíos place_id y gps_coordinates un error?

No. Los registros de paquete local devuelven place_id, gps_coordinates y thumbnail vacíos, por lo que esos campos son anulables por diseño. Mantén el registro y pobla la ubicación desde los campos que están presentes en lugar de descartar filas o agregar manejo de errores alrededor del comportamiento esperado.

P: ¿Por qué mi bucle de Activepieces itera cero veces cuando el paso HTTP tuvo éxito?

La respuesta analizada está anidada bajo body, por lo que {{step_1.organic_results}} se resuelve en nada mientras {{step_1.body.organic_results}} se resuelve en el array. Una referencia faltante no produce ningún error en Activepieces 0.82.0: el bucle simplemente no recibe nada y la ejecución aún reporta éxito, lo que lo hace indistinguible de un conjunto de resultados vacío hasta que revises la ruta.

En Scrapeless, solo accedemos a datos disponibles públicamente y cumplimos estrictamente con las leyes, regulaciones y políticas de privacidad del sitio web aplicables. El contenido de este blog es sólo para fines de demostración y no implica ninguna actividad ilegal o infractora. No ofrecemos garantías y renunciamos a toda responsabilidad por el uso de la información de este blog o enlaces de terceros. Antes de realizar cualquier actividad de scraping, consulte a su asesor legal y revise los términos de servicio del sitio web de destino u obtenga los permisos necesarios.

Artículos más populares

Catalogar