Para extraer datos de un Impressum con Python sin tener que crear un crawler propio, utilice la API Impressum Scraper de Datablist junto con la librería Requests. Usted proporciona las URLs de los sitios web de las empresas, la API localiza la página de Impressum de cada sitio y extrae de ella datos estructurados de la empresa y sus contactos.

En este ejemplo utilizo dos marcas alemanas consolidadas: el fabricante de ropa Trigema y la marca de productos para actividades al aire libre VAUDE. Un pequeño ejemplo ejecutable en Python realiza la consulta y conserva tanto los datos extraídos como la URL del Impressum de origen en cada registro de proveedor.

📌 Resumen para quienes tienen prisa

Utilice la API Impressum Scraper de Datablist para convertir sitios web de empresas alemanas en datos estructurados de empresa y contacto. El ejemplo en Python envía dos sitios web, espera a que termine la tarea en segundo plano, recupera todas las páginas de resultados y guarda en cada registro la URL de la página legal localizada.

  • Entrada: URLs de sitios web de empresas alemanas.
  • Salida: Datos de empresa y contacto, además del enlace al Impressum de origen.

💡 ¿Prefiere una solución no-code? Utilice Impressum Scraper de Datablist para extraer estos datos empresariales sin escribir código.

Configure su clave API y el entorno de Python

Cree una cuenta de Datablist y, después, una Personal API Key. El acceso a la REST API está disponible con el plan Growth. Este es un ejemplo del formato de la clave:

text
auth0|exampleuser:exampleaccount:EXAMPLE_TOKEN_NOT_VALID:1

Exporte su propia clave como DATABLIST_API_KEY:

shell
export DATABLIST_API_KEY="your-personal-api-key"

Para este ejemplo en Python utilizo el paquete requests. Cree un archivo llamado scrape_impressum.py e instale el paquete:

shell
python -m pip install requests

Cada sitio web enviado consume 10 créditos. El ejemplo siguiente, con dos sitios web, consume 20 créditos cuando se procesan ambas entradas.

Cree la función scrape_impressums()

Pegue este script completo en scrape_impressum.py:

python
import json
import os
import time
import uuid
import requests
def scrape_impressums(suppliers, api_key):
"""Submit one task, wait for it to finish, and return every result."""
tasks_url = "https://api.datablist.com/v1/enrichments/tasks"
headers = {"X-API-Key": api_key}
inputs = [
{
"inputId": supplier["id"],
"data": {"websiteUrl": supplier["website_url"]},
}
for supplier in suppliers
]
payload = {
"enrichmentId": "impressum-scraper",
"uniqueId": str(uuid.uuid4()),
"settings": {},
"inputs": inputs,
}
response = requests.post(tasks_url, headers=headers, json=payload)
response.raise_for_status()
task = response.json()
task_id = task["@id"]
task_url = f"{tasks_url}/{task_id}"
while task["status"] not in ("completed", "failed", "stopped"):
time.sleep(3)
response = requests.get(task_url, headers=headers)
response.raise_for_status()
task = response.json()
if task["status"] != "completed":
raise RuntimeError(
f"Task {task_id} {task['status']}: {task.get('error')}"
)
results = []
results_url = f"{task_url}/results"
params = {"limit": 100}
while True:
response = requests.get(results_url, headers=headers, params=params)
response.raise_for_status()
page = response.json()
results.extend(page["results"])
next_cursor = page["nextCursor"]
if next_cursor is None:
break
params["cursor"] = next_cursor
return results
if __name__ == "__main__":
api_key = os.environ.get("DATABLIST_API_KEY")
if not api_key:
raise RuntimeError("Set DATABLIST_API_KEY before running this script.")
suppliers = [
{
"id": "supplier-trigema",
"label": "Trigema",
"website_url": "https://www.trigema.de",
},
{
"id": "supplier-vaude",
"label": "VAUDE",
"website_url": "https://www.vaude.com",
},
]
impressum_results = scrape_impressums(suppliers, api_key)
for result in impressum_results:
print(json.dumps(result, ensure_ascii=False))

Ejecute el script completo con:

shell
python scrape_impressum.py

La función sigue tres pasos para interactuar con la API: envía los sitios web de entrada, espera a que termine la tarea y recupera todas las páginas de resultados.

Envíe los sitios web de entrada

El script transforma cada proveedor en una entrada para la API como esta:

python
inputs = [
{
"inputId": supplier["id"],
"data": {"websiteUrl": supplier["website_url"]},
}
for supplier in suppliers
]

inputId es su propio identificador estable. data.websiteUrl es la página de inicio de la empresa que inspeccionará el scraper. Utilice el sitio web de la propia empresa, no un directorio ni un perfil en redes sociales. El payload selecciona el enrichment público impressum-scraper y utiliza un objeto settings vacío porque esta API no requiere ajustes públicos.

La solicitud POST crea una tarea en segundo plano. Datablist acepta la solicitud y devuelve un objeto de tarea cuyo @id identifica esa ejecución. La función utiliza ese ID para construir las URLs de estado y resultados.

Una respuesta de creación abreviada tiene este aspecto:

json
{
"@id": "task-id",
"enrichmentId": "impressum-scraper",
"status": "queued",
"links": {
"self": "https://api.datablist.com/v1/enrichments/tasks/task-id",
"results": "https://api.datablist.com/v1/enrichments/tasks/task-id/results"
}
}

queued significa que la solicitud se ha aceptado, no que el resultado esté listo. El script lleva el @id devuelto a los dos pasos siguientes, por lo que no necesita copiar manualmente las URLs de la tarea. También llama a raise_for_status() antes de leer cada respuesta. De este modo, un error de autenticación o validación detiene el proceso en la solicitud HTTP que ha fallado, en vez de confundirse con una consulta completada.

Espere a que termine la tarea en segundo plano

Datablist procesa la tarea en segundo plano. El ejemplo comprueba su estado cada tres segundos hasta que llega a completed, failed o stopped. Requests es una librería bloqueante de Python, por lo que su script local espera durante estas llamadas, aunque la tarea de la API se ejecute en segundo plano.

Si la tarea termina con failed o stopped, la función genera un error que incluye el ID de la tarea y su estado final. Conserve ese ID cuando investigue la tarea existente, en lugar de volver a enviar inmediatamente el mismo trabajo de pago.

Recupere todas las páginas de resultados

Una vez completada la tarea, el script solicita hasta 100 resultados por página. La regla de paginación es sencilla: recupere la página siguiente hasta que nextCursor sea null. Cuando el cursor contiene un valor, el script lo envía con la siguiente solicitud.

No vincule los registros devueltos con su aplicación según la posición que ocupan en la lista. Los resultados pueden llegar en un orden distinto al de las entradas enviadas. Utilice inputId como clave de unión.

Cómo encuentra la API una página de Impressum

La página de inicio es el punto de partida, no la página de la que la API espera extraer los datos. Impressum Scraper utiliza AI para inspeccionar los enlaces internos del host proporcionado e identificar un Impressum o una página legal o de contacto equivalente. Esto es importante porque el enlace puede aparecer bajo nombres como Rechtliches, Kontakt o Legal, en vez de encontrarse en /impressum.

Si la AI no encuentra un enlace interno adecuado, el scraper prueba las rutas habituales /impressum y /imprint en el mismo host. Cuando llega a una página de origen, la AI extrae en un único resultado los campos de razón social, dirección, contacto, registro mercantil, IVA y fuente. No utiliza un motor de búsqueda ni accede a un directorio externo.

Impressum Scraper sigue el enlace legal o una ruta habitual de un sitio web alemán antes de extraer datos empresariales estructurados y la URL del Impressum de origen
Impressum Scraper sigue el enlace legal o una ruta habitual de un sitio web alemán antes de extraer datos empresariales estructurados y la URL del Impressum de origen

Los dos resultados muestran en la práctica que las rutas pueden variar. Trigema devolvió /kundenservice/rechtliches/impressum/, mientras que VAUDE devolvió /de/de/impressum.html. Conserve impressumUrl en cada resultado, ya que registra la página de origen exacta de los campos extraídos.

Analice los resultados de Trigema y VAUDE

Este es un extracto compacto de los resultados de ambos ejemplos.

📘 Direcciones de email de ejemplo: Los emails aparecen ocultos con ** a continuación. La API devuelve las direcciones completas.

json
[
{
"inputId": "supplier-trigema",
"status": "success",
"outputs": {
"firstName": "Wolfgang",
"lastName": "Grupp",
"companyName": "Trigema W. Grupp KG",
"postalAddress": "Josef-Mayer-Str. 31-35, D-72393 Burladingen",
"emailAddress": "b**@trigema.de",
"registrationNumber": "HRA 740365",
"vatNumber": "DE144846566",
"impressumUrl": "https://www.trigema.de/kundenservice/rechtliches/impressum/",
"agentConfidenceScore": 90
},
"creditsUsed": "10",
"error": null
},
{
"inputId": "supplier-vaude",
"status": "success",
"outputs": {
"firstName": "Antje",
"lastName": "von Dewitz",
"companyName": "VAUDE Sport GmbH & Co. KG",
"postalAddress": "Vaude Straße 2, 88069 Tettnang",
"emailAddress": "s**@service.vaude.com",
"registrationNumber": "HRA 631071",
"vatNumber": "DE203894755",
"impressumUrl": "https://www.vaude.com/de/de/impressum.html",
"agentConfidenceScore": 95
},
"creditsUsed": "10",
"error": null
}
]

Comience por los nombres. Trigema es la etiqueta del proveedor en la entrada de Python, mientras que Trigema W. Grupp KG es la razón social extraída del Impressum. La misma distinción aparece con VAUDE: la etiqueta de entrada es VAUDE y la empresa devuelta es VAUDE Sport GmbH & Co. KG. Conservar ambos valores le permite mantener el nombre reconocible que utiliza su equipo y, al mismo tiempo, añadir la entidad legal que figura en el sitio web de la empresa. Esto resulta especialmente útil al comparar el registro de un proveedor con una factura, un contrato u otro conjunto de datos empresariales que pueda utilizar la razón social completa.

Los campos devueltos responden a distintas necesidades de investigación:

  • firstName y lastName contienen el nombre del director gerente o fundador extraído de la página, cuando se encuentra. En este caso son Wolfgang Grupp y Antje von Dewitz.
  • postalAddress proporciona la dirección comercial extraída de la página legal, mientras que los campos de email y teléfono incluyen los datos de contacto publicados allí.
  • registrationNumber y vatNumber conservan los identificadores mostrados en la página. Para Trigema son HRA 740365 y DE144846566; para VAUDE, HRA 631071 y DE203894755. Estos valores concretos pueden compararse con los identificadores que ya tenga guardados en sus datos de proveedores.
  • impressumUrl identifica la página utilizada para la extracción. Es distinta de la página de inicio enviada: una registra la empresa desde la que comenzó y la otra, la fuente de los datos legales de la compañía.

Ambos registros tienen status: success y consumieron 10 créditos. agentConfidenceScore es una señal de 0 a 100 que le ayuda a priorizar la revisión; no representa un porcentaje de precisión. Los campos de salida pueden quedar vacíos si un dato no aparece en la página o no se puede extraer. Por eso, conserve el estado del elemento y abra la URL del Impressum devuelta cuando un dato sea importante para el siguiente paso.

La salida documentada también puede incluir el género, el número de teléfono y otros datos de contacto. Consulte la documentación de la API Impressum Scraper para conocer el esquema actual.

Convierta la salida en registros de proveedores

La llamada directa a la API ya funciona. Ahora puede situarla en el contexto de una tarea de investigación de proveedores. El descubrimiento o onboarding de proveedores puede proporcionarle un ID estable, el nombre corto que utiliza su equipo y una página de inicio. El resultado del Impressum añade la entidad legal detrás de ese sitio web, sus identificadores y datos de contacto publicados, así como la página donde aparecieron esos valores.

El siguiente fragmento indexa los resultados por inputId y crea registros locales de investigación empresarial. Añádalo después de la llamada a scrape_impressums() en el script completo:

python
results_by_id = {
result["inputId"]: result for result in impressum_results
}
company_research = []
for supplier in suppliers:
result = results_by_id[supplier["id"]]
company_research.append(
{
"supplier_id": supplier["id"],
"supplier_label": supplier["label"],
"website_url": supplier["website_url"],
"status": result["status"],
"outputs": result.get("outputs", {}),
"credits_used": result["creditsUsed"],
"error": result.get("error"),
}
)
print(json.dumps(company_research, indent=2, ensure_ascii=False))

En el caso de Trigema, el registro conserva supplier-trigema, la etiqueta visible Trigema y https://www.trigema.de. El objeto anidado outputs añade Trigema W. Grupp KG, su dirección e identificadores, el nombre devuelto de Wolfgang Grupp y la URL del Impressum de origen. El registro de VAUDE sigue la misma cadena: parte de la etiqueta VAUDE y su página de inicio para llegar a VAUDE Sport GmbH & Co. KG y su propia página de origen. Así puede comparar o agrupar registros por entidad legal sin perder la identidad original del proveedor que inició la investigación.

El registro mantiene unidos los datos devueltos, el estado correcto de la API, el consumo de 10 créditos y el valor público del error, junto con el ID, la etiqueta y el sitio web del proveedor.

La regla de combinación importante es la búsqueda en el diccionario mediante el ID del proveedor. Así se sigue vinculando el resultado correcto aunque la API devuelva VAUDE antes que Trigema. El fragmento también conserva en company_research los resultados de elementos que no se han procesado correctamente, ya que no filtra por estado. Un elemento con no_result o error permanece disponible con su ID y su error, en lugar de desaparecer de la cola de revisión.

Este código prepara registros de investigación locales. Puede serializar la lista o enviarla a su propio código downstream sin realizar otra llamada a la API.

Calcule el coste de la API

Impressum Scraper consume una cantidad fija de 10 créditos por cada sitio web enviado. Los dos sitios web del ejemplo consumieron 20 créditos en total. Con la misma tarifa, 1.000 sitios web consumen 10.000 créditos.

El plan Growth ofrece acceso a la REST API e incluye créditos en la suscripción. Las recargas opcionales permiten añadir más créditos cuando los necesite. El acceso al plan, los créditos incluidos y la compra de recargas son componentes distintos del coste, así que consulte los precios actuales de Datablist antes de planificar una ejecución de mayor tamaño.

Loading pricing…

Resuelva problemas sin repetir tareas de pago

El script se detiene antes de enviar una solicitud

Si falta DATABLIST_API_KEY, el script genera el error Set DATABLIST_API_KEY before running this script. Exporte la variable en el mismo terminal y vuelva a ejecutar el archivo:

shell
export DATABLIST_API_KEY="your-personal-api-key"
python scrape_impressum.py

La API rechaza la solicitud

response.raise_for_status() detiene la ejecución cuando se produce un error HTTP. Compruebe que ha proporcionado una Personal API Key válida y que su cuenta dispone de acceso a la REST API. Este caso es distinto al de una variable ausente: un valor no válido sí llega a la API y recibe una respuesta HTTP.

La tarea falla o se detiene

El error generado contiene el ID y el estado de la tarea. Inspeccione esa tarea existente, sus resultados y sus campos de créditos antes de crear otra. Una tarea con estado failed o stopped puede conservar resultados y consumo de créditos, por lo que repetirla inmediatamente podría duplicar un trabajo de pago.

Un resultado está incompleto

Una tarea completada puede contener elementos con no_result, error o campos de salida incompletos. Conserve el inputId, el status, el impressumUrl cuando esté disponible y el error público del registro. Compruebe que la entrada sea la página de inicio o el dominio raíz de la propia empresa y, después, inspeccione el sitio antes de decidir si merece la pena realizar otra consulta.

La documentación sobre tareas explica con más detalle los estados, la paginación de resultados, el historial de tareas, los límites y la retención.

Próximos pasos

Ahora dispone de una integración ejecutable con Python Requests que envía sitios web de empresas alemanas, espera a que termine la tarea de Impressum Scraper, recupera todas las páginas de resultados y conserva los datos empresariales estructurados junto con sus URLs de origen en registros locales de investigación de proveedores.

Sustituya los dos proveedores de ejemplo por sus propios IDs estables y URLs de sitios web. Después, revise cada impressumUrl devuelto antes de utilizar los campos extraídos en su proceso downstream. Puede descargar el ejemplo síncrono con Requests que se mantiene actualizado o pasar al ejemplo asíncrono con HTTPX del repositorio cuando necesite concurrencia no bloqueante.