几个月前,我们的一位工程师给我看了他周末写的一个 Python 脚本。原本他想把 Pinterest 上的产品灵感图片抓下来,给一项市场调研项目使用。他运行后,结果却只抓到了……16 个 Pins。可那个 Board 明明有 2000 多个。那一刻,他盯着屏幕,又看了看我,说:“我觉得 Pinterest 在嘲讽我。”
这并不是个例。坦白说,这也是我见过开发者用 Python 抓 Pinterest 时最常见的挫败感。你启动 requests 和 BeautifulSoup,访问一个 Pinterest 链接,拿回来的不是寥寥几个条目,就是一个空白的 HTML 壳。原因很简单:Pinterest 是一个完全由 JavaScript 渲染的单页应用——你发出的静态 HTTP 请求根本看不到真实内容。本指南会带你搞清楚为什么会这样,哪些方法真正可行(Playwright、内部 API 拦截,以及像 这样的无代码工具),并提供逐步代码,教你抓取 Pins、Boards、用户主页、无限滚动内容以及高清图片。不管你是想搭建生产级爬虫,还是只是想快速拿到数据,这篇文章都能帮到你。
什么是 Pinterest 抓取?
Pinterest 抓取,指的是通过程序化方式从 Pinterest 中提取数据,比如 Pin 图片、标题、描述、Board 名称、粉丝数和链接等。你不需要手动逐个浏览和保存 Pins,而是用代码(或工具)从搜索结果、Boards 或用户主页中批量采集结构化数据。
截至 2025 年末,,并且拥有,它是互联网上最丰富的视觉数据来源之一。对企业来说,这些数据价值极高——无论是追踪产品趋势、对标竞品内容,还是建立达人合作名单,都非常有用。
为什么要用 Python 抓取 Pinterest?
Pinterest 早已不只是婚礼策划师的灵感板了。它现在也是一个非常重要的商业洞察平台—— 会基于品牌 Pins 购买商品,而,这意味着用户带着明确意图而来,却没有品牌忠诚度。这对发现新机会来说是巨大优势,也解释了为什么这么多团队都想拿到结构化的 Pinterest 数据。
按团队来拆解,大概是这样的:
| 团队 | 需要的数据 | 商业价值 |
|---|---|---|
| 电商运营 | 产品图片、价格、热门审美风格 | 竞争性定价、受趋势影响的选品 |
| 市场营销 | Board 表现、Pin 互动、竞品内容 | 内容策略、活动对标 |
| 销售 / 线索开发 | 创作者主页、粉丝数、联系信息 | 达人拓展、合作目标筛选 |
| 房地产 | 家居布置 Pins、装修趋势、房间布局 | 房源拍摄、软装指导 |
| 内容创作者 | 热门话题、流行形式、季节性主题 | 内容日历、视觉风格研究 |
更关键的是:Pinterest 的官方 API 限制很多。它要求企业账号、审批流程(甚至包括你应用的视频演示),而且只能访问你自己账号的数据。如果你想浏览公开 Boards、搜索结果或竞品主页,抓取就是更现实的替代方案。这也是为什么很多团队会选择 Python——或者在不想折腾配置时,直接用 Thunderbit 这类无代码工具。
为什么只有 BeautifulSoup 会在 Pinterest 上失败(以及真正可行的方法)
如果你试过用 requests + BeautifulSoup 抓 Pinterest,最后只得到 16 个条目或者一个空页面,你不是看错了。Pinterest 基于 React 构建,内容 100% 通过 JavaScript 渲染。你用普通 HTTP 请求访问 Pinterest 页面时,服务器只会返回一个极简的 HTML 骨架——几个 <link> 和 <script> 标签,再加一个空的 <div>,由 React 在浏览器里挂载应用。所有的 Pin 卡片、图片、标题和网格布局,都是等 JavaScript 在浏览器里执行后才注入进去的。
没有 JavaScript 执行,就没有 Pins。
那什么方法才行?下面是几种主流方案的对比:
| 方案 | 支持 JS 渲染? | 能拿到完整数据? | 复杂度 | 适合场景 |
|---|---|---|---|---|
requests + BeautifulSoup | 否 | 约 0–16 条 | 低 | 不适合 Pinterest |
| Selenium / Playwright | 是 | 是,需要滚动逻辑 | 中 | 完整控制、Python 数据管道 |
| Pinterest 内部 API 拦截 | 是 | 是,分页 JSON | 高 | 最大化数据,不需要浏览器 |
| 第三方 Scraper API | 是 | 视情况而定 | 低 | 大规模采集,无需自建基础设施 |
| 无代码工具(Thunderbit) | 是 | AI 结构化 | 很低 | 非技术用户、快速出结果 |
在本教程里,我推荐使用 Playwright 作为 Python 方案。它可以渲染 JavaScript,支持模拟滚动,维护活跃(,招聘需求年增长),而且在基准测试中比 Selenium 。如果你想走无代码路线,我也会一起讲。
Pinterest 官方 API vs. Python 抓取 vs. 无代码:该怎么选
在动手写代码之前,先问自己一句:你真的需要写代码吗?下面是一个决策参考:
| 对比项 | Pinterest API | Python 抓取 | Thunderbit(无代码) |
|---|---|---|---|
| 是否需要审批 | 需要企业账号 + 视频演示 | 不需要 | 不需要 |
| 是否能访问公开 Pins/Boards | 有限制(仅自己的数据) | 完全可以 | 完全可以 |
| 是否能下载高清图片 | 视情况而定 | 可以,配合 URL 解析 | 可以,通过图片提取 |
| 是否支持无限滚动 | 不适用 | 可以,需编写代码 | 自动支持 |
| 是否需要维护 | 低 | 高(选择器容易失效) | 无需维护(AI 自适应) |
| 导出到 Sheets/Airtable | 手动 | 自定义代码 | 内置支持 |
| 上手时间 | 数小时到数天 | 30–60 分钟 | 2 分钟 |
如果你是市场人员、电商运营,或者只是想把 Pinterest 数据快速放进表格里,而不想写或维护 Python 脚本,那么 是最快路径。你只要打开任意 Pinterest 页面,点击“AI Suggest Fields”,再点“Scrape”,就能直接导出到 Google Sheets、Excel、Airtable 或 Notion。它的子页面抓取功能甚至可以自动跟进单个 Pin 链接,进一步补全数据。我见过从没写过代码的团队成员,在不到三分钟内把 500 多个 Pins 导进 Google 表格。
如果你想要完全掌控流程、想把抓取集成进 Python 数据管道,或者单纯享受自己动手搭建工具的过程——那就继续往下看。
为 Pinterest 抓取搭建 Python 环境
- 难度: 中级
- 预计时间: 约 30–60 分钟(含编码和测试)
- 你需要准备: Python 3.9+、Chrome 浏览器(用于测试)、终端/命令行访问权限
安装 Playwright 和依赖
先创建项目文件夹并配置虚拟环境:
1mkdir pinterest-scraper
2cd pinterest-scraper
3python -m venv venv
4source venv/bin/activate # Windows 上:venv\Scripts\activate
安装 Playwright 并下载 Chromium 浏览器二进制文件:
1pip install playwright
2playwright install chromium
你还会用到 Python 内置的 json、os 和 csv 模块来导出数据,这些不需要额外安装。
项目文件夹结构
我建议从一开始就把结构整理好:
1pinterest-scraper/
2├── scraper.py
3├── config.py
4├── output/
5│ ├── pins.json
6│ └── pins.csv
7└── images/
8 ├── board-name-1/
9 └── board-name-2/
在 config.py 中,设置你的 user agent 字符串。Pinterest 会拦截默认的无头浏览器特征,所以要使用更真实的 UA:
1USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
第 1 步:构建 Pinterest 搜索链接
把搜索关键词放入模板中,生成搜索 URL:
1query = "mid century modern furniture"
2url = f"https://www.pinterest.com/search/pins/?q={query.replace(' ', '%20')}&rs=typed"
你可以把它参数化,适配任意搜索词。rs=typed 参数告诉 Pinterest 这个查询是手动输入的(而不是推荐的),有时会影响结果相关性。
第 2 步:启动无头浏览器并加载页面
下面是 Playwright 的核心设置。注意自定义 user agent——否则 Pinterest 很可能会拦截你,或者直接给你一个登录墙页面。
1import asyncio
2from playwright.async_api import async_playwright
3from config import USER_AGENT
4async def scrape_search(query, max_pins=100):
5 url = f"https://www.pinterest.com/search/pins/?q={query.replace(' ', '%20')}&rs=typed"
6 async with async_playwright() as p:
7 browser = await p.chromium.launch(headless=True)
8 page = await browser.new_page(
9 user_agent=USER_AGENT,
10 viewport={"width": 1920, "height": 1080}
11 )
12 await page.goto(url)
13 await asyncio.sleep(3) # 等待 JS 渲染初始 Pins
运行到这里后,页面应该已经加载出第一批 Pins,通常是 25–50 个。
第 3 步:从页面中提取 Pin 数据
Pinterest 会把每个 Pin 包在一个 div[data-test-id='pinWrapper'] 里。在里面,你会找到一个链接(<a>),包含 Pin 的 URL 和标题(通过 aria-label 提供),以及一个 <img>,包含缩略图地址。
1 results = []
2 pins = await page.query_selector_all("div[data-test-id='pinWrapper']")
3 for pin in pins:
4 link = await pin.query_selector("a")
5 if not link:
6 continue
7 title = await link.get_attribute("aria-label") or ""
8 href = await link.get_attribute("href") or ""
9 img = await link.query_selector("img")
10 src = await img.get_attribute("src") if img else ""
11 results.append({
12 "title": title,
13 "url": f"https://www.pinterest.com{href}" if href.startswith("/") else href,
14 "image_url": src
15 })
此时,results 里已经包含当前可视区域中的 Pins。想拿到更多,就得滚动页面——这也是最关键的一部分。
第 4 步:把结果保存为 JSON 或 CSV
提取完成后,把数据写入文件,方便后续使用:
1import json
2import csv
3def save_json(data, filepath="output/pins.json"):
4 with open(filepath, "w", encoding="utf-8") as f:
5 json.dump(data, f, ensure_ascii=False, indent=2)
6def save_csv(data, filepath="output/pins.csv"):
7 if not data:
8 return
9 with open(filepath, "w", newline="", encoding="utf-8-sig") as f:
10 writer = csv.DictWriter(f, fieldnames=data[0].keys())
11 writer.writeheader()
12 writer.writerows(data)
如果你打算在 Excel 里打开 CSV,请使用 utf-8-sig 编码,这样可以避免中文乱码。
抓取整个 Pinterest Board 和用户主页
这是现有教程里一个很大的内容缺口。我几乎找不到哪篇竞品指南会深入讲解 Board 或主页抓取,但这恰恰是论坛里最常被问到的功能之一。用户想下载某个 Board 的全部 Pins,把图片按 Board 分类存进文件夹,还想提取主页级别的数据,比如粉丝数和 Board 列表。
从 Board 链接抓取全部 Pins
Board 链接通常是 https://www.pinterest.com/{username}/{board-name}/。DOM 结构和搜索结果类似——Pins 仍然包在 div[data-test-id='pinWrapper'] 中——但你需要滚动加载全部内容。
1async def scrape_board(board_url, max_pins=500):
2 async with async_playwright() as p:
3 browser = await p.chromium.launch(headless=True)
4 page = await browser.new_page(user_agent=USER_AGENT, viewport={"width": 1920, "height": 1080})
5 await page.goto(board_url)
6 await asyncio.sleep(3)
7 seen_ids = set()
8 all_pins = []
9 for scroll_round in range(100): # 安全上限
10 pins = await page.query_selector_all("div[data-test-id='pinWrapper']")
11 new_count = 0
12 for pin in pins:
13 link = await pin.query_selector("a")
14 if not link:
15 continue
16 href = await link.get_attribute("href") or ""
17 if href in seen_ids:
18 continue
19 seen_ids.add(href)
20 new_count += 1
21 title = await link.get_attribute("aria-label") or ""
22 img = await link.query_selector("img")
23 src = await img.get_attribute("src") if img else ""
24 all_pins.append({
25 "title": title,
26 "url": f"https://www.pinterest.com{href}" if href.startswith("/") else href,
27 "image_url": src
28 })
29 print(f"第 {scroll_round + 1} 次滚动:已收集 {len(all_pins)} 个唯一 Pins")
30 if new_count == 0 or len(all_pins) >= max_pins:
31 break
32 prev_height = await page.evaluate("document.body.scrollHeight")
33 await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
34 await asyncio.sleep(2.5)
35 curr_height = await page.evaluate("document.body.scrollHeight")
36 if curr_height == prev_height:
37 break # 没有更多内容了
38 await browser.close()
39 return all_pins
需要注意的一点是:Board 页面有时会出现一个 “More Ideas” 标签页,它会把保存的 Pins 和算法推荐内容分开。如果你只想抓取用户实际保存的 Pins,可以在遇到这个分隔区时停止滚动。
抓取用户主页:Boards、粉丝数和 Pins
主页链接通常是 https://www.pinterest.com/{username}/。在主页上,你可以提取:
- 粉丝 / 关注数: 查找
div[data-test-id='follower-count'] - Board 列表: 每个 Board 都是一个链接到
/{username}/{board-name}/的卡片 - 总 Pin 数: 有时会显示在主页顶部
1async def scrape_profile(username):
2 url = f"https://www.pinterest.com/{username}/"
3 async with async_playwright() as p:
4 browser = await p.chromium.launch(headless=True)
5 page = await browser.new_page(user_agent=USER_AGENT, viewport={"width": 1920, "height": 1080})
6 await page.goto(url)
7 await asyncio.sleep(3)
8 # 提取粉丝数
9 follower_el = await page.query_selector("div[data-test-id='follower-count']")
10 followers = await follower_el.inner_text() if follower_el else "N/A"
11 # 提取 Board 链接
12 board_links = await page.query_selector_all("a[href*='/" + username + "/']")
13 boards = []
14 for bl in board_links:
15 href = await bl.get_attribute("href") or ""
16 name = await bl.get_attribute("aria-label") or href.split("/")[-2]
17 if href.count("/") >= 3 and href != f"/{username}/":
18 boards.append({"name": name, "url": f"https://www.pinterest.com{href}"})
19 await browser.close()
20 return {"username": username, "followers": followers, "boards": boards}
如果你想把某个主页下的所有 Board 都抓出来,只要遍历 Board 列表,再对每个 Board 调用 scrape_board() 即可。你还可以把下载的图片自动按 Board 分文件夹整理好。
构建一个生产级的无限滚动处理器
这一部分,决定了你的爬虫是不是玩具级。最大的痛点——我至少在十几个论坛帖子里都见过——就是爬虫只能返回 16–25 个条目,因为它没有滚动足够远,或者只是写了一个固定次数的 for i in range(5): scroll(),然后祈祷结果别太差。
这种做法很不稳定。Pinterest 会在滚动事件触发时,每次分批加载大约 25 个 Pins。如果你滚动 5 次,也许能拿到 125 个;也可能因为网络慢只拿到 75 个;如果每批更小,甚至可能拿到 150 个。你需要一种更聪明的模式。
直到没有新内容为止的滚动模式
下面是一个更稳健的滚动函数:它会追踪唯一 Pin ID,使用可配置的超时时间,包含重试逻辑,并输出进度:
1import time
2import random
3async def scroll_and_collect(page, max_pins=1000, max_scrolls=200, scroll_pause=2.5):
4 seen_ids = set()
5 all_pins = []
6 no_new_count = 0
7 for i in range(max_scrolls):
8 pins = await page.query_selector_all("div[data-test-id='pinWrapper']")
9 new_this_round = 0
10 for pin in pins:
11 link = await pin.query_selector("a")
12 if not link:
13 continue
14 href = await link.get_attribute("href") or ""
15 if href in seen_ids:
16 continue
17 seen_ids.add(href)
18 new_this_round += 1
19 title = await link.get_attribute("aria-label") or ""
20 img = await link.query_selector("img")
21 src = await img.get_attribute("src") if img else ""
22 all_pins.append({
23 "title": title,
24 "url": f"https://www.pinterest.com{href}" if href.startswith("/") else href,
25 "image_url": src
26 })
27 print(f" 第 {i+1} 次滚动:{new_this_round} 个新 Pins | 共 {len(all_pins)} 个唯一 Pins")
28 if len(all_pins) >= max_pins:
29 print(f" 已达到 max_pins 限制({max_pins}),停止。")
30 break
31 if new_this_round == 0:
32 no_new_count += 1
33 if no_new_count >= 3:
34 print(" 连续 3 次滚动都没有新 Pins,说明内容已经结束。")
35 break
36 else:
37 no_new_count = 0
38 prev_height = await page.evaluate("document.body.scrollHeight")
39 await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
40 await asyncio.sleep(scroll_pause + random.uniform(0.5, 1.5))
41 curr_height = await page.evaluate("document.body.scrollHeight")
42 if curr_height == prev_height and new_this_round == 0:
43 print(" 页面高度没有变化,而且没有新 Pins,说明可能已经到底了。")
44 break
45 return all_pins
为什么这个设计更稳?
- 按 href 去重: 每个 Pin 的 URL 都是唯一的,所以可以把它当作 ID。这样在滚动过程中 DOM 重绘时,也不会把同一个 Pin 算两次。
- 三次连续无新增规则: 如果连续 3 次滚动都没有新 Pins,就停止。这可以处理页面还在加载,但实际上已经没有新内容的情况。
- 加入随机抖动延迟: 在每次滚动之间加入 0.5–1.5 秒的随机延迟,让行为更像真人,也能降低触发反爬机制的概率。
- max_scrolls 安全上限: 防止出错后进入死循环。
处理边界情况
- “More Ideas” 分隔: 在 Board 页面里,Pinterest 有时会插入一个 “More Ideas” 区块。如果你只想要 Board 的真实保存内容,可以检测到这个元素后停止滚动。
- 长时间会话的限流: 如果你在一个有几千个 Pins 的 Board 上持续滚动,Pinterest 可能会开始限速。如果你发现滚动时隔一会儿才出现 0 个新 Pins(不是连续 3 次),可以把滚动间隔提高到 5 秒以上。
获取 Pinterest 高清原图(而不是缩略图)
这部分最让人抓狂。你抓了一堆 Pins,下载下来的图却全是 236px 的小缩略图。论坛用户常常把它形容成“垃圾画质,太小了”。解决方法在于理解 Pinterest 的图片 URL 结构。
Pinterest 图片 URL 路径规则
Pinterest 的图片都托管在 https://i.pinimg.com/{size}/{hash}.jpg。其中 {size} 这一段决定了图片分辨率:
| 尺寸路径 | 分辨率 | 用途 |
|---|---|---|
/236x/ | 宽 236px | 默认网格视图(你默认拿到的就是这个) |
/474x/ | 宽 474px | 中等分辨率 |
/736x/ | 宽 736px | Pin 详情页 / 展开视图 |
/originals/ | 原始上传尺寸 | 完整分辨率 |
工具函数:把任意 Pinterest 图片 URL 升级为高清版本
下面这个函数可以把任意 Pinterest 图片 URL 改写为尽可能高的质量,并带有回退逻辑:
1import requests as req
2def upgrade_image_url(url, preferred_size="originals"):
3 """将 Pinterest 图片 URL 改写为尽可能高的分辨率。"""
4 sizes = ["originals", "736x", "474x", "236x"]
5 if preferred_size not in sizes:
6 preferred_size = "originals"
7 for size in sizes[sizes.index(preferred_size):]:
8 upgraded = url
9 for s in sizes:
10 upgraded = upgraded.replace(f"/{s}/", f"/{size}/")
11 try:
12 resp = req.head(upgraded, timeout=5, allow_redirects=True)
13 if resp.status_code == 200:
14 return upgraded
15 except Exception:
16 continue
17 return url # 如果都失败,就返回原始链接
重要提示(截至 2025 年): /originals/ 路径越来越频繁地返回 HTTP 403 Forbidden 错误。 也确认了这一点,时间是 2025 年中期。现在更可靠的最高可用路径通常是 /736x/。我的函数会先尝试 /originals/,然后自动回退到 /736x/。
把图片下载到有组织的文件夹中
1import os
2import time
3def download_images(pins, folder="images/default", delay=1.5):
4 os.makedirs(folder, exist_ok=True)
5 for i, pin in enumerate(pins):
6 img_url = upgrade_image_url(pin.get("image_url", ""), preferred_size="736x")
7 if not img_url:
8 continue
9 filename = f"pin_{i+1}.jpg"
10 filepath = os.path.join(folder, filename)
11 try:
12 resp = req.get(img_url, timeout=15)
13 if resp.status_code == 200:
14 with open(filepath, "wb") as f:
15 f.write(resp.content)
16 print(f" 已下载 {filename}({len(resp.content) // 1024} KB)")
17 else:
18 print(f" 下载失败 {filename}:HTTP {resp.status_code}")
19 except Exception as e:
20 print(f" 下载 {filename} 出错:{e}")
21 time.sleep(delay + random.uniform(0.3, 0.8))
下载之间一定要加限速延迟。我通常会设置 1.5–2.3 秒,再加一点随机抖动。否则抓到几百个请求后,Pinterest 很快就会封你的 IP。
导出你抓取的 Pinterest 数据
导出为 CSV 或 JSON
上面已经讲过基础做法。对于更大的数据集(1 万个 Pins 以上),可以考虑 JSON Lines 格式——每行一个 JSON 对象——这样更适合流式处理和后续加工:
1def save_jsonl(data, filepath="output/pins.jsonl"):
2 with open(filepath, "w", encoding="utf-8") as f:
3 for item in data:
4 f.write(json.dumps(item, ensure_ascii=False) + "\n")
导出到 Google Sheets、Airtable 或 Notion
如果你想直接用 Python 把数据推送到 Google Sheets,需要 gspread 库和一个 Google Cloud 服务账号。Airtable 可以用 pyairtable,Notion 则可以用 notion-client。这些都需要配置 API 密钥,也会让你的流程复杂不少。
或者——虽然我有点偏爱这个方案,但它确实是最快的——你可以直接用 抓取 Pinterest,然后一键导出到这些平台。无需 API 密钥、无需服务账号、无需额外代码。 原生支持导出。
如何避免在抓取 Pinterest 时被封
ScrapeOps 把 Pinterest 的反爬系统绕过难度评为 ——不算简单,但也不是最难的目标。它会结合浏览器指纹识别、行为分析和基于 IP 的限流。下面这些做法比较有效:
- 轮换 user agent: 准备一组真实的 Chrome UA,每个会话随机选一个。
- 增加随机延迟: 每次滚动和请求之间等待 2–5 秒,并加入抖动。如果没有代理,建议提高到 10–15 秒。
- 使用真实的视口尺寸: 设置
viewport={"width": 1920, "height": 1080},不要用太小或奇怪的尺寸。 - 规模化时考虑代理: 如果你要抓成千上万的 Pins,建议轮换住宅代理。不然抓到几百次请求后就可能被封 IP。
- 遵守
robots.txt: Pinterest 的robots.txt阻止了大多数自动爬虫,且有大约 。做合规评估时要注意这一点。 - 避免登录后抓取: 尽量只抓公开可见、且未登录状态下可访问的内容。登录状态下抓取会带来更高的法律和技术风险。
如果你走无代码路线,Thunderbit 的 AI 引擎会自动处理反爬和 CAPTCHA 挑战——你就少维护一堆麻烦。
Pinterest 抓取的法律与伦理注意事项
这一部分我会简要带过,因为不是文章重点,但它很重要。
Pinterest 的服务条款(第 2a 条)写明,你同意不会以未经授权的方式“scrape, collect, search, copy or otherwise access data or content from Pinterest in unauthorized ways, such as by using automated means (without our express prior permission).” 不过,法院通常认为,抓取公开可访问的数据并不违反《计算机欺诈与滥用法案》——可以参考 以及 2024 年 1 月的 Meta v. Bright Data 案,法院裁定:在未登录状态下抓取公开可见数据是合法的。
几个基本原则:
- 只抓取公开可见内容,并保持未登录状态
- 不要把抓取的数据用于垃圾营销或冒充用户
- 尊重图片版权——尽量提取元数据,未经许可不要将受版权保护的图片用于商业再分发
- 如果你计划将抓取数据用于商业用途,先咨询律师
想更深入了解法律背景,可以参考我们的。
总结:你学到了什么,以及下一步怎么做
现在你已经知道为什么静态抓取在 Pinterest 上行不通(它是一个基于 React 的 SPA——没有 JavaScript,就没有数据),也知道如何用 Playwright 抓取搜索结果、Boards 和用户主页,如何构建一个不会在 16 个 Pins 后就放弃的生产级无限滚动处理器,以及如何拿到高清图片,而不是小缩略图。
快速回顾重点:
requests+ BeautifulSoup 在 Pinterest 上基本没用,别浪费时间。- Playwright 是最适合这个任务的 Python 工具——速度快、维护活跃,并且原生支持 JS 渲染。
- 无限滚动 需要基于去重的滚动循环,而不是固定次数。
- 高清图片 需要改写 URL 路径——优先使用
/736x/(因为/originals/经常返回 403)。 - Board 和主页抓取 在现有教程中很少被认真覆盖,但用对选择器其实并不难。
- 对于不想写代码的人或追求速度的团队, 可以让你在 2 次点击内抓取 Pinterest,并导出到 Google Sheets、Excel、Airtable 或 Notion——不需要 Python。你可以通过 免费试用。
如果你正在搭建 Python 数据管道,本指南里的代码可以作为很好的基础。如果你只是想要数据,Thunderbit 就是捷径。无论选哪条路,你都不会再卡在“16 个 Pins 和一脸茫然”的状态里了。
想了解更多关于抓取和数据提取的内容,可以看看我们的这些指南:、、以及。你也可以查看 ,或者观看 上的教程。
常见问题
1. 可以只用 BeautifulSoup 抓 Pinterest 吗?
单独用它效果并不好。Pinterest 的所有内容都通过 JavaScript 渲染,所以 requests + BeautifulSoup 只能看到一个空的 HTML 壳。你需要先用 Playwright 或 Selenium 这类无头浏览器把页面渲染出来,或者直接使用像 Thunderbit 这样可以自动处理 JS 渲染的无代码工具。
2. 一次会话里可以抓多少个 Pinterest Pins?
这取决于你的滚动逻辑和反爬处理方式。使用本指南中的生产级无限滚动处理器(去重、超时、重试逻辑),你可以稳定抓取每个 Board 或搜索词下的几百到几千个 Pins。对于特别大的 Board,通常需要花几分钟持续滚动和采集。
3. 为什么我抓到的 Pinterest 图片都很小?
默认情况下,Pinterest 在网格视图里会提供 /236x/ 缩略图。要拿到更高分辨率的图片,你需要把图片 URL 路径改成 /736x/ 或 /originals/。不过从 2025 年开始,/originals/ 越来越容易返回 403,所以 /736x/ 才是更可靠的最高可用版本。
4. 抓取 Pinterest 合法吗?
根据最近的法院判例(例如 hiQ v. LinkedIn、Meta v. Bright Data),抓取公开可访问的数据通常是被接受的,但 Pinterest 的服务条款禁止未经授权的自动化访问。建议只抓公开内容,不要把数据用于垃圾营销,尊重版权,并在商业使用前咨询法律顾问。
5. 抓取 Pinterest 最好的无代码替代方案是什么?
可以在 2 次点击内提取 Pinterest Pins 数据——包括标题、图片、URL、描述等——并内置导出到 Google Sheets、Excel、Airtable 或 Notion。它会自动处理 JavaScript 渲染、无限滚动和反爬挑战,所以你不需要编写或维护任何代码。
了解更多