如何在2026年抓取Pinterest图钉和看板:开发者完整指南
如果你正在构建视觉内容数据集、趋势分析平台或竞品监控系统,Pinterest 是一个极具价值的数据源——它拥有超过 5 亿月活跃用户和海量的视觉发现数据。然而,Pinterest 的反爬机制、本地化搜索结果和内部 API 结构使得大规模数据采集充满挑战。本文将深入讲解如何合法、高效地抓取 Pinterest 公开图钉(Pins)和看板(Boards),涵盖内部 Resource API 的工作原理、代理轮换策略以及生产环境中的最佳实践。
法律声明:本文仅涉及公开可访问数据的采集。在开始之前,请务必阅读并遵守 Pinterest 的服务条款(Terms of Service)。在美国,未经授权的数据访问可能违反《计算机欺诈和滥用法》(CFAA);在欧盟,处理个人数据须遵守《通用数据保护条例》(GDPR)。如果你需要采集的数据涉及个人信息或需要登录才能访问,请优先使用 Pinterest 官方 API v5。
公开数据 vs 登录墙:你能抓什么?
Pinterest 的数据表面可以分为两类:
- 公开数据(无需登录):公开看板的图钉流、图钉详情页、公开搜索结果、用户公开个人资料页。这些页面在浏览器中无需登录即可访问。
- 登录墙数据:首页推荐流(home feed)、个性化推荐、私密看板、已保存的图钉。这些内容需要用户登录并依赖个性化算法,不适合也不应通过爬虫获取。
Pinterest 提供了 官方 API v5,允许开发者通过 OAuth 获取用户授权的看板和图钉数据。但官方 API 有严格的速率限制(通常每个应用每天约 10 万次请求),且只能访问已授权用户自己的数据,无法用于大规模公开数据采集或搜索结果抓取。
Pinterest 内部 Resource API 的工作原理
Pinterest 前端页面并不是通过传统的 REST API 加载数据的。它使用一套内部 Resource API,所有数据请求都通过统一的端点模式进行:
GET https://www.pinterest.com/resource/{ResourceName}/get/
?source_url={url_encoded_page_url}
&data={url_encoded_json_params}
常见的 Resource 端点包括:
| Resource 名称 | 用途 | 关键参数 |
|---|---|---|
PinResource | 获取单个图钉详情 | id, field_set_key |
BoardFeedResource | 获取看板中的图钉列表 | board_id, page_size, bookmarks |
SearchResource | 搜索图钉/看板 | query, scope, page_size |
UserResource | 获取用户公开资料 | username |
这些请求需要特定的 HTTP 头才能正常返回数据:
X-Pinterest-PWS-Handler:标识前端处理模块,如www/[username]/[board].jsX-APP-VERSION:前端应用版本号,如abcd123,需与当前部署版本匹配csrftoken:CSRF 令牌,通常从首次访问的 Cookie 中获取User-Agent:必须使用真实浏览器 UA,否则可能被直接拦截
source_url 参数是当前页面的 URL 路径(如 /search/pins/?q=coffee),data 参数是一个 URL 编码的 JSON 对象,包含分页游标(bookmarks)、查询条件和字段配置。
反爬机制与代理策略
Pinterest 使用多层反爬机制来保护其平台:
- 每 IP 速率限制:同一 IP 在短时间内发送过多请求会触发 429 状态码或临时封禁。根据实测,单 IP 每分钟请求超过 60-100 次即可能触发限制。
- Bot 评分:Pinterest 会根据请求头、TLS 指纹、行为模式和 IP 信誉对每个请求进行评分。数据中心 IP 通常会被标记为高风险。
- 本地化搜索:搜索结果和推荐内容基于请求来源的地理位置进行个性化。从日本 IP 搜索 "coffee" 返回的结果与美国 IP 截然不同。
这就是为什么 轮换住宅代理 + 地理定位 对 Pinterest 抓取至关重要。住宅代理使用真实 ISP 分配的 IP 地址,具有较低的 bot 风险评分;通过地理定位(如 country-US),你可以确保搜索结果的一致性和可重复性。
ProxyHat 代理配置
使用 ProxyHat 住宅代理,你可以通过用户名参数实现地理定位和会话保持:
- 地理定位:
user-country-US:pass— 强制使用美国 IP - 城市级定位:
user-country-US-city-new_york:pass— 精确到城市 - 粘性会话:
user-session-abc123:pass— 在同一会话中保持相同 IP
更多代理位置请查看 ProxyHat 可用地区列表。
实战:Python 抓取看板图钉
以下示例展示如何使用 Python requests 通过 ProxyHat 住宅代理分页抓取 Pinterest 看板中的公开图钉:
import requests
import json
import time
from urllib.parse import quote
# ProxyHat 住宅代理配置
proxy_url = "http://user-country-US-session-pinterest01:YOUR_PASSWORD@gate.proxyhat.com:8080"
proxies = {"http": proxy_url, "https": proxy_url}
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",
"Accept-Language": "en-US,en;q=0.9",
"X-Pinterest-PWS-Handler": "www/[username]/[board].js",
"X-APP-VERSION": "abcd123",
}
def fetch_board_pins(board_slug, page_size=25, max_pages=10):
"""分页抓取公开看板的图钉列表"""
all_pins = []
bookmarks = None
for page in range(max_pages):
data_params = {
"options": {
"board_slug": board_slug,
"page_size": page_size,
"current_url": f"/{board_slug}/",
},
"context": {}
}
if bookmarks:
data_params["options"]["bookmarks"] = bookmarks
source_url = quote(f"/{board_slug}/", safe="")
data = quote(json.dumps(data_params), safe="")
url = f"https://www.pinterest.com/resource/BoardFeedResource/get/?source_url={source_url}&data={data}"
try:
resp = requests.get(url, headers=headers, proxies=proxies, timeout=15)
if resp.status_code == 429:
print(f"Rate limited on page {page}, backing off...")
time.sleep(30)
continue
result = resp.json()
pins = result.get("resource_response", {}).get("data", [])
bookmarks = result.get("resource_response", {}).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 len(pins) < page_size:
break
time.sleep(2) # 请求间隔,避免触发速率限制
except Exception as e:
print(f"Error on page {page}: {e}")
break
return all_pins
# 使用示例
pins = fetch_board_pins("username/board-name", page_size=25, max_pages=10)
print(f"共抓取 {len(pins)} 个图钉")
for pin in pins[:3]:
print(json.dumps(pin, indent=2, ensure_ascii=False))
上述代码通过 bookmarks 游标实现分页,每次请求携带上一次返回的游标以获取下一页数据。粘性会话(session-pinterest01)确保 csrftoken 在请求间保持一致,避免因 IP 切换导致的 CSRF 验证失败。
实战:Node.js 抓取搜索结果
以下 Node.js 示例通过 ProxyHat HTTP 网关(端口 8080)抓取 Pinterest 搜索结果:
const axios = require("axios");
const proxyConfig = {
proxy: {
protocol: "http",
host: "gate.proxyhat.com",
port: 8080,
auth: {
username: "user-country-US-session-search01",
password: "YOUR_PASSWORD",
},
},
};
const headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Accept": "application/json",
"X-Pinterest-PWS-Handler": "www/search/[scope].js",
"X-APP-VERSION": "abcd123",
};
async function searchPins(query, pageSize = 25) {
const data = JSON.stringify({
options: {
query: query,
scope: "pins",
page_size: pageSize,
},
context: {},
});
const sourceUrl = encodeURIComponent(`/search/pins/?q=${query}`);
const dataParam = encodeURIComponent(data);
const url = `https://www.pinterest.com/resource/SearchResource/get/?source_url=${sourceUrl}&data=${dataParam}`;
try {
const response = await axios.get(url, {
headers,
proxy: proxyConfig.proxy,
timeout: 15000,
});
const results = response.data.resource_response?.data || [];
return results.map((pin) => ({
id: pin.id,
title: pin.title || pin.grid_title,
image: pin.images?.orig?.url,
link: pin.link,
}));
} catch (error) {
console.error("Search failed:", error.response?.status, error.message);
return [];
}
}
// 使用示例
searchPins("minimalist home decor").then((pins) => {
console.log(`找到 ${pins.length} 个图钉`);
pins.slice(0, 3).forEach((p) => console.log(JSON.stringify(p, null, 2)));
});
分页、会话管理与指纹防护
游标分页(Bookmark Pagination)
Pinterest 的 Resource API 不使用传统的页码分页,而是使用 bookmarks 游标。每次请求返回的 bookmark 字段是一个 base64 编码的字符串,包含下一次请求的偏移信息。关键点:
- 第一次请求不携带 bookmarks 参数
- 后续请求将上一次返回的 bookmark 放入
options.bookmarks数组 - 当返回空 bookmark 或空数据时表示已到末尾
粘性会话与 CSRF 连续性
由于 Pinterest 依赖 csrftoken 进行请求验证,频繁切换 IP 会导致 Cookie 失效。使用 ProxyHat 的 session- 参数可以在一定时间内保持同一出口 IP,确保 CSRF 令牌在整个采集过程中有效:
# 同一会话保持相同 IP
http://user-country-US-session-myboard001:pass@gate.proxyhat.com:8080
请求节奏与 User-Agent 卫生
即使使用住宅代理,也需要模拟真实用户行为:
- 请求间隔:每次请求间隔 2-5 秒,加入随机抖动
- User-Agent:使用主流浏览器的真实 UA,避免使用已知爬虫 UA(如
python-requests/2.x) - Accept-Language:与代理地理位置匹配,如美国 IP 使用
en-US,en;q=0.9 - 并发控制:单会话并发不超过 2-3 个请求,多会话可提高总吞吐量
更多代理配置选项请参考 ProxyHat 官方文档。
伦理抓取与官方 API 的选择
数据采集不是法外之地。在构建 Pinterest 数据管道时,请遵循以下原则:
- 只采集公开、非个人数据:图钉的标题、图片 URL、链接和描述属于公开内容。但用户的行为数据(如点击历史、保存记录)属于个人信息,受 GDPR 保护。
- 遵守 robots.txt:Pinterest 的
robots.txt文件定义了允许和禁止爬取的路径。在开始之前请检查https://www.pinterest.com/robots.txt。 - 控制请求频率:不要对 Pinterest 服务器造成过大负担。合理的请求速率不仅符合道德规范,也能提高采集的长期稳定性。
- 生产环境优先使用官方 API:如果你的应用需要长期、稳定的数据访问,请评估 Pinterest API v5 是否满足需求。官方 API 提供稳定的 SLA、明确的速率限制和合规保障。
对于需要大规模公开数据采集的场景(如趋势分析、视觉内容数据集构建),代理辅助的网页抓取仍然是必要的补充手段。了解更多代理应用场景请访问 网页抓取用例 和 SERP 追踪用例。
关键要点总结
- 公开数据优先:只抓取无需登录即可访问的公开图钉、看板和搜索结果,避免触碰登录墙后的个人数据。
- 理解 Resource API:Pinterest 使用内部 Resource API(如
BoardFeedResource、SearchResource),需要正确的请求头和 URL 编码的 JSON 数据参数。- 住宅代理 + 地理定位:使用 ProxyHat 住宅代理配合
country-US参数,确保搜索结果一致性并降低 bot 风险评分。- 游标分页 + 粘性会话:使用 bookmarks 游标分页,配合
session-参数保持 CSRF 令牌连续性。- 请求节奏控制:2-5 秒请求间隔,匹配地理位置的 Accept-Language,单会话低并发。
- 伦理优先:遵守 robots.txt 和服务条款,生产环境优先考虑官方 API v5。
准备好开始抓取 Pinterest 公开数据了吗?查看 ProxyHat 定价方案,选择适合你项目规模的住宅代理套餐。






