Volver al blog

Dify + Scrapeless: Ofrezca a sus Agentes Datos Web en Vivo Con una Herramienta Personalizada

Emily Chen
Emily Chen

Advanced Data Extraction Specialist

20-Aug-2026

TL;DR:

  • El plugin Deep SerpApi en el Marketplace de Dify expone exactamente una herramienta con un parámetro, query, por lo que cualquier solicitud que necesite un resultado vertical, un desplazamiento de página o un sitio diferente tiene que venir de otro lugar.
  • Una herramienta personalizada es un archivo OpenAPI. Dify lo analiza en una sola operación, scraperRequest, que alcanza a toda la familia de actores Scrapeless scraper.* a través de un único endpoint.
  • Dify precompleta dos campos de autenticación con valores que esta API rechaza: el nombre del encabezado se establece de manera predeterminada en Authorization y el prefijo del encabezado se establece de manera predeterminada en Basic. Cualquiera de los valores por defecto devuelve 401 con {"code":14404,"message":"invalid access token"}.
  • Dify tipa el objeto anidado input como un parámetro string, por lo que un nodo de código que emite texto JSON es la forma confiable de construirlo dentro de un flujo de trabajo.
  • Una llamada al producto de Amazon devuelve aproximadamente 2.2 MB, de los cuales 1.9 MB son html en bruto. Selecciona result en un nodo de código antes de que la carga útil llegue a un modelo.
  • Una cuenta gratuita de Scrapeless cubre cada solicitud en esta guía.

Un agente de Dify sin herramienta web responde con sus pesos de modelo y lo que hayas subido a su base de conocimientos. Pregúntale por las páginas de más alto rango de hoy, el precio actual de un competidor o los fontaneros que operan en una ciudad específica, y producirá algo fluido y obsoleto.

Dify resuelve eso con herramientas, y hay dos formas de agregar una. Esta guía cubre la segunda: una herramienta personalizada construida a partir de un archivo OpenAPI, que convierte la Scrapeless Scraping API en una acción llamable en cada agente y flujo de trabajo en tu espacio de trabajo.

Lo que agrega una herramienta personalizada que el plugin no hace

El oficial listado de Deep SerpApi en el Marketplace de Dify expone una herramienta con un único parámetro requerido, query, y un campo de credencial para la clave de la API. Si una simple consulta de Google es todo lo que necesita tu flujo de trabajo, instálalo y deja de leer: son dos clics y funciona, y el monitor de noticias empresariales construido sobre Dify muestra un flujo de trabajo completo ensamblado alrededor de él.

El endpoint HTTP de Scrapeless detrás de él acepta considerablemente más que una cadena de consulta. La misma forma de solicitud selecciona el paquete local en lugar de resultados web, se desplaza a la segunda página de esos resultados o cambia completamente a un listado de Amazon. Ninguna de esas opciones es accesible a través de un único campo query.

Una herramienta personalizada cierra esa brecha. Pegas un documento OpenAPI, Dify lee las operaciones de él, y toda la familia de actores se convierte en una herramienta adjuntable. No hay nada que instalar y nada que desplegar, y el mismo archivo funciona en Dify Cloud y en una instancia auto-alojada.

Lo que devuelve la API de Scraping

Un endpoint toma cada solicitud: POST https://api.scrapeless.com/api/v1/scraper/request. El cuerpo lleva dos campos: actor nombra el scraper, y input lleva los parámetros de ese scraper.

La respuesta es JSON analizado en lugar de HTML. Una llamada a scraper.google.search coloca organic_results en el nivel superior junto a metadata, pagination, y search_information. Agregar tbm: lcl al mismo actor sustituye eso por local_results.places, el bloque de negocios con calificaciones, números de teléfono y direcciones. Una llamada a scraper.amazon anida el producto analizado bajo result.

Ese diseño de forma única es lo que hace que una operación OpenAPI sea suficiente. Los detalles de los parámetros de cada actor viven en la documentación de la API de Scraping.

Prerrequisitos

  • Un espacio de trabajo Dify — Cloud, o auto-alojado en 1.0.0 o posterior. El comportamiento descrito aquí se midió en una instancia auto-alojada 1.16.1.
  • Una clave de API de Scrapeless del panel de control.
  • Permiso en el espacio de trabajo para agregar herramientas. Dify restringe los endpoints de herramientas personalizadas a administradores y propietarios del espacio de trabajo.

Paso 1: Importar el esquema OpenAPI

En Dify, abre Herramientas → Personalizado → Crear herramienta personalizada y pega el documento a continuación. Es válido según la especificación OpenAPI 3.0.3, que es la versión que espera el analizador de Dify.

yaml Copy
openapi: 3.0.3
info:
  title: Scrapeless Scraper API
  version: "1.0.0"
servers:
  - url: https://api.scrapeless.com
paths:
  /api/v1/scraper/request:
    post:
      operationId: scraperRequest
      summary: Run a scraper actor and return structured data
      security:
        - ApiTokenAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [actor, input]
              properties:
                actor:
                  type: string
                  description: Which scraper to run.
                  enum: [scraper.google.search, scraper.amazon]
                  example: scraper.google.search
                input:
                  type: object
                  description: Actor parameters. Keys depend on the actor.
                  additionalProperties: true
            examples:
              googleSearch:
                summary: Google SERP
                value:
                  actor: scraper.google.search
                  input:
                    q: web scraping api
              googleLocalPack:
                summary: Google local pack
                value:
                  actor: scraper.google.search
                  input:
                    q: plumbers in Austin, TX
                    tbm: lcl
              amazonProduct:
                summary: Amazon product by URL
                value:
                  actor: scraper.amazon
                  input:
                    action: product
                    url: https://www.amazon.com/dp/B09B8V1LZ3
      responses:
        '200':
          description: Parsed result. Shape depends on the actor.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
components:
  securitySchemes:
    ApiTokenAuth:
      type: apiKey
      in: header
      name: x-api-token

Dify analiza eso en exactamente una herramienta. El nombre proviene de operationId, por lo que la herramienta se llama scraperRequest, y toma dos parámetros: actor y input. Los tres ejemplos nombrados aparecen en el generador de solicitudes, lo que ahorra escribir la URL de Amazon a mano.

Paso 2: Completa los cuatro campos de autenticación

Elige autenticación API Key y establece cada campo. Dos de los cuatro llegan pre-completados con valores que esta API rechaza:

Campo Qué establecer Qué pre-completa Dify
Tipo de autenticación API Key (almacenado como api_key_header) None
Nombre del encabezado x-api-token Authorization
Valor Tu clave de API de Scrapeless vacío
Prefijo del encabezado Custom Basic

El campo del prefijo es el que confunde a la gente. Dify lo concatena al valor, así que dejarlo en Basic envía el encabezado x-api-token: Basic <your-key>. Eso no es lo que el esquema de autenticación HTTP Básica significa; una credencial Básica real es un par user:password codificado en base64, y Scrapeless espera la clave desnuda, por lo que la solicitud es rechazada. Bearer falla de la misma manera. Solo Custom pasa el valor sin tocar.

Dejar el nombre del encabezado en Authorization falla de la misma manera, por la misma razón: la clave nunca llega al encabezado que lee la API.

Ambos errores producen una respuesta, y puedes reproducir cualquiera desde un terminal antes de tocar Dify:

bash Copy
# Correct: bare key in x-api-token
curl -s -o /dev/null -w 'bare key      -> %{http_code}\n' \
  -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"}}'

# What Dify sends with the default prefix
curl -s -w '\nBasic prefix  -> %{http_code}\n' \
  -X POST https://api.scrapeless.com/api/v1/scraper/request \
  -H "Content-Type: application/json" \
  -H "x-api-token: Basic $SCRAPELESS_API_KEY" \
  -d '{"actor":"scraper.google.search","input":{"q":"web scraping api"}}'

# What Dify sends with the default header name
curl -s -w '\nAuthorization -> %{http_code}\n' \
  -X POST https://api.scrapeless.com/api/v1/scraper/request \
  -H "Content-Type: application/json" \
  -H "Authorization: $SCRAPELESS_API_KEY" \
  -d '{"actor":"scraper.google.search","input":{"q":"web scraping api"}}'
text Copy
bare key      -> 200
{"code":14404,"message":"invalid access token"}
Basic prefix  -> 401
{"code":14404,"message":"invalid access token"}
Authorization -> 401

Un 401 aquí es el servidor diciéndote que la credencial que recibió no es una que acepte, que es exactamente lo que la especificación semántica HTTP reserva para ese estado. El cuerpo lo específica aún más: el código 14404 es específicamente un token inutilizable, no una solicitud malformada.

Paso 3: Ejecuta la Prueba Incorporada

El panel de prueba de Dify llama al endpoint con las credenciales que acabas de ingresar. Completa los dos parámetros:

json Copy
{
  "actor": "scraper.google.search",
  "input": "{\"q\": \"web scraping api\"}"
}

Una configuración que funciona devuelve aproximadamente 15 KB de JSON de SERP. Un prefijo roto devuelve una única cadena de error que lleva el cuerpo ascendente de manera literal: Request failed with status code 401 and {"code":14404,"message":"invalid access token"}.

Nota la cita en la carga de prueba. Dify aplana las propiedades anidadas del cuerpo de la solicitud, así que input se registra como un parámetro string en lugar de un objeto; el esquema analizado informa que actor y input son string, ambos requeridos. Un objeto JSON real también funciona en el panel, porque Dify normaliza cualquiera de las formas en el objeto que la API espera. Esa conversión es importante: una solicitud construida a mano contra el endpoint tiene que enviar un objeto, y una cadena allí regresa como 400 {"message":"invalid input body"}.

Guarda el proveedor una vez que la prueba devuelva datos. scraperRequest luego aparece en la lista de herramientas para cada aplicación en el espacio de trabajo.

¿Construyendo esto en un plan gratuito? Crea una cuenta de Scrapeless y las solicitudes de esta guía se ejecutan en la cuota gratuita.

Lo Que Regresa

El sobre depende del actor, y cada forma quiere un manejo diferente aguas abajo.

Búsqueda web. scraper.google.search con {"q": "web scraping api"} devolvió ocho organic_results en una respuesta de 15 KB, junto con metadata, pagination, search_information, related_searches y un bloque de inline_videos. Cada resultado lleva title, link, snippet, source, position y snippet_highlighted_words.

Paquete local. Agregar tbm: lcl reemplaza organic_results con local_results.places — 20 negocios por solicitud. Establecer start: 20 devuelve la siguiente página; en dos páginas consecutivas de una consulta, 37 de los 40 registros fueron distintos, por lo que un flujo que almacena ambas páginas debería basarse en algo estable en lugar de asumir que no hay repeticiones.

Los campos del paquete local necesitan un pase de limpieza antes de llegar a un CRM o una hoja de cálculo:

  • phone, type y hours llegan con un espacio inicial, y algunas cadenas de horas usan un espacio no separable estrecho en lugar de uno normal.
  • phone tenía un valor en forma de teléfono en 15 de 20 registros en una captura; el resto llevaba horarios de apertura o una etiqueta de servicio como Online estimates.
  • place_id, place_id_search, lsig y thumbnail estaban vacíos en todos los 20 registros.
  • gps_coordinates está presente pero lee {"latitude": 0, "longitude": 0}, por lo que pasa una verificación de veracidad mientras no lleva una ubicación.

Amazon. scraper.amazon con action: product devolvió 2,226,755 bytes. El producto analizado bajo result es de 4,608 bytes en 63 campos; los 1,960,588 bytes restantes son los html crudos de la lista. Pasar toda esa carga a un modelo es costoso e innecesario.

Recorta la Respuesta Antes de Que Alcance el Modelo

Coloca un nodo de Código directamente después del nodo Herramienta. Se ejecuta Python 3 o JavaScript, toma la salida de la herramienta como una variable de entrada y devuelve un diccionario que los nodos posteriores leen por clave. Seleccionar campos allí no cuesta nada y mantiene pequeño el contexto del modelo:

python Copy
def main(response: dict) -> dict:
    places = (response.get("local_results") or {}).get("places") or []
    rows = []
    for place in places:
        contact = (place.get("phone") or "").strip()
        digits = sum(character.isdigit() for character in contact)
        rows.append({
            "name": (place.get("title") or "").strip(),
            "category": (place.get("type") or "").strip(),
            "rating": place.get("rating"),
            "reviews": place.get("reviews") or 0,
            "phone": contact if digits >= 10 else None,
            "note": None if digits >= 10 else contact,
            "address": (place.get("address") or "").strip(),
        })
    return {"rows": rows, "count": len(rows)}


# Local check against a live response. Leave everything below out of the Code node.
if __name__ == "__main__":
    import json, os, urllib.request

    body = json.dumps({
        "actor": "scraper.google.search",
        "input": {"q": "plumbers in Austin, TX", "tbm": "lcl"},
    }).encode()
    call = urllib.request.Request(
        "https://api.scrapeless.com/api/v1/scraper/request",
        data=body,
        headers={"Content-Type": "application/json",
                 "x-api-token": os.environ["SCRAPELESS_API_KEY"]},
    )
    with urllib.request.urlopen(call, timeout=180) as reply:
        cleaned = main(json.load(reply))

    print(cleaned["count"], "rows")
    print(json.dumps(cleaned["rows"][0], ensure_ascii=False))

El bloque anterior también sirve como un chequeo local: ejecútalo con tu clave en el entorno y obtiene un paquete local en vivo, aplica la misma función y imprime la primera fila limpia. Ten en cuenta que una llamada directa envía input como un objeto: la API responde con una cadena con 400 {"message":"invalid input body"}. Dify convierte la forma de cadena para ti en el camino, que es por eso que el mismo valor funciona en ambos lugares.

La limpieza convierte 20 registros crudos en 20 utilizables: nombres y categorías sin espacios en blanco extraños, un número real en phone cuando el campo contiene uno, y el texto de horas de apertura se traslada a note en lugar de escribirse en una columna de teléfono.

Para la forma de Amazon, el mismo nodo es una línea: return {"product": response["result"]} — y elimina el 99% de la carga útil.

Conéctalo a un Agente o a un Flujo de Trabajo

Ambas superficies utilizan la misma herramienta guardada, y la elección es sobre quién escoge los parámetros.

En un Agente, el modelo decide cuándo llamar a scraperRequest y qué poner en actor y input. Eso funciona cuando las instrucciones nombran la herramienta y la condición de los datos explícitamente:

text Copy
When a question depends on current web content, call scraperRequest with
actor "scraper.google.search" and input {"q": "<the search terms>"}, read the
organic_results, and answer from those. Do not answer from memory when the
question is about current prices, rankings, or availability.

En un Flujo de Trabajo, fijas actor en el nodo de la Herramienta y dejas que un nodo ascendente proporcione solo la consulta. Debido a que input es un parámetro de cadena, el patrón confiable es un nodo de Código que construye el texto JSON:

python Copy
def main(query: str) -> dict:
    import json
    return {"payload": json.dumps({"q": query, "tbm": "lcl"})}

Conecta payload en el campo input del nodo de la Herramienta. La propia documentación de herramientas de Dify cubre el cableado de nodos circundantes en más profundidad.

Si Alojamiento Propio de Dify

Las instancias autohospedadas dirigen el HTTP de la herramienta a través de un contenedor ssrf_proxy dedicado en lugar de permitir que el contenedor de la API acceda a internet directamente. Cuando ese servicio no está funcionando, las llamadas a la herramienta fallan con un error DNS — [Errno -3] Temporary failure in name resolution — que se lee como una URL rota en lugar de como un contenedor faltante. Inicia toda la pila de composición, no solo api y web, y la misma herramienta funciona de manera idéntica a la Nube.

El comportamiento en esta guía fue medido en una instancia autohospedada 1.16.1: el esquema se analizó en una herramienta, la prueba de credenciales devolvió 15,648 bytes de JSON de SERP con Custom como prefijo y una cadena 401 con Basic, y el proveedor guardado listó scraperRequest como una herramienta adjuntable.

Conclusión

El complemento de Marketplace cubre una cadena de consulta. Una herramienta personalizada cubre el endpoint detrás de ella, que es lo que una corriente de leads necesita una vez que comienza a leer paquetes locales, paginando a través de ellos y limpiando los campos antes de que lleguen a cualquier parte.

El costo de configuración es un archivo OpenAPI y cuatro campos de autenticación — dos de los cuales Dify completa incorrectamente por defecto. Consigue esos correctos y cada actor en la familia se vuelve disponible para cada aplicación en el espacio de trabajo, con un nodo de Código haciendo la moldura que mantiene las cargas útiles pequeñas y las columnas limpias.

¿Listo para conectarlo? Comienza con una cuenta gratuita de Scrapeless, agarra tu clave de API y pega el esquema anterior en tu espacio de trabajo. Los límites de uso y plan están listados en la página de precios de Scrapeless.

FAQ

P: ¿Debería usar el complemento Deep SerpApi o una herramienta personalizada?

Usa el complemento cuando una consulta simple de Google es todo lo que necesitas: expone una herramienta con un solo parámetro query y se necesitan dos clics para instalarlo. Usa una herramienta personalizada cuando necesites el paquete local, un desplazamiento de página, una lista de Amazon o cualquier otro actor, porque esos parámetros no son alcanzables a través de ese único campo.

P: ¿Por qué mi herramienta personalizada de Dify devuelve 401 cuando la misma clave funciona en curl?

Dos valores predeterminados de Dify envían la clave en una forma que la API no lee. El nombre de la cabecera predeterminado es Authorization en lugar de x-api-token, y el prefijo de la cabecera predeterminado es Basic, lo que hace que Dify envíe x-api-token: Basic <key>. Establece el nombre de la cabecera en x-api-token y el prefijo en Custom.

P: ¿Por qué el campo input es una cadena en lugar de un objeto?

Dify aplana las propiedades anidadas del cuerpo de la solicitud cuando analiza un documento OpenAPI, por lo que un objeto anidado se convierte en un parámetro de cadena. Dify acepta cualquiera de las formas y la normaliza antes de que la solicitud salga, por lo que un nodo de Código que emite json.dumps(...) es la forma confiable de construirlo en un Flujo de Trabajo. Una llamada directa al endpoint es más estricta y requiere un objeto.

P: ¿Esto funciona en Dify Cloud así como en autohospedado?

Sí. La herramienta personalizada es un documento OpenAPI más credenciales, sin nada que instalar en ninguno de los dos. Las instancias autohospedadas tienen un requisito adicional: el contenedor ssrf_proxy debe estar funcionando, porque el HTTP de salida de la herramienta se dirige a través de él.
Q: ¿Cuántos resultados devuelve una solicitud?

Una búsqueda web devolvió ocho resultados orgánicos en la captura utilizada para esta guía, y los recuentos de resultados varían según la consulta. El paquete local devuelve 20 lugares por solicitud, y start: 20 obtiene la siguiente página; las páginas consecutivas de una consulta se superponen ligeramente, así que se deduplican al escribir.

Q: ¿Cómo evito que la respuesta de Amazon abrume el contexto del modelo?

Selecciona result en un nodo de Código colocado después del nodo de Herramienta. Una llamada de producto devolvió 2,226,755 bytes, de los cuales 1,960,588 eran el campo html sin procesar y solo 4,608 eran el producto analizado, así que devolver {"product": response["result"]} mantiene todo lo útil y descarta el resto.

Q: ¿Puede una herramienta personalizada cubrir varios actores?

Sí, y ese es el propósito del diseño. El endpoint toma actor más input, así que una sola operación scraperRequest alcanza a cada actor al que tu cuenta tiene acceso. Agregar uno al enum en el esquema lo expone en el generador de solicitudes sin necesidad de una segunda herramienta.

Q: ¿Dónde debería vivir la clave API?

En el campo de credenciales del proveedor de la herramienta, que Dify almacena como un secreto e inyecta en el momento de la llamada. Mantenerla allí en lugar de un parámetro de nodo significa que un flujo de trabajo exportado o una aplicación duplicada no lleva la clave consigo.

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