Skip to content

Instantly share code, notes, and snippets.

@jam53
Created February 22, 2026 10:27
Show Gist options
  • Select an option

  • Save jam53/80348e4f1bdb5261419581a81bb6324f to your computer and use it in GitHub Desktop.

Select an option

Save jam53/80348e4f1bdb5261419581a81bb6324f to your computer and use it in GitHub Desktop.
Given a Pinterest link to a pin, this script grabs the source image (or video) from the webpage and downloads it. Provided the Pin ID in the URL consists purely of numbers.
# Prerequisite: pip install requests
# Usage: python DownloadPinterestOriginalSource.py <pin_url> -o <output_dir>
# Example: python DownloadPinterestOriginalSource.py https://www.pinterest.com/pin/41447259074000929/ -o Downloads
# Options:
# -o, --output-dir: Directory to save the image (default: Downloads)
# -h, --help: Show help message and exit
import argparse
import pathlib
import re
import sys
import requests
# Regex to find the original image URL (allow any extension)
IMAGES_ORIG_RE = re.compile(
r'"images_orig"\s*:\s*\{\s*"__typename"\s*:\s*"ImageDetails"\s*,\s*"url"\s*:\s*"(https://i\.pinimg\.com/originals/[0-9a-f/]+\.[^"\\]+)"',
re.IGNORECASE,
)
# Regex to find video URLs (prefer mp4, but also see HLS/MPEG-DASH)
# Covers both `/videos/mc/...` and `/videos/iht/...` and similar.
VIDEO_URL_RE = re.compile(
r"https://v1\.pinimg\.com/videos/[^\s\"'<>]+",
re.IGNORECASE,
)
# Regex to find the pin ID
PIN_ID_RE = re.compile(r"/pin/(\d+)/?")
def fetch_page_html(pin_url: str) -> str:
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/123.0.0.0 Safari/537.36"
)
}
resp = requests.get(pin_url, headers=headers, timeout=20)
resp.raise_for_status()
return resp.text
def extract_original_url(html: str) -> str:
# If there is a video, prefer a direct MP4 URL over the image.
video_matches = VIDEO_URL_RE.findall(html)
if video_matches:
# Prefer mp4 over m3u8/mpd/etc. if available.
mp4_candidates = [u for u in video_matches if ".mp4" in u.lower()]
if mp4_candidates:
return mp4_candidates[0]
# Otherwise just return the first video URL.
return video_matches[0]
# Fallback to original image URL from images_orig.
m = IMAGES_ORIG_RE.search(html)
if not m:
raise RuntimeError("Could not find video URL or images_orig.url in the page.")
return m.group(1)
def parse_pin_id(pin_url: str) -> str:
m = PIN_ID_RE.search(pin_url)
if not m:
raise RuntimeError(f"Could not extract pin id from URL: {pin_url}")
return m.group(1)
def download_file(url: str, output_dir: pathlib.Path, pin_id: str | None = None) -> pathlib.Path:
output_dir.mkdir(parents=True, exist_ok=True)
basename = url.rstrip("/").split("/")[-1]
if "." in basename:
ext = "." + basename.split(".")[-1]
else:
ext = ".jpg"
if pin_id:
filename = f"{pin_id}{ext}"
else:
filename = basename if basename.endswith(ext) else basename + ext
dest = output_dir / filename
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
with open(dest, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
return dest
def main(argv=None) -> int:
parser = argparse.ArgumentParser(
description="Download the original image from a Pinterest pin URL."
)
parser.add_argument("pin_url", help="Pinterest pin URL (e.g. https://www.pinterest.com/pin/...)")
parser.add_argument(
"-o", "--output-dir",
default="Downloads",
help="Directory to save the image (default: Downloads)",
)
args = parser.parse_args(argv)
out_dir = pathlib.Path(args.output_dir)
pin_id = parse_pin_id(args.pin_url)
print(f"Fetching page HTML for {args.pin_url} ...")
html = fetch_page_html(args.pin_url)
print("Extracting original image URL ...")
original_url = extract_original_url(html)
print(f"Found original image URL:\n {original_url}")
print("Downloading original image ...")
path = download_file(original_url, out_dir, pin_id=pin_id)
print(f"Saved to: {path.resolve()}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment