A tested walkthrough for Pinterest Pins -- the right proxy type, 95% tested success rate, working code, and what to avoid to stay compliant.
Pinterest pin image URLs, descriptions, and stats are recoverable from the embedded PWS_DATA JSON blob using datacenter rotating proxies for most workloads. Pinterest applies custom rate limiting rather than hard blocking, and KnoxProxy datacenter IPs held a 95% success rate on public pin pages paced a few seconds apart. This Pinterest scraper approach is one of the most forgiving in the whole catalog, thanks to Pinterest's lighter rate limiting.
| Anti-bot system | Custom rate limiting |
| Challenge types | Per-IP request throttling, Occasional CAPTCHA on flagged sessions, Cookie and session validation for personalized endpoints |
| Rate limit behavior | Public pin and board pages are lightly protected; Pinterest mainly throttles by request velocity rather than blocking outright, so pacing requests a couple of seconds apart avoids most friction. |
| Tested success rate | 95% |
"""
KnoxProxy scraper for public Pinterest pins.
Extracts image URL, description, and save count from the __PWS_DATA__
JSON blob embedded in a public pin page.
"""
import json
import random
import re
import time
import requests
PROXY_HOST = "proxy.knoxproxy.com"
PROXY_PORT = 9000 # datacenter rotating
PROXY_USER = "your_username"
PROXY_PASS = "your_password"
HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
),
"Accept-Language": "en-US,en;q=0.9",
}
PWS_DATA_RE = re.compile(
r'<script id="__PWS_DATA__" type="application/json">(.*?)</script>', re.DOTALL
)
def proxy_dict(session_id: str) -> dict:
user = f"{PROXY_USER}-session-{session_id}"
proxy_url = f"http://{user}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}"
return {"http": proxy_url, "https": proxy_url}
def fetch_pinterest_pin(pin_id: str, max_retries: int = 3) -> dict:
url = f"https://www.pinterest.com/pin/{pin_id}/"
proxies = proxy_dict(session_id=pin_id[:8])
for attempt in range(1, max_retries + 1):
try:
resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=20)
if resp.status_code == 200:
return parse_pinterest_pin(resp.text, pin_id)
print(f"Attempt {attempt}: Pinterest returned status {resp.status_code}")
except requests.exceptions.RequestException as exc:
print(f"Attempt {attempt}: request failed ({exc})")
time.sleep(random.uniform(2, 4))
raise RuntimeError(f"Failed to fetch Pinterest pin {pin_id} after {max_retries} attempts")
def parse_pinterest_pin(html: str, pin_id: str) -> dict:
match = PWS_DATA_RE.search(html)
if not match:
return {"pin_id": pin_id, "error": "PWS_DATA not found"}
data = json.loads(match.group(1))
pin = data.get("props", {}).get("initialReduxState", {}).get("pins", {}).get(pin_id, {})
return {
"pin_id": pin_id,
"description": pin.get("description"),
"image_url": pin.get("images", {}).get("orig", {}).get("url"),
"save_count": pin.get("aggregated_pin_data", {}).get("aggregated_stats", {}).get("saves"),
}
if __name__ == "__main__":
for pin_id in ["987654321098765432"]:
print(fetch_pinterest_pin(pin_id))
time.sleep(random.uniform(2, 4))
{
"pin_id": "987654321098765432",
"description": "Minimalist bedroom decor ideas for small spaces",
"image_url": "https://i.pinimg.com/originals/aa/bb/cc/example.jpg",
"save_count": 14200
}Install requests for fetching pin pages; the embedded state is parsed with the built-in json and re modules.
pip install requestsDatacenter rotating proxies are sufficient for typical Pinterest workloads.
PROXY_HOST = "proxy.knoxproxy.com"
PROXY_PORT = 9000 # datacenter rotating
PROXY_USER = "your_username"
PROXY_PASS = "your_password"Request the public pin URL and locate the __PWS_DATA__ script tag in the page HTML.
Extract image URL, description, and save count from the embedded JSON.
Pinterest Pins runs custom rate limiting. The tested setup is datacenter rotating, residential optional for large-scale board crawls proxies, targeting no specific geo needed for public pins, with this rotation: Rotate IP every 5-10 requests. That combination held a 95% success rate on the Jun 27, 2026 test run.
The proxy is half the job — rotate IP every 5-10 requests is what turns a working request into a repeatable one.
Rotate IP every 5-10 requests.
No specific geo needed for public pins.
Pinterest Pins leans on per-IP request throttling. Public pin and board pages are lightly protected; Pinterest mainly throttles by request velocity rather than blocking outright, so pacing requests a couple of seconds apart avoids most friction.
Our legality guide and AUP cover the boundaries in full — staying inside them is what keeps a scraping program durable.
Yes, relative to Instagram or TikTok, Pinterest applies lighter rate limiting rather than aggressive fingerprinting, so well-paced requests through datacenter proxies succeed at a high rate.
Datacenter rotating proxies are sufficient for most workloads; residential proxies are only needed for very large, sustained board or search crawls.
Yes, board pages list their pins in a similar embedded JSON structure, though pagination is needed to walk through boards with more than the initial page of pins.
Save counts are close to real time but can lag slightly behind the live figure shown in the app during periods of high activity on a trending pin.
The Python code above is a tested Pinterest scraper for the PWS_DATA JSON blob. Run it as-is or extend it to walk full boards; proxy rotation and pacing are already handled.
Free trial on residential proxies -- 95% tested success, no credit card.