Automatización de Pines de Pinterest para Sitios Estáticos mediante RSS y Metaetiquetas
Para integrar tu sitio con Pinterest, comienza verificando tu dominio. En el Centro de Negocios de Pinterest, elige el método de metaetiqueta e insértala en el <head> de tu página de inicio:
<meta name="p:domain_verify" content="12ac6ff1eaa70a3386sg439fda58bbb6"/>
Esto permite a Pinterest indexar páginas con Pines Enriquecidos. Luego, añade metaetiquetas al <head> de cada artículo:
<meta name="is_article" content="true">
<meta name="pinterest_description" content="Descripción del pin, 150–200 caracteres">
<meta name="pinterest_image" content="https://example.com/image.webp">
<meta name="article_published_at" content="2026-04-03T12:00:00+03:00">
La imagen debe ser vertical (1000×1500 px), servida mediante HTTPS y menor a 2 MB. Sin pinterest_image, Pinterest usa la primera <img> de la página, lo que a menudo no es óptimo.
Generación de un Feed RSS con un Script de Node.js
Pinterest analiza RSS para crear pines automáticamente. Usa un script para escanear archivos HTML, extraer metadatos y generar rss.xml.
Crea generate-rss.js en una carpeta scripts:
import fs from 'node:fs/promises';
import path from 'node:path';
import * as cheerio from 'cheerio';
// ================== CONFIGURACIÓN (PERSONALIZA ESTO) ==================
const BASE_URL = 'https://TU_SITIO.com';
const ROOT_DIR = path.resolve(process.cwd(), 'dist');
const OUTPUT_RSS_PATH = path.join(ROOT_DIR, 'rss.xml');
const CHANNEL_TITLE = 'Nombre de tu Blog';
const CHANNEL_DESCRIPTION = 'Descripción: artículos sobre desarrollo, SEO, diseño';
// ================== NO MODIFIQUE A PARTIR DE AQUÍ ==================
function escapeXml(value = '') {
return value
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function getMimeTypeByExt(urlOrPath = '') {
const ext = urlOrPath.split('.').pop()?.toLowerCase();
switch (ext) {
case 'jpg': case 'jpeg': return 'image/jpeg';
case 'png': return 'image/png';
case 'webp': return 'image/webp';
case 'gif': return 'image/gif';
default: return 'image/*';
}
}
function buildArticleUrl(filePath) {
const relativePath = path.relative(ROOT_DIR, filePath).replace(/\\/g, '/');
return `${BASE_URL}/${relativePath}`;
}
function buildImageUrl(src) {
if (!src) return '';
if (/^https?:\/\//i.test(src)) return src;
if (src.startsWith('/')) return `${BASE_URL}${src}`;
return `${BASE_URL}/${src}`;
}
async function collectHtmlFiles(dir) {
const entries = await fs.readdir(dir, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
const nested = await collectHtmlFiles(fullPath);
files.push(...nested);
} else if (entry.isFile() && entry.name.endsWith('.html')) {
files.push(fullPath);
}
}
return files;
}
async function parseArticle(filePath) {
const content = await fs.readFile(filePath, 'utf8');
const $ = cheerio.load(content);
const isArticle = $('meta[name="is_article"]').length > 0;
if (!isArticle) return null;
const title = $('h1').first().text().trim() || 'Sin Título';
const pinterestDescription = $('meta[name="pinterest_description"]').attr('content')?.trim() || '';
const pinterestImg = $('meta[name="pinterest_image"]').attr('content');
let firstImgSrc = $('img').first().attr('src') || '';
if (firstImgSrc.endsWith('.svg')) firstImgSrc = '';
const imageUrl = buildImageUrl(pinterestImg || firstImgSrc);
let pubDate;
const articleDateMeta = $('meta[name="article_published_at"]').attr('content');
if (articleDateMeta) {
const parsed = new Date(articleDateMeta);
if (!isNaN(parsed.getTime())) pubDate = parsed;
}
if (!pubDate) {
const stat = await fs.stat(filePath);
pubDate = stat.mtime;
}
return { title, pinterestDescription, url: buildArticleUrl(filePath), imageUrl, pubDate };
}
function buildRssXml(items) {
const itemsXml = items.map(item => {
const enclosure = item.imageUrl ? `\n <enclosure url="${escapeXml(item.imageUrl)}" type="${getMimeTypeByExt(item.imageUrl)}" />` : '';
return `\n <item>\n <title>${escapeXml(item.title)}</title>\n <link>${escapeXml(item.url)}</link>\n <description><![CDATA[${item.pinterestDescription}]]></description>\n <pubDate>${item.pubDate.toUTCString()}</pubDate>${enclosure}\n </item>`;
}).join('\n');
return `<?xml version="1.0" encoding="UTF-8"?>\n<rss version="2.0">\n<channel>\n <title>${escapeXml(CHANNEL_TITLE)}</title>\n <link>${escapeXml(BASE_URL)}</link>\n <description>${escapeXml(CHANNEL_DESCRIPTION)}</description>${itemsXml}\n</channel>\n</rss>`;
}
async function main() {
console.log('🔍 Buscando HTML en:', ROOT_DIR);
const htmlFiles = await collectHtmlFiles(ROOT_DIR);
console.log(`📄 Archivos HTML encontrados: ${htmlFiles.length}`);
const articles = [];
for (const filePath of htmlFiles) {
const article = await parseArticle(filePath);
if (article) articles.push(article);
}
console.log(`📰 Artículos con is_article: ${articles.length}`);
if (!articles.length) {
console.warn('⚠️ No se encontraron artículos. RSS no creado.');
return;
}
articles.sort((a, b) => b.pubDate - a.pubDate);
const rssXml = buildRssXml(articles);
await fs.writeFile(OUTPUT_RSS_PATH, rssXml, 'utf8');
console.log(`✅ RSS guardado: ${OUTPUT_RSS_PATH}`);
}
main().catch(err => {
console.error('❌ Error:', err);
process.exit(1);
});
Para ejecutar:
npm install cheerio- Configura
BASE_URL,ROOT_DIRy los detalles del canal. node generate-rss.js
El script escanea HTML recursivamente, analiza con Cheerio, escapa XML, determina tipos MIME por extensión y construye URLs absolutas. Ordena por pubDate.
Conexión del RSS a Pinterest y Automatización
En Pinterest: "Crear" → "Pines Enriquecidos" → "Feed RSS" → pega https://tu-sitio.com/rss.xml. Los pines se generan en 6–24 horas.
Proceso:
- Añade un artículo con metaetiquetas.
- Ejecuta
node generate-rss.js. - Pinterest analiza el RSS y crea pines desde
<title>,<description>y<enclosure>.
Para automatización completa, integra en CI/CD (por ejemplo, GitHub Actions) o cron: 0 0 * cd /ruta/al/proyecto && node scripts/generate-rss.js.
Ventajas de este enfoque:
- Funciona con sitios estáticos (Hugo, Eleventy, HTML plano).
- No requiere CMS ni plugins.
- Escala a miles de artículos.
- Pinterest almacena en caché el RSS, por lo que no se necesitan actualizaciones en tiempo real.
Puntos Clave
- Verifica tu dominio con la metaetiqueta
p:domain_verifypara indexación. - Usa
pinterest_imagepara controlar las imágenes de los pines. - El script maneja alternativas como
mtimedel archivo y la primera<img>. - RSS incluye
<enclosure>para imágenes con tipos MIME. - Automatiza mediante cron o CI para producción.
— Editorial Team
Aún no hay comentarios.