Cómo scrapear Pinterest Pins y Boards en 2026: Guía para desarrolladores

Guía técnica para scrapear pins, boards y resultados de búsqueda públicos de Pinterest con proxies residenciales rotativos. Incluye ejemplos en Python y Node.js, paginación por cursor y mejores prácticas éticas.

How to Scrape Pinterest Pins and Boards in 2026: A Developer's Guide

Aviso legal: Este artículo cubre únicamente el acceso a datos públicos de Pinterest. Antes de extraer cualquier dato, revisa los Términos de Servicio de Pinterest. En EE. UU., la Computer Fraud and Abuse Act (CFAA) penaliza el acceso no autorizado a sistemas informáticos. En la UE, el RGPD (GDPR) regula el tratamiento de datos personales. Si el dato requiere login o contiene información personal, usa la API oficial de Pinterest v5 en lugar de scraping.

Si has intentado scrapear Pinterest en 2026, probablemente te topaste con bloqueos de IP, páginas vacías renderizadas en JavaScript y respuestas truncadas. Pinterest es una plataforma visual con más de 500 millones de usuarios activos mensuales, y su arquitectura combina renderizado dinámico con endpoints internos JSON que no están documentados públicamente. Esta guía explica cómo construir un Pinterest scraper robusto orientado a datos públicos —pins, boards y resultados de búsqueda— usando proxies residenciales rotativos, y cuándo conviene recurrir a la API oficial.

Cómo scrapear Pinterest Pins y Boards en 2026: el panorama técnico

Pinterest funciona como una SPA (Single Page Application) construida sobre React. Cuando un usuario navega, el navegador no recibe HTML estático con los pins; en su lugar, la app JS realiza llamadas XHR a endpoints internos conocidos como Resource API. Estos endpoints devuelven JSON estructurado con toda la información del pin o board. El reto para cualquier Pinterest API scraping es que estos endpoints requieren headers específicos, tokens CSRF y están protegidos por sistemas de puntuación anti-bot que limitan el número de requests por IP en ventanas de tiempo cortas.

Antes de profundizar, es crucial distinguir entre las superficies accesibles y las que no lo son:

SuperficieAcceso¿Scraping viable?
Pin público (URL /pin/ID/)Sin loginSí, datos del pin visibles
Board público (URL /board/...)Sin loginSí, feed de pins del board
Resultados de búsquedaSin loginSí, pero localizado por IP
Home feed personalizadoRequiere loginNo — usa API oficial
Estadísticas de cuenta propiaRequiere loginNo — usa API v5

API oficial de Pinterest v5 vs scraping

Pinterest ofrece una API REST oficial v5 con endpoints para obtener pins, boards y analíticas de cuentas propias. Sin embargo, esta API está diseñada principalmente para gestores de cuentas y anunciantes. Limitaciones clave:

  • Requiere autenticación OAuth 2.0 con una cuenta de Pinterest Developer.
  • El endpoint /v5/boards/{board_id}/pins devuelve solo los pins de tus propios boards, no de cualquier board público.
  • No existe un endpoint de búsqueda pública de pins de terceros.
  • Rate limits documentados de aproximadamente 1,000 requests por minuto por token, con cuotas diarias adicionales.

Para casos de uso como análisis de tendencias visuales, investigación de mercados o construcción de datasets de imágenes públicas —donde necesitas acceder a boards y pins de cualquier usuario público— el scraping de superficies públicas sigue siendo la opción práctica. La API v5 no cubre este caso.

La Resource API interna de Pinterest

Pinterest expone sus datos a través de endpoints bajo el path /resource/. Cada recurso tiene un nombre (PinResource, BoardFeedResource, SearchResource) y se invoca con una petición GET que incluye dos parámetros clave en la URL:

  • source_url=: la URL amigable que el usuario vería en el navegador, codificada en formato URL. Por ejemplo, para un board: source_url=%2Fusuario%2Fboard-slug%2F.
  • data=: un objeto JSON codificado como URL con los parámetros de la consulta, incluyendo el cursor de paginación (bookmarks).

Endpoints principales

PinResource: Devuelve los datos de un pin individual.

GET /resource/PinResource/get/?source_url=%2Fpin%2F1234567890%2F&data=%7B%22options%22%3A%7B%22id%22%3A%221234567890%22%2C%22field_set_key%22%3A%22unauth_react_main_pin%22%7D%7D

BoardFeedResource: Devuelve los pins de un board público con paginación por cursor.

GET /resource/BoardFeedResource/get/?source_url=%2Fusuario%2Fboard-slug%2F&data=%7B%22options%22%3A%7B%22board_id%22%3A%22BOARD_ID%22%2C%22page_size%22%3A25%2C%22bookmarks%22%3A%5B%5D%7D%7D

SearchResource: Devuelve resultados de búsqueda de pins. Los resultados están localizados según la IP del solicitante.

GET /resource/BaseSearchResource/get/?source_url=%2Fsearch%2Fpins%2F%3Fq%3Dminimalist%2520interior&data=%7B%22options%22%3A%7B%22query%22%3A%22minimalist%20interior%22%2C%22bookmarks%22%3A%5B%5D%7D%7D

Headers requeridos

Las peticiones a la Resource API deben incluir headers específicos o serán rechazadas:

HeaderPropósito
X-Pinterest-PWS-HandlerIdentifica el handler del frontend (ej. www/[username]/[slug].js)
X-APP-VERSIONVersión de la app JS actual; cambia con cada deploy
csrftokenToken CSRF extraído de la cookie inicial
Acceptapplication/json, text/javascript, */*; q=0.01
User-AgentDebe coincidir con un navegador real moderno

El csrftoken se obtiene de la cookie csrftoken que Pinterest establece en la primera petición a cualquier página pública. Es esencial mantener la misma sesión (mismo conjunto de cookies) entre la petición inicial y las llamadas a la Resource API.

Realidad anti-bot: por qué necesitas proxies residenciales

Pinterest aplica un sistema de puntuación anti-bot que combina varios signals: tasa de requests por IP, patrón de navegación, headers, TLS fingerprint y comportamiento de cursor. Cuando una IP supera un umbral de requests —típicamente en el orden de 50–100 requests por minuto para IPs de datacenter— Pinterest responde con HTTP 429, páginas vacías o un desafío de seguridad intersticial.

Los proxies de datacenter (AWS, DigitalOcean, OVH) son detectados rápidamente porque Pinterest utiliza bases de datos de rangos IP comerciales. Los rangos ASN de proveedores cloud conocidos son marcados como sospechosos por defecto.

Los proxies residenciales ofrecen IPs asignadas a proveedores de ISP reales (Comcast, AT&T, Movistar, Vodafone), lo que los hace indistinguibles de usuarios legítimos a nivel de ASN. Esto es crítico para Pinterest por dos razones:

  1. Rate limits por IP: Con rotación de IPs residenciales, distribuyes tus requests entre cientos o miles de IPs, manteniendo cada IP por debajo del umbral de detección.
  2. Localización de resultados: Los resultados de búsqueda y las recomendaciones de Pinterest están localizados por IP. Una búsqueda de "muebles de diseño" desde una IP en Madrid devuelve resultados diferentes a una IP en Ciudad de México. Si necesitas datos de un mercado específico, debes usar proxies con geo-targeting.

Consulta las ubicaciones de proxies disponibles en ProxyHat para verificar cobertura por país.

Configuración de ProxyHat para scraping de Pinterest

ProxyHat proporciona proxies residenciales rotativos accesibles vía un gateway HTTP/SOCKS5 unificado. La autenticación se realiza en el formato estándar usuario:contraseña@host:puerto, y los parámetros de geo-targeting y sesión se pasan dentro del nombre de usuario.

Parámetros clave

  • Geo-targeting por país: user-country-US:pass@gate.proxyhat.com:8080
  • Geo-targeting por ciudad: user-country-DE-city-berlin:pass@gate.proxyhat.com:8080
  • Sesión sticky: user-session-abc123:pass@gate.proxyhat.com:8080 — mantiene la misma IP de salida entre requests.
  • Combinado: user-country-US-session-abc123:pass@gate.proxyhat.com:8080

Para más detalles sobre configuración, consulta la documentación oficial de ProxyHat.

Ejemplo 1: Scrapear BoardFeedResource con Python

Este ejemplo pagina los pins de un board público usando la Resource API de Pinterest a través del gateway HTTP de ProxyHat en el puerto 8080. Usa una sesión sticky para mantener el csrftoken entre peticiones.

import requests
import json
import urllib.parse
import time

# Credenciales ProxyHat — residencial, EE. UU., sesión sticky
PROXY = "http://user-country-US-session-pint01:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY, "https": PROXY}

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Language": "en-US,en;q=0.9",
    "X-Pinterest-PWS-Handler": "www/[username]/[slug].js",
    "X-APP-VERSION": "c8f5c1a",
    "Referer": "https://www.pinterest.com/",
}

BOARD_URL = "/usuario/board-slug/"
BOARD_ID = "1234567890123456789"

def fetch_board_pins(board_id, max_pages=10):
    session = requests.Session()
    session.proxies = PROXIES
    session.headers.update(HEADERS)

    # 1. Visitar la página del board para obtener cookies y csrftoken
    board_page = session.get(f"https://www.pinterest.com{BOARD_URL}")
    csrf = session.cookies.get("csrftoken", "")
    session.headers["X-CSRFToken"] = csrf

    bookmarks = []
    all_pins = []

    for page in range(max_pages):
        data_param = json.dumps({
            "options": {
                "board_id": board_id,
                "page_size": 25,
                "bookmarks": bookmarks,
                "current_url": BOARD_URL,
            }
        })
        encoded_data = urllib.parse.quote(data_param)
        encoded_source = urllib.parse.quote(BOARD_URL)

        api_url = (
            f"https://www.pinterest.com/resource/BoardFeedResource/get/"
            f"?source_url={encoded_source}&data={encoded_data}"
        )

        resp = session.get(api_url)
        if resp.status_code == 429:
            print(f"Rate limited en página {page}. Esperando 60s...")
            time.sleep(60)
            continue
        if resp.status_code != 200:
            print(f"Error HTTP {resp.status_code} en página {page}")
            break

        payload = resp.json()
        resource_resp = payload.get("resource_response", {})
        pins = resource_resp.get("data", [])
        bookmarks = resource_resp.get("bookmark", [])

        for pin in pins:
            all_pins.append({
                "id": pin.get("id"),
                "title": pin.get("title") or pin.get("grid_title", ""),
                "image_url": pin.get("images", {}).get("orig", {}).get("url", ""),
                "link": pin.get("link", ""),
            })

        if not bookmarks or bookmarks == [""]:
            print("No hay más páginas.")
            break

        # Pacing: 2-3 segundos entre páginas
        time.sleep(2.5)

    return all_pins

pins = fetch_board_pins(BOARD_ID, max_pages=5)
print(f"Total pins extraídos: {len(pins)}")
for p in pins[:3]:
    print(json.dumps(p, indent=2, ensure_ascii=False))

Salida esperada (pin truncado):

{
  "id": "9876543210987654321",
  "title": "Ideas de decoración minimalista",
  "image_url": "https://i.pinimg.com/736x/ab/cd/ef/abcdef123456.jpg",
  "link": "https://example.com/blog/minimalist-decor"
}

Ejemplo 2: Scrapear resultados de búsqueda con Node.js

Este ejemplo usa el gateway HTTP de ProxyHat en el puerto 8080 para buscar pins públicos y extraer los campos relevantes.

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const PROXY_URL = 'http://user-country-US-session-pint02:PASSWORD@gate.proxyhat.com:8080';
const agent = new HttpsProxyAgent(PROXY_URL);

const HEADERS = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  'Accept': 'application/json, text/javascript, */*; q=0.01',
  'Accept-Language': 'en-US,en;q=0.9',
  'X-Pinterest-PWS-Handler': 'www/search/[scope].js',
  'X-APP-VERSION': 'c8f5c1a',
  'Referer': 'https://www.pinterest.com/',
};

async function searchPins(query, maxPages = 5) {
  const client = axios.create({
    httpsAgent: agent,
    headers: HEADERS,
    timeout: 30000,
  });

  // Obtener cookies iniciales
  const initial = await client.get('https://www.pinterest.com/search/pins/?q=' + encodeURIComponent(query));
  const setCookie = initial.headers['set-cookie'] || [];
  const csrfMatch = setCookie.find(c => c.startsWith('csrftoken='));
  const csrf = csrfMatch ? csrfMatch.split('=')[1].split(';')[0] : '';

  const sourceUrl = `/search/pins/?q=${encodeURIComponent(query)}`;
  let bookmarks = [];
  const allPins = [];

  for (let page = 0; page < maxPages; page++) {
    const dataParam = encodeURIComponent(JSON.stringify({
      options: { query, bookmarks, scope: 'pins' }
    }));
    const encodedSource = encodeURIComponent(sourceUrl);

    const apiUrl = `https://www.pinterest.com/resource/BaseSearchResource/get/?source_url=${encodedSource}&data=${dataParam}`;

    const resp = await client.get(apiUrl, {
      headers: { ...HEADERS, 'X-CSRFToken': csrf }
    });

    const resourceResp = resp.data.resource_response || {};
    const pins = resourceResp.data || [];
    bookmarks = resourceResp.bookmark || [];

    for (const pin of pins) {
      allPins.push({
        id: pin.id,
        title: pin.title || pin.grid_title || '',
        image_url: pin.images?.orig?.url || '',
        link: pin.link || '',
      });
    }

    if (!bookmarks.length || bookmarks[0] === '') break;
    await new Promise(r => setTimeout(r, 2500));
  }

  return allPins;
}

(async () => {
  const pins = await searchPins('minimalist interior design', 3);
  console.log(`Pins encontrados: ${pins.length}`);
  console.log(JSON.stringify(pins.slice(0, 3), null, 2));
})();

Paginación por cursor, sesiones sticky y pacing

Bookmark/cursor pagination

Pinterest usa un sistema de paginación por cursor opaco. La respuesta de cada Resource API incluye un campo bookmark (a veces llamado bookmarks) que es un array de strings. Para obtener la siguiente página, debes pasar ese array en el campo options.bookmarks de la siguiente petición. Cuando el array está vacío o contiene un string vacío, no hay más resultados.

Los bookmarks son opacos: no son offsets numéricos ni IDs secuenciales. Son tokens generados por el servidor que codifican el estado de la paginación. Nunca intentes modificarlos o construirlos manualmente.

Sesión sticky para continuidad de csrftoken

El csrftoken está vinculado a la sesión de cookies. Si tu proxy rota la IP entre la petición inicial (que obtiene el token) y las llamadas a la Resource API, Pinterest puede invalidar la sesión. Por eso es crucial usar el flag -session- en ProxyHat para mantener la misma IP durante todo el flujo:

# Sesión sticky con geo US
http://user-country-US-session-mi-sesion-01:PASSWORD@gate.proxyhat.com:8080

Cuando termines de scrapear un board o búsqueda completa, puedes cambiar el identificador de sesión para rotar a una nueva IP y empezar el siguiente objetivo con una sesión limpia.

Pacing y rate limiting

Incluso con proxies residenciales, el pacing es esencial. Recomendaciones prácticas:

  • 2–3 segundos entre cada página de resultados (request a la Resource API).
  • 5–10 segundos de pausa si recibes un HTTP 429.
  • Máximo 50 requests por minuto por sesión/IP para mantener un perfil de navegación humano.
  • Rotar el identificador de sesión (-session-) cada 100–200 requests para cambiar de IP y reducir la acumulación de señales anti-bot.

User-Agent y fingerprint hygiene

El User-Agent debe ser un navegador real moderno y consistente con el resto de headers. Reglas:

  • Usa un UA de Chrome o Firefox actualizado (no uses UA de bots o librerías).
  • Mantén el mismo UA durante toda la sesión.
  • Incluye Accept-Language coherente con el geo del proxy (ej. es-ES,es;q=0.9 para IPs en España).
  • No rotes UAs entre requests de la misma sesión — eso es una señal de bot obvia.
  • Considera usar curl_cffi en Python para imitar el TLS fingerprint de Chrome a nivel de handshake, ya que Pinterest puede inspeccionar el JA3/JA4.

Errores comunes y edge cases

<
ProblemaCausa probableSolución
Respuesta JSON vacía o resource_response.data = []IP bloqueada o session expiradaRotar sesión (-session-) y re-obtener csrftoken
HTTP 403 ForbiddenHeaders incompletos o X-APP-VERSION desactualizadoVisitar la página pública y copiar el X-APP-VERSION actual del HTML
HTTP 429 Too Many RequestsRate limit por IP excedidoAumentar pacing, rotar IP, reducir concurrencia
Bookmarks siempre vacíosBoard sin más pins o query sin resultadosVerificar que el board_id es correcto y público
Página de seguridad intersticialPuntuación anti-bot altaCambiar a IP residencial de otro país, reducir velocidad

Scraping ético y cuándo usar la API oficial

El scraping de Pinterest debe limitarse a datos públicos, no personales: metadatos de pins (título, descripción, imagen, enlace), boards públicos y resultados de búsqueda agregados. No extraigas:

  • Datos de usuarios que requieren login para ver (perfiles privados, boards secretos).
  • Información personal identificable más allá de lo visible públicamente.
  • Datos de analíticas o métricas de cuentas de terceros.

Respeta el archivo robots.txt de Pinterest. Aunque los endpoints de la Resource API no siempre están listados en robots.txt, las URLs de boards y pins sí lo están. Si robots.txt prohíbe un path, no lo scrapees.

Cuándo preferir la API oficial v5

  • Producción estable: Si necesitas datos de tus propias cuentas o boards gestionados, la API v5 es más fiable y no viola ToS.
  • Datos de analíticas: La API v5 ofrece endpoints de analíticas de pins y campañas que no están disponibles vía scraping público.
  • Escritura de datos: Crear pins, boards o gestionar cuentas requiere la API oficial — el scraping es solo lectura.
  • Cumplimiento corporativo: Si tu organización requiere auditoría y cumplimiento de ToS, la API oficial es la única opción respaldada por Pinterest.

Para más información sobre casos de uso de scraping con proxies, consulta nuestra guía de web scraping y la página de precios de ProxyHat. Si necesitas tracking de resultados de motores de búsqueda, también tenemos un caso de uso sobre SERP tracking.

Puntos clave

1. Datos públicos solamente: Scrapea pins, boards y búsquedas públicas. Cualquier dato detrás de login requiere la API oficial v5.

2. La Resource API es el camino: Los endpoints /resource/ devuelven JSON estructurado, pero requieren headers específicos y csrftoken válido.

3. Proxies residenciales con geo: Pinterest localiza resultados por IP. Usa -country-US o el mercado que necesites. Los proxies de datacenter son bloqueados rápidamente.

4. Sesión sticky para csrftoken: Mantén la misma IP durante todo el flujo con -session- para evitar invalidación de sesión.

5. Pacing y fingerprint: 2–3 segundos entre páginas, UA consistente, rotación de sesión cada 100–200 requests.

¿Listo para empezar?

Accede a más de 50M de IPs residenciales en más de 148 países con filtrado impulsado por IA.

Ver preciosProxies residenciales
← Volver al Blog