Exportar JSON de búsqueda de Google a CSV para análisis
Expert Network Defense Engineer
TL;DR:
- Un CSV de resultados de búsqueda de Google necesita el contexto de la consulta junto a sus filas. Preserva los tiempos de solicitud y observación para que cada resultado siga siendo interpretable después de la exportación.
- CSV es una proyección de JSON. Mantén la captura en bruto, distingue valores ausentes y nulos, y registra el significado de las celdas transformadas.
- Un archivo solo con encabezados necesita un registro de ejecución. Las capturas pendientes, fallidas, no asignadas y vacías presentes pueden producir filas orgánicas nulas por diferentes razones.
Una hoja de cálculo puede preservar cada título y aun así perder el significado de la búsqueda que la produjo. Sin la consulta, el contexto enviado y el tiempo de observación, una fila se vuelve difícil de comparar o rastrear. Una celda en blanco crea otra ambigüedad: ¿faltaba el valor, era nulo o fue rechazado por la transformación?
API de Búsqueda de Google sin Scrapeless proporciona datos de búsqueda estructurados en la fuente. Esta guía construye un CSV de resultados de búsqueda de Google a partir de una captura guardada utilizando un exportador local de Python. La generación de CSV, la manipulación de hojas de cálculo y el almacenamiento de archivos son funciones del programa de ejemplo, no una afirmación de que la API devuelve directamente este formato de exportación.
Prerrequisitos y el Sobre de Captura
El exportador necesita Python y una captura JSON guardada con request, http_status, y response. Incluye run_id, requested_at, y received_at cuando el colector los registre. Estos campos externos pertenecen a la aplicación de colección, no al envoltorio de respuesta nativo de la API.
El flujo de trabajo de solicitud de Google Search distingue los datos de tarea HTTP 200 del trabajo pendiente HTTP 201. Preserva el resultado HTTP con la respuesta antes de aplanar cualquier cosa. Leer un campo orgánico ausente de una respuesta pendiente y sustituirlo por una lista vacía borraría esa distinción.
No se necesita clave API ni paquete de terceros para la transformación local. Producir una captura de cuenta es un paso autenticado separado, que no se realizó para este artículo. Las verificaciones locales utilizan capturas sintéticas para ejercitar tipos de datos, estados vacíos, Unicode y texto sensible a hojas de cálculo.
El modelo de valor JSON preserva arreglos, objetos, nulos y cadenas que no se asignan directamente a celdas planas. Mantén la captura original disponible después de la exportación para que los analistas posteriores puedan recuperar módulos omitidos y valores originales exactos.
Decide Qué Columnas Llevan Contexto y Significado
Repite el identificador de ejecución, los tiempos de solicitud y recepción, consulta exacta cuando esté disponible, y solicitud serializada en cada fila de resultado. La solicitud completa preserva configuraciones más allá de las columnas de conveniencia fijas y facilita la auditoría de la exportación.
Los parámetros de búsqueda de Google incluyen configuraciones de país e idioma, pero el modo de URL completa puede llevar la configuración dentro de url. Por lo tanto, una columna q en blanco no indica necesariamente que falta una consulta enviada. Inspecciona request_json; no reconstruyas una consulta efectiva adivinando a partir de un campo de conveniencia vacío.
El orden del arreglo orgánico y la posición devuelta son columnas separadas. ordinal registra el orden fuente basado en cero del elemento. position se retiene solo cuando es un entero positivo, con booleanos rechazados explícitamente. El exportador no fabrica un ranking a partir del orden del arreglo.
Los campos de texto y la posición cada uno tienen una columna de estado compañera. missing, null, y value explican los casos comunes. invalid marca una posición inutilizable; unexpected_type marca un valor de campo de texto no string que se retiene como JSON serializado en lugar de ser descartado silenciosamente.
Separa la Cita CSV de la Interpretación de Hojas de Cálculo
Un escritor CSV maneja delimitadores y texto entre comillas; no decide cómo una hoja de cálculo evalúa una celda. Usa el escritor CSV de Python para comas, comillas y saltos de línea integrados en lugar de unir cadenas manualmente.
El programa abre su salida con newline="" y utf-8-sig. La primera configuración permite que el módulo CSV gestione los límites de registro. La firma UTF-8 puede ayudar a una hoja de cálculo a reconocer texto acentuado o no latino, pero el comportamiento de importación de la aplicación de destino aún necesita inspección.
Un valor que comienza con un carácter de fórmula puede ser interpretado como una expresión cuando se abre en una hoja de cálculo. La guía de inyección de CSV describe por qué un CSV sintácticamente correcto no es suficiente para hacer que el texto no confiable sea inerte.
Este exportador antepone un apóstrofo para los caracteres que inician fórmulas seleccionados, incluyendo variantes de ancho completo, y para las tabulaciones o saltos de línea iniciales. Aplica la política al contexto de la solicitud así como al texto del resultado. Las posiciones numéricas utilizan una regla de validación separada.
Comienza a Extraer Datos con Scrapeless
Potencia tu trabajo de scraping web y automatización con Scrapeless!
Regístrate hoy y obtén $5 en crédito gratis — sin necesidad de tarjeta de crédito.Reclama tu crédito gratis ahora en el Tablero de Scrapeless.
Ejecuta el Exportador Local de JSON a CSV
Guarda el programa como serp_csv.py, luego ejecuta python3 serp_csv.py capture.json organic.csv. Lee la captura y escribe organic.csv más el organic.csv.run.json correspondiente. Los archivos de salida existentes son reemplazados; elige un directorio de exportación dedicado o nombres únicos al retener varias versiones.
El programa rechaza rutas de salida que sobrescribirían la captura de entrada. No cambia el JSON original, no envía solicitudes API ni recupera tareas pendientes.
python
import argparse
import csv
import json
from pathlib import Path
FIELDS = ["run_id", "requested_at", "received_at", "q", "request_json", "ordinal",
"position", "position_state", "title", "title_state", "link", "link_state",
"snippet", "snippet_state"]
def spreadsheet_text(value):
text = "" if value is None else str(value)
stripped = text.lstrip()
if (stripped.startswith(("=", "+", "-", "@", "=", "+", "-", "@"))
or text.startswith(("\t", "\r", "\n"))):
return "'" + text
return text
def field(row, name):
if name not in row:
return "", "missing"
value = row[name]
if value is None:
return "", "null"
if name == "position":
return (value, "value") if type(value) is int and value > 0 else ("", "invalid")
if isinstance(value, str):
return spreadsheet_text(value), "value"
return spreadsheet_text(json.dumps(value, ensure_ascii=False)), "unexpected_type"
def export(source, target):
source, target = Path(source), Path(target)
sidecar = target.with_suffix(target.suffix + ".run.json")
if source.resolve() in (target.resolve(), sidecar.resolve()):
raise ValueError("Output paths must differ from input")
record = json.loads(source.read_text(encoding="utf-8"))
request = record.get("request")
if not isinstance(request, dict) or not isinstance(request.get("input"), dict):
raise ValueError("Expected a capture record with request.input")
payload = record.get("response")
rows = payload.get("organic_results") if isinstance(payload, dict) else None
status = record.get("http_status")
if status == 201:
state, rows = "pending", []
elif status != 200:
state, rows = ("transport_error" if status is None else "http_error"), []
elif not isinstance(rows, list) or any(not isinstance(x, dict) for x in rows):
state, rows = "unmapped", []
else:
state = "observed" if rows else "empty"
context = {
"run_id": spreadsheet_text(record.get("run_id")),
"requested_at": spreadsheet_text(record.get("requested_at")),
"received_at": spreadsheet_text(record.get("received_at")),
"q": spreadsheet_text(request["input"].get("q")),
"request_json": spreadsheet_text(json.dumps(request, ensure_ascii=False, sort_keys=True)),
}
with target.open("w", encoding="utf-8-sig", newline="") as handle:
writer = csv.DictWriter(handle, fieldnames=FIELDS)
writer.writeheader()
for ordinal, item in enumerate(rows):
output = dict(context, ordinal=ordinal)
for name in ("position", "title", "link", "snippet"):
output[name], output[name + "_state"] = field(item, name)
writer.writerow(output)
sidecar.write_text(json.dumps({"source": str(source), "run_id": record.get("run_id"),
"state": state, "rows": len(rows), "request": request,
"requested_at": record.get("requested_at"), "received_at": record.get("received_at"),
"export_policy": "spreadsheet_text_prefix_v1; original values remain in source JSON"},
ensure_ascii=False, indent=2), encoding="utf-8")
print(f"Exported {len(rows)} organic rows; state={state}; metadata={sidecar}")
return state, len(rows)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("source")
parser.add_argument("target")
args = parser.parse_args()
export(args.source, args.target)
El sidecar registra el estado de la colección, la cantidad de filas proyectadas, la ruta de origen, la solicitud, las marcas de tiempo y la política de exportación. Un CSV solo con encabezados sigue siendo explicable mientras ese registro permanezca con él. Mantén ambos archivos de salida juntos al entregar la exportación a otra persona.
Inspeccionar Nulos y Datos Orgánicos Malformados
Un array orgánico vacío presente produce state=empty. HTTP 201 produce pending, un estado HTTP faltante se convierte en transport_error, y otro estado no 200 se convierte en http_error en el modelo de estado de esta aplicación. Estos resultados pueden compartir una cantidad de filas cero sin compartir un significado.
Si el campo orgánico está ausente, no es un array, o contiene un elemento no objeto, toda la proyección se convierte en unmapped. El programa no exporta filas orgánicas para esa ejecución. Esto evita eliminar silenciosamente elementos malformados mientras describe las filas restantes como una proyección completa.
Los campos opcionales se manejan de manera más restringida. Un fragmento faltante deja una celda en blanco y un estado de campo explícito sin descartar el elemento orgánico. Un valor complejo inesperado sigue siendo representado como texto JSON, por lo que el valor inusual aún puede ser inspeccionado.
Estas son políticas de aplicación. Documenta junto a la exportación y revísalas deliberadamente si el consumidor necesita un esquema diferente. Una columna de estado de campo es útil precisamente porque otro analista no debería tener que inferir la transformación a partir de unas pocas celdas visibles.
Verifica la Transferencia de la Hoja de Cálculo
Lee la salida con un analizador CSV y compara registros lógicos, no líneas físicas. Un fragmento entre comillas puede contener un salto de línea sin crear un nuevo resultado de búsqueda. Confirma que la cuenta del sidecar coincida con las filas analizadas y que cada fila lleve su contexto de solicitud.
Revisa valores Unicode y sensibles a fórmulas en la aplicación que el equipo realmente utiliza. La política del apóstrofo cambia intencionalmente la representación exportada y puede ser visible en algunos visores. No es una garantía universal en todas las configuraciones de importación y aplicaciones de hojas de cálculo.
Incluye el comportamiento de guardar y volver a abrir en la prueba. La discusión sobre la importación de hojas de cálculo ilustra por qué el manejo de escapes merece una revisión específica de la aplicación. Importa columnas relevantes como texto y utiliza el JSON original siempre que se requieran cadenas de origen exactas.
Un exitoso viaje de vuelta local confirma la consistencia de esta proyección. No establece que la muestra de búsqueda ascendente sea exhaustiva, representativa o adecuada para una conclusión de ranking sin un análisis adicional.
Conclusión
Exporta el contexto de la solicitud con los resultados, mantiene los estados de campo donde los blancos ocultarían el significado y retiene el JSON bruto. Un CSV más un registro de ejecución le da al siguiente analista suficiente información para distinguir una porción vacía medida de una colección no disponible.
Un investigación de contenido de SERP puede utilizar las observaciones exportadas para construir una lista de lectura revisable antes de redactar un informe de contenido.
Construye Tu Próxima Observación de Búsqueda
Utilice Scrapeless Google Search API para los datos de búsqueda en este flujo de trabajo. Revise Scrapeless pricing al planificar la recolección, y mantenga los parámetros de búsqueda de Google junto a su configuración.
Discuta su implementación con la comunidad en Discord o Telegram.
FAQ
P: ¿El Google Search API crea directamente este CSV?
No. El exportador demostrado transforma JSON guardado localmente. La generación de archivos y el esquema auxiliar pertenecen al programa de Python.
P: ¿Por qué mantener request_json cuando la consulta ya tiene una columna?
La solicitud completa preserva configuraciones opcionales y entrada de URL completas que una columna de consulta por sí sola no puede representar.
P: ¿Las comillas CSV evitan la interpretación de fórmulas?
No. El manejo de delimitadores y la evaluación de hojas de cálculo son independientes. Aplique una política de texto documentada y verifique el flujo de trabajo de importación previsto.
P: ¿Un CSV vacío significa que la búsqueda no devolvió resultados?
No necesariamente. Inspeccione el estado del auxiliar para distinguir un array vacío presente de una colección pendiente, fallida o no mapeada.
P: ¿Se pueden recuperar los valores originales?
Sí, de la captura de entrada retenida. El CSV es una proyección y transforma intencionadamente algunas representaciones de texto para su uso en hojas de cálculo.
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.



