Created
February 22, 2026 10:27
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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