通过RSS和元标签为静态网站自动化生成Pinterest图钉
要将您的网站与Pinterest集成,首先需要验证您的域名。在Pinterest商业中心,选择元标签验证方法,并将其插入到主页的<head>中:
<meta name="p:domain_verify" content="12ac6ff1eaa70a3386sg439fda58bbb6"/>
这允许Pinterest索引带有富图钉的页面。接下来,为每篇文章的<head>添加元标签:
<meta name="is_article" content="true">
<meta name="pinterest_description" content="图钉描述,150–200个字符">
<meta name="pinterest_image" content="https://example.com/image.webp">
<meta name="article_published_at" content="2026-04-03T12:00:00+03:00">
图片应为竖版(1000×1500像素),通过HTTPS提供,且小于2 MB。如果没有pinterest_image,Pinterest将使用页面上的第一个<img>,这通常效果不佳。
使用Node.js脚本生成RSS源
Pinterest通过解析RSS来自动创建图钉。使用脚本来扫描HTML文件、提取元数据并生成rss.xml。
在scripts文件夹中创建generate-rss.js:
import fs from 'node:fs/promises';
import path from 'node:path';
import * as cheerio from 'cheerio';
// ================== 设置(请自定义这些) ==================
const BASE_URL = 'https://YOUR_SITE.com';
const ROOT_DIR = path.resolve(process.cwd(), 'dist');
const OUTPUT_RSS_PATH = path.join(ROOT_DIR, 'rss.xml');
const CHANNEL_TITLE = '您的博客名称';
const CHANNEL_DESCRIPTION = '描述:关于开发、SEO、设计的文章';
// ================== 请勿修改以下内容 ==================
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() || '无标题';
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('🔍 在以下目录搜索HTML:', ROOT_DIR);
const htmlFiles = await collectHtmlFiles(ROOT_DIR);
console.log(`📄 找到的HTML文件:${htmlFiles.length}`);
const articles = [];
for (const filePath of htmlFiles) {
const article = await parseArticle(filePath);
if (article) articles.push(article);
}
console.log(`📰 带有is_article的文章:${articles.length}`);
if (!articles.length) {
console.warn('⚠️ 未找到文章。未创建RSS。');
return;
}
articles.sort((a, b) => b.pubDate - a.pubDate);
const rssXml = buildRssXml(articles);
await fs.writeFile(OUTPUT_RSS_PATH, rssXml, 'utf8');
console.log(`✅ RSS已保存:${OUTPUT_RSS_PATH}`);
}
main().catch(err => {
console.error('❌ 错误:', err);
process.exit(1);
});
运行步骤:
npm install cheerio- 配置
BASE_URL、ROOT_DIR和频道详情。 node generate-rss.js
该脚本递归扫描HTML,使用Cheerio解析,转义XML,根据扩展名确定MIME类型,并构建绝对URL。按pubDate排序。
将RSS连接到Pinterest并实现自动化
在Pinterest中:“创建” → “富图钉” → “RSS源” → 粘贴https://your-site.com/rss.xml。图钉将在6–24小时内生成。
流程:
- 添加带有元标签的文章。
- 运行
node generate-rss.js。 - Pinterest解析RSS并根据
<title>、<description>和<enclosure>创建图钉。
要实现完全自动化,可集成到CI/CD(如GitHub Actions)或cron任务中:0 0 * cd /path/to/project && node scripts/generate-rss.js。
此方法的优势:
- 适用于静态网站(Hugo、Eleventy、纯HTML)。
- 无需CMS或插件。
- 可扩展到数千篇文章。
- Pinterest会缓存RSS,因此无需实时更新。
关键要点
- 使用
p:domain_verify元标签验证域名以进行索引。 - 使用
pinterest_image控制图钉视觉效果。 - 脚本处理回退到文件
mtime和第一个<img>。 - RSS包含带有MIME类型的
<enclosure>用于图片。 - 通过cron或CI实现生产环境自动化。
— Editorial Team
暂无评论。