import puppeteer from 'puppeteer'; import type { Page } from 'puppeteer'; import dotenv from 'dotenv'; import * as fs from 'fs/promises'; import path from 'path'; import { spawn } from 'child_process'; dotenv.config(); /** * Script: generate_pinterest_keywords.ts * * For each genre/subgenre pair (provided below) this script: * - searches Pinterest for "genre subgenre" * - scrolls the results page several times * - collects up to 20 unique pin IDs from the page * - outputs a JSON array to the console: * [{ genre: "...", subGenre: "...", pinIds: ["id1","id2", ...] }, ...] * * Usage: * - npx ts-node src/generate_pinterest_keywords.ts * - or compile with tsc and run with node * * Notes: * - Puppeteer will run headless by default. If you need to debug visually set headless: false. * - Adjust SCROLL_ITERATIONS and MAX_PIN_IDS_PER_TERM if you want different behavior. */ const SCROLL_ITERATIONS = 8; // number of times to scroll (adjust if you want more) const MAX_PIN_IDS_PER_TERM = 20; // target number of pin ids per genre/subgenre const SCROLL_DELAY_MS = 900; // delay between scrolls const searchList: { genre: string; subGenre: string }[] = [ /* { genre: "abstract", subGenre: "3D Renderings" }, { genre: "abstract", subGenre: "Abstract Portraits" }, { genre: "abstract", subGenre: "Collage" }, { genre: "abstract", subGenre: "Color Explosions" }, { genre: "abstract", subGenre: "cubic" }, { genre: "abstract", subGenre: "Cubism" }, { genre: "abstract", subGenre: "Digital Glitch" }, { genre: "abstract", subGenre: "Fluid Paints" }, { genre: "abstract", subGenre: "Fractals" }, { genre: "abstract", subGenre: "Geometric Shapes" }, { genre: "abstract", subGenre: "Graffiti" }, { genre: "abstract", subGenre: "Impressionism" }, { genre: "abstract", subGenre: "Kaleidoscopes" }, { genre: "abstract", subGenre: "Light Art" }, { genre: "abstract", subGenre: "Mandalas" }, { genre: "abstract", subGenre: "Minimalism" }, { genre: "abstract", subGenre: "Optical Illusions" }, { genre: "abstract", subGenre: "particle" }, { genre: "abstract", subGenre: "Pop Art" }, { genre: "abstract", subGenre: "science" }, { genre: "abstract", subGenre: "space" }, { genre: "abstract", subGenre: "sphere" }, { genre: "abstract", subGenre: "Street Art" }, { genre: "abstract", subGenre: "Surrealism" }, { genre: "abstract", subGenre: "Typography Art" }, { genre: "abstruct", subGenre: "art" }, { genre: "abstruct", subGenre: "colors" }, { genre: "abstruct", subGenre: "particle" }, { genre: "animals", subGenre: "Bats" }, { genre: "animals", subGenre: "Bears" }, { genre: "animals", subGenre: "Butterflies" }, { genre: "animals", subGenre: "Camels" }, { genre: "animals", subGenre: "Crocodiles" }, { genre: "animals", subGenre: "Dolphins" }, { genre: "animals", subGenre: "Eagles" }, { genre: "animals", subGenre: "Elephants" }, { genre: "animals", subGenre: "Foxes" }, { genre: "animals", subGenre: "Giraffes" }, { genre: "animals", subGenre: "Horses" }, { genre: "animals", subGenre: "Lions" }, { genre: "animals", subGenre: "Owls" }, { genre: "animals", subGenre: "Pandas" }, { genre: "animals", subGenre: "Penguins" }, { genre: "animals", subGenre: "Seals" }, { genre: "animals", subGenre: "Sharks" }, { genre: "animals", subGenre: "Tigers" }, { genre: "animals", subGenre: "Whales" }, { genre: "animals", subGenre: "Wolves" }, { genre: "architecture", subGenre: "luxury room" }, { genre: "childhood", subGenre: "Adoption" }, { genre: "childhood", subGenre: "Babies" }, { genre: "childhood", subGenre: "Bedtime Stories" }, { genre: "childhood", subGenre: "Birthday Parties" }, { genre: "childhood", subGenre: "Children Playing" }, { genre: "childhood", subGenre: "Family Dinners" }, { genre: "childhood", subGenre: "Family Portraits" }, { genre: "childhood", subGenre: "Graduations" }, { genre: "childhood", subGenre: "Grandparents" }, { genre: "childhood", subGenre: "Holiday Celebrations" }, { genre: "childhood", subGenre: "Learning to Walk" }, { genre: "childhood", subGenre: "Nursery" }, { genre: "childhood", subGenre: "Parent-Teacher Meetings" }, { genre: "childhood", subGenre: "Picnics" }, { genre: "childhood", subGenre: "Pregnancy" }, { genre: "childhood", subGenre: "School Activities" }, { genre: "childhood", subGenre: "Siblings" }, { genre: "childhood", subGenre: "Sports with Kids" }, { genre: "childhood", subGenre: "Toys" }, { genre: "childhood", subGenre: "Vacations" }, { genre: "cinematic", subGenre: "Action Movies" }, { genre: "cinematic", subGenre: "Animations" }, { genre: "cinematic", subGenre: "Documentaries" }, { genre: "cinematic", subGenre: "Experimental Cinema" }, { genre: "cinematic", subGenre: "Fantasy Epics" }, { genre: "cinematic", subGenre: "Historical Dramas" }, { genre: "cinematic", subGenre: "Hollywood Blockbusters" }, { genre: "cinematic", subGenre: "Horror Films" }, { genre: "cinematic", subGenre: "Indie Films" }, { genre: "cinematic", subGenre: "Mockumentaries" }, { genre: "cinematic", subGenre: "Musicals" }, { genre: "cinematic", subGenre: "Nature Documentaries" }, { genre: "cinematic", subGenre: "Noir" }, { genre: "cinematic", subGenre: "Romantic Comedies" }, { genre: "cinematic", subGenre: "Sci-Fi Thrillers" }, { genre: "cinematic", subGenre: "Short Films" }, { genre: "cinematic", subGenre: "Silent Films" }, { genre: "cinematic", subGenre: "Stop Motion" }, { genre: "cinematic", subGenre: "Superhero Films" }, { genre: "cinematic", subGenre: "Westerns" }, { genre: "city", subGenre: "Bridges" }, { genre: "city", subGenre: "Castles" }, { genre: "city", subGenre: "Cathedrals" }, { genre: "city", subGenre: "Factories" }, { genre: "city", subGenre: "Futuristic Cities" }, { genre: "city", subGenre: "Historic Towns" }, { genre: "city", subGenre: "Libraries" }, { genre: "city", subGenre: "Markets" }, { genre: "city", subGenre: "Modern Plazas" }, { genre: "city", subGenre: "Museums" }, { genre: "city", subGenre: "Palaces" }, { genre: "city", subGenre: "Residential Blocks" }, { genre: "city", subGenre: "Skylines" }, { genre: "city", subGenre: "Skyscrapers" }, { genre: "city", subGenre: "Slums" }, { genre: "city", subGenre: "Stadiums" }, { genre: "city", subGenre: "Street Cafes" }, { genre: "city", subGenre: "Urban Parks" }, { genre: "fantasy", subGenre: "academia" }, { genre: "fantasy", subGenre: "aesthetic" }, { genre: "fantasy", subGenre: "art" }, { genre: "fantasy", subGenre: "Crystal Caves" }, { genre: "fantasy", subGenre: "Dark Castles" }, { genre: "fantasy", subGenre: "dark ethereal" }, { genre: "fantasy", subGenre: "darkacademia" }, { genre: "fantasy", subGenre: "ddreamy room" }, { genre: "fantasy", subGenre: "Dragon Realms" }, { genre: "fantasy", subGenre: "dreamy room" }, { genre: "fantasy", subGenre: "Elven Cities" }, { genre: "fantasy", subGenre: "Enchanted Rivers" }, { genre: "fantasy", subGenre: "Epic Battles" }, { genre: "fantasy", subGenre: "ethereal" }, { genre: "fantasy", subGenre: "Fairy Villages" }, { genre: "fantasy", subGenre: "Floating Islands" }, { genre: "fantasy", subGenre: "Ghostly Spirits" }, { genre: "fantasy", subGenre: "illumication" }, { genre: "fantasy", subGenre: "Knights" }, { genre: "fantasy", subGenre: "landscape" }, { genre: "fantasy", subGenre: "Magic Forests" }, { genre: "fantasy", subGenre: "Magical Beasts" }, { genre: "fantasy", subGenre: "Mystic Portals" }, { genre: "fantasy", subGenre: "Mythical Weapons" }, { genre: "fantasy", subGenre: "Queens and Kings" }, { genre: "fantasy", subGenre: "Runes and Symbols" }, { genre: "fantasy", subGenre: "Sacred Temples" }, { genre: "fantasy", subGenre: "Shape-shifters" }, { genre: "fantasy", subGenre: "Talking Animals" }, { genre: "fantasy", subGenre: "Wizards" }, { genre: "fashion", subGenre: "Accessories" }, { genre: "fashion", subGenre: "Boho Style" }, { genre: "fashion", subGenre: "Bridal Wear" }, { genre: "fashion", subGenre: "Business Suits" }, { genre: "fashion", subGenre: "Casual Wear" }, { genre: "fashion", subGenre: "Cocktail Dresses" }, { genre: "fashion", subGenre: "Cosplay" }, { genre: "fashion", subGenre: "Evening Gowns" }, { genre: "fashion", subGenre: "Hair Styling" }, { genre: "fashion", subGenre: "Haute Couture" }, { genre: "fashion", subGenre: "Makeup Styles" }, { genre: "fashion", subGenre: "Pajamas" }, { genre: "fashion", subGenre: "Runway Shows" }, { genre: "fashion", subGenre: "School Uniforms" }, { genre: "fashion", subGenre: "Shoes" }, { genre: "fashion", subGenre: "Sportswear" }, { genre: "fashion", subGenre: "Streetwear" }, { genre: "fashion", subGenre: "Swimwear" }, { genre: "fashion", subGenre: "Traditional Costumes" }, { genre: "fashion", subGenre: "Vintage Outfits" }, { genre: "food", subGenre: "Bakeries" }, { genre: "food", subGenre: "BBQ" }, { genre: "food", subGenre: "Breakfasts" }, { genre: "food", subGenre: "Chocolate Making" }, { genre: "food", subGenre: "Cocktails" }, { genre: "food", subGenre: "Coffee Culture" }, { genre: "food", subGenre: "Desserts" }, { genre: "food", subGenre: "Farmers Market" }, { genre: "food", subGenre: "Fine Dining" }, { genre: "food", subGenre: "Food Trucks" }, { genre: "food", subGenre: "Fruit Platters" }, { genre: "food", subGenre: "Pasta Dishes" }, { genre: "food", subGenre: "Pizza" }, { genre: "food", subGenre: "Seafood" }, { genre: "food", subGenre: "Spices and Herbs" }, { genre: "food", subGenre: "Street Food" }, { genre: "food", subGenre: "Sushi" }, { genre: "food", subGenre: "Tea Ceremonies" }, { genre: "food", subGenre: "Vegetarian Meals" }, { genre: "food", subGenre: "Wine Tasting" }, { genre: "history", subGenre: "African Tribes" }, { genre: "history", subGenre: "Ancient Egypt" }, { genre: "history", subGenre: "Celtic Legends" }, { genre: "history", subGenre: "Chinese Dynasties" }, { genre: "history", subGenre: "Greek Temples" }, { genre: "history", subGenre: "Indian Kingdoms" }, { genre: "history", subGenre: "Industrial Revolution" }, { genre: "history", subGenre: "Mayan Ruins" }, { genre: "history", subGenre: "Medieval Europe" }, { genre: "history", subGenre: "Native American" }, { genre: "history", subGenre: "Nomadic Life" }, { genre: "history", subGenre: "Ottoman Empire" }, { genre: "history", subGenre: "Renaissance" }, { genre: "history", subGenre: "Samurai Japan" }, { genre: "history", subGenre: "Traditional Festivals" }, { genre: "history", subGenre: "Victorian Era" }, { genre: "history", subGenre: "Viking Culture" }, { genre: "history", subGenre: "World War Eras" }, { genre: "horror", subGenre: "Abandoned Hospitals" }, { genre: "horror", subGenre: "Ancient Tombs" }, { genre: "horror", subGenre: "Blood Moons" }, { genre: "horror", subGenre: "Creepy Dolls" }, { genre: "horror", subGenre: "Curses" }, { genre: "horror", subGenre: "Dark Alleys" }, { genre: "horror", subGenre: "Demons" }, { genre: "horror", subGenre: "Foggy Forests" }, { genre: "horror", subGenre: "Ghosts" }, { genre: "horror", subGenre: "Graveyards" }, { genre: "horror", subGenre: "Haunted Houses" }, { genre: "horror", subGenre: "Monsters" }, { genre: "horror", subGenre: "Occult Rituals" }, { genre: "horror", subGenre: "Possessions" }, { genre: "horror", subGenre: "Scary Clowns" }, { genre: "horror", subGenre: "Shadows" }, { genre: "horror", subGenre: "Silent Villages" }, { genre: "horror", subGenre: "Vampires" }, { genre: "horror", subGenre: "Werewolves" }, { genre: "horror", subGenre: "Witches" }, { genre: "music", subGenre: "Ballet" }, { genre: "music", subGenre: "Breakdance" }, { genre: "music", subGenre: "Choirs" }, { genre: "music", subGenre: "Classical Concerts" }, { genre: "music", subGenre: "Dance Battles" }, { genre: "music", subGenre: "DJ Performances" }, { genre: "music", subGenre: "Drumming" }, { genre: "music", subGenre: "Electronic Music" }, { genre: "music", subGenre: "Flamenco" }, { genre: "music", subGenre: "Folk Dance" }, { genre: "music", subGenre: "Hip-Hop Dance" }, { genre: "music", subGenre: "Jazz Clubs" }, { genre: "music", subGenre: "K-Pop" }, { genre: "music", subGenre: "Opera" }, { genre: "music", subGenre: "Orchestras" }, { genre: "music", subGenre: "Rock Bands" }, { genre: "music", subGenre: "Salsa" }, { genre: "music", subGenre: "Singing Solo" }, { genre: "music", subGenre: "Street Dance" }, { genre: "music", subGenre: "Tap Dance" }, { genre: "nature", subGenre: "Aurora Skies" }, { genre: "nature", subGenre: "Canyons" }, { genre: "nature", subGenre: "Caves" }, { genre: "nature", subGenre: "Cliffs" }, { genre: "nature", subGenre: "Coral Reefs" }, { genre: "nature", subGenre: "Deserts" }, { genre: "nature", subGenre: "Forests" }, { genre: "nature", subGenre: "Glaciers" }, { genre: "nature", subGenre: "Lakes" }, { genre: "nature", subGenre: "Meadows" }, { genre: "nature", subGenre: "Mountains" }, { genre: "nature", subGenre: "night sky" }, { genre: "nature", subGenre: "Oceans" }, { genre: "nature", subGenre: "Rainforest" }, { genre: "nature", subGenre: "Rivers" }, { genre: "nature", subGenre: "Savannah" }, { genre: "nature", subGenre: "Storms" }, { genre: "nature", subGenre: "Sunsets" }, { genre: "nature", subGenre: "Volcanoes" }, { genre: "nature", subGenre: "Waterfalls" }, { genre: "nature", subGenre: "Wetlands" }, { genre: "people", subGenre: "Artists" }, { genre: "people", subGenre: "Celebrations" }, { genre: "people", subGenre: "Children" }, { genre: "people", subGenre: "Commuting" }, { genre: "people", subGenre: "Craftsmen" }, { genre: "people", subGenre: "Daily Life" }, { genre: "people", subGenre: "Elderly" }, { genre: "people", subGenre: "Family Moments" }, { genre: "people", subGenre: "Farm Life" }, { genre: "people", subGenre: "Festivals" }, { genre: "people", subGenre: "Fishing Villages" }, { genre: "people", subGenre: "Friendship" }, { genre: "people", subGenre: "Markets" }, { genre: "people", subGenre: "Relaxing" }, { genre: "people", subGenre: "Romantic Dates" }, { genre: "people", subGenre: "School Days" }, { genre: "people", subGenre: "Shopping" }, { genre: "people", subGenre: "Street Life" }, { genre: "people", subGenre: "Travelers" }, { genre: "people", subGenre: "Workplaces" }, { genre: "romance", subGenre: "Anger" }, { genre: "romance", subGenre: "Anniversaries" }, { genre: "romance", subGenre: "Arguments" }, { genre: "romance", subGenre: "Comforting" }, { genre: "romance", subGenre: "Confessions" }, { genre: "romance", subGenre: "Family Love" }, { genre: "romance", subGenre: "Farewells" }, { genre: "romance", subGenre: "First Dates" }, { genre: "romance", subGenre: "Friendship" }, { genre: "romance", subGenre: "Heartbreak" }, { genre: "romance", subGenre: "Hugs" }, { genre: "romance", subGenre: "Joy" }, { genre: "romance", subGenre: "Kisses" }, { genre: "romance", subGenre: "Laughter" }, { genre: "romance", subGenre: "Loneliness" }, { genre: "romance", subGenre: "Reunions" }, { genre: "romance", subGenre: "Sadness" }, { genre: "romance", subGenre: "Surprise" }, { genre: "romance", subGenre: "wedding" }, { genre: "romance", subGenre: "Weddings" }, { genre: "sci-fi", subGenre: "AI Entities" }, { genre: "sci-fi", subGenre: "Aliens" }, { genre: "sci-fi", subGenre: "Androids" }, { genre: "sci-fi", subGenre: "Clones" }, { genre: "sci-fi", subGenre: "Colonies on Mars" }, { genre: "sci-fi", subGenre: "Cyberpunk Cities" }, { genre: "sci-fi", subGenre: "Exosuits" }, { genre: "sci-fi", subGenre: "Futuristic Weapons" }, { genre: "sci-fi", subGenre: "Galactic Battles" }, { genre: "sci-fi", subGenre: "Genetic Labs" }, { genre: "sci-fi", subGenre: "Holograms" }, { genre: "sci-fi", subGenre: "Hover Cars" }, { genre: "sci-fi", subGenre: "Nanotechnology" }, { genre: "sci-fi", subGenre: "Post-Apocalypse" }, { genre: "sci-fi", subGenre: "Robots" }, { genre: "sci-fi", subGenre: "Space Stations" }, { genre: "sci-fi", subGenre: "Time Travel" }, { genre: "sci-fi", subGenre: "Virtual Reality" }, { genre: "sci-fi", subGenre: "Wormholes" }, { genre: "space", subGenre: "Asteroids" }, { genre: "space", subGenre: "Aurora" }, { genre: "space", subGenre: "Black Holes" }, { genre: "space", subGenre: "Comets" }, { genre: "space", subGenre: "Cosmic Dust" }, { genre: "space", subGenre: "Deep Space" }, { genre: "space", subGenre: "Eclipses" }, { genre: "space", subGenre: "Exoplanets" }, { genre: "space", subGenre: "Galaxies" }, { genre: "space", subGenre: "Meteor Showers" }, { genre: "space", subGenre: "Moons" }, { genre: "space", subGenre: "Nebulae" }, { genre: "space", subGenre: "Observatories" }, { genre: "space", subGenre: "Planets" }, { genre: "space", subGenre: "Rocket Launches" }, { genre: "space", subGenre: "Satellites" }, { genre: "space", subGenre: "Spacewalks" }, { genre: "space", subGenre: "Stars" }, { genre: "space", subGenre: "Supernovas" }, { genre: "space", subGenre: "Telescopes" }, { genre: "sports", subGenre: "Archery" }, { genre: "sports", subGenre: "Baseball" }, { genre: "sports", subGenre: "Basketball" }, { genre: "sports", subGenre: "Boxing" }, { genre: "sports", subGenre: "Climbing" }, { genre: "sports", subGenre: "Cycling" }, { genre: "sports", subGenre: "Fencing" }, { genre: "sports", subGenre: "Gymnastics" }, { genre: "sports", subGenre: "Horse Riding" }, { genre: "sports", subGenre: "Martial Arts" }, { genre: "sports", subGenre: "Rowing" }, { genre: "sports", subGenre: "Running" }, { genre: "sports", subGenre: "Skateboarding" }, { genre: "sports", subGenre: "Skiing" }, { genre: "sports", subGenre: "Snowboarding" }, { genre: "sports", subGenre: "Soccer" }, { genre: "sports", subGenre: "Surfing" }, { genre: "sports", subGenre: "Swimming" }, { genre: "sports", subGenre: "Tennis" }, { genre: "sports", subGenre: "Yoga" }, { genre: "technology", subGenre: "3D Printing" }, { genre: "technology", subGenre: "Artificial Intelligence" }, { genre: "technology", subGenre: "Augmented Reality" }, { genre: "technology", subGenre: "Autonomous Cars" }, { genre: "technology", subGenre: "Biotech" }, { genre: "technology", subGenre: "Cyber Security" }, { genre: "technology", subGenre: "Data Centers" }, { genre: "technology", subGenre: "Digital Currency" }, { genre: "technology", subGenre: "Drones" }, { genre: "technology", subGenre: "Futuristic Homes" }, { genre: "technology", subGenre: "Green Tech" }, { genre: "technology", subGenre: "Nanobots" }, { genre: "technology", subGenre: "Quantum Computing" }, { genre: "technology", subGenre: "Robotics" }, { genre: "technology", subGenre: "Smart Cities" }, { genre: "technology", subGenre: "Smart Farms" }, { genre: "technology", subGenre: "Space Elevators" }, { genre: "technology", subGenre: "Surveillance Systems" }, { genre: "technology", subGenre: "VR Worlds" }, { genre: "technology", subGenre: "Wearables" }, { genre: "travel", subGenre: "Backpacking" }, { genre: "travel", subGenre: "Camping" }, { genre: "travel", subGenre: "City Tours" }, { genre: "travel", subGenre: "Cruises" }, { genre: "travel", subGenre: "Cultural Trips" }, { genre: "travel", subGenre: "Desert Journeys" }, { genre: "travel", subGenre: "Diving Trips" }, { genre: "travel", subGenre: "Exploring Ruins" }, { genre: "travel", subGenre: "Festivals Abroad" }, { genre: "travel", subGenre: "Glamping" }, { genre: "travel", subGenre: "Hiking" }, { genre: "travel", subGenre: "Hot Air Balloons" }, { genre: "travel", subGenre: "Island Hopping" }, { genre: "travel", subGenre: "Jungle Treks" }, { genre: "travel", subGenre: "Motorbike Tours" }, { genre: "travel", subGenre: "Mountain Climbing" }, { genre: "travel", subGenre: "Polar Expeditions" }, { genre: "travel", subGenre: "Road Trips" }, { genre: "travel", subGenre: "Safari" }, { genre: "travel", subGenre: "Train Journeys" }, { genre: "work", subGenre: "Actors" }, { genre: "work", subGenre: "Artists" }, { genre: "work", subGenre: "Athletes" }, { genre: "work", subGenre: "Chefs" }, { genre: "work", subGenre: "Craftsmen" }, { genre: "girl", subGenre: "Casual Dresses" }, { genre: "girl", subGenre: "Mini Skirts" }, { genre: "girl", subGenre: "Long Skirts" }, { genre: "girl", subGenre: "Evening Gowns" }, { genre: "girl", subGenre: "School Uniforms" }, { genre: "girl", subGenre: "Business Suits" }, { genre: "girl", subGenre: "Cocktail Dresses" }, { genre: "girl", subGenre: "Boho Outfits" }, { genre: "girl", subGenre: "Streetwear" }, { genre: "girl", subGenre: "Traditional Costumes" }, { genre: "girl", subGenre: "Party Dresses" }, { genre: "girl", subGenre: "Swimwear" }, { genre: "girl", subGenre: "Sportswear" }, { genre: "girl", subGenre: "Lingerie" }, { genre: "girl", subGenre: "Pajamas" }, { genre: "girl", subGenre: "Gothic Outfits" }, { genre: "girl", subGenre: "Vintage Dresses" }, { genre: "girl", subGenre: "Winter Coats" }, { genre: "girl", subGenre: "Summer Outfits" }, { genre: "girl", subGenre: "Festival Outfits" }, { genre: "woman", subGenre: "Evening Gowns" }, { genre: "woman", subGenre: "Cocktail Dresses" }, { genre: "woman", subGenre: "Ball Gowns" }, { genre: "woman", subGenre: "Business Attire" }, { genre: "woman", subGenre: "Formal Suits" }, { genre: "woman", subGenre: "Luxury Lingerie" }, { genre: "woman", subGenre: "Opera Dresses" }, { genre: "woman", subGenre: "Elegant Skirts" }, { genre: "woman", subGenre: "Designer Outfits" }, { genre: "woman", subGenre: "Classic Black Dress" }, { genre: "woman", subGenre: "High Fashion Couture" }, { genre: "woman", subGenre: "Vintage Elegance" }, { genre: "woman", subGenre: "Wedding Dresses" }, { genre: "woman", subGenre: "Chic Office Wear" }, { genre: "woman", subGenre: "Luxury Coats" }, { genre: "woman", subGenre: "Formal Evening Suits" }, { genre: "woman", subGenre: "Silk Dresses" }, { genre: "woman", subGenre: "Red Carpet Outfits" }, { genre: "woman", subGenre: "Classic Tailored Wear" }, { genre: "woman", subGenre: "Luxury Resort Wear" } { "genre": "woman", "subGenre": "Casual Dresses" }, { "genre": "woman", "subGenre": "Jeans and Blouses" }, { "genre": "woman", "subGenre": "Maxi Skirts" }, { "genre": "woman", "subGenre": "Casual Office Wear" }, { "genre": "woman", "subGenre": "Cardigans with Skirts" }, { "genre": "woman", "subGenre": "Casual Jumpsuits" }, { "genre": "woman", "subGenre": "Casual Knitwear" }, { "genre": "woman", "subGenre": "Linen Outfits" }, { "genre": "woman", "subGenre": "Weekend Outfits" }, { "genre": "woman", "subGenre": "Street Casual" }, { "genre": "woman", "subGenre": "Boho Casual" }, { "genre": "woman", "subGenre": "Smart Casual" }, { "genre": "woman", "subGenre": "Denim Skirts" }, { "genre": "woman", "subGenre": "Casual Midi Dresses" }, { "genre": "woman", "subGenre": "Summer Casual" }, { "genre": "woman", "subGenre": "Casual Sweaters" }, { "genre": "woman", "subGenre": "Casual Jackets" }, { "genre": "woman", "subGenre": "Everyday Casual Wear" }, { "genre": "woman", "subGenre": "Relaxed Home Wear" }, { "genre": "woman", "subGenre": "Travel Casual" }, { "genre": "girl", "subGenre": "Casual Mini Skirts" }, { "genre": "girl", "subGenre": "T-Shirts and Shorts" }, { "genre": "girl", "subGenre": "Casual Sundresses" }, { "genre": "girl", "subGenre": "Sweaters with Skirts" }, { "genre": "girl", "subGenre": "Casual Hoodies" }, { "genre": "girl", "subGenre": "Casual Denim" }, { "genre": "girl", "subGenre": "Casual Rompers" }, { "genre": "girl", "subGenre": "School Casual" }, { "genre": "girl", "subGenre": "Casual Tops and Skirts" }, { "genre": "girl", "subGenre": "Leggings and Tees" }, { "genre": "girl", "subGenre": "Casual Tank Tops" }, { "genre": "girl", "subGenre": "Sporty Casual" }, { "genre": "girl", "subGenre": "Casual Pajamas" }, { "genre": "girl", "subGenre": "Casual Jackets" }, { "genre": "girl", "subGenre": "Simple Dresses" }, { "genre": "girl", "subGenre": "Casual Streetwear" }, { "genre": "girl", "subGenre": "Casual Overalls" }, { "genre": "girl", "subGenre": "Casual Knit Tops" }, { "genre": "girl", "subGenre": "Casual Party Wear" }, { "genre": "girl", "subGenre": "Weekend Casual" }, { "genre": "girl", "subGenre": "Anime School Uniform" }, { "genre": "girl", "subGenre": "Magical Girl Costume" }, { "genre": "girl", "subGenre": "Catgirl Outfit" }, { "genre": "girl", "subGenre": "Maid Outfit" }, { "genre": "girl", "subGenre": "Nurse Uniform" }, { "genre": "girl", "subGenre": "Sailor Suit" }, { "genre": "girl", "subGenre": "Fantasy Elf Costume" }, { "genre": "girl", "subGenre": "Vampire Girl Outfit" }, { "genre": "girl", "subGenre": "Gothic Lolita Dress" }, { "genre": "girl", "subGenre": "Princess Dress" }, { "genre": "girl", "subGenre": "Warrior Girl Armor" }, { "genre": "girl", "subGenre": "Cyberpunk Outfit" }, { "genre": "girl", "subGenre": "Steampunk Girl Costume" }, { "genre": "girl", "subGenre": "Fairy Wings Costume" }, { "genre": "girl", "subGenre": "Idol Singer Outfit" }, { "genre": "girl", "subGenre": "Bunny Girl Costume" }, { "genre": "girl", "subGenre": "Magical Witch Outfit" }, { "genre": "girl", "subGenre": "Samurai Girl Costume" }, { "genre": "girl", "subGenre": "Succubus Outfit" }, { "genre": "girl", "subGenre": "Video Game Heroine Cosplay" } { "genre": "epic", "subGenre": "woman" }, { "genre": "epic", "subGenre": "girl" }, { "genre": "epic", "subGenre": "human" }, { "genre": "epic", "subGenre": "man" }, { "genre": "epic", "subGenre": "architecture" }, { "genre": "epic", "subGenre": "animals" }, { "genre": "epic", "subGenre": "ethereal" }, { "genre": "epic", "subGenre": "gothic" }, { "genre": "epic", "subGenre": "dark" }, { "genre": "epic", "subGenre": "space" }, { "genre": "epic", "subGenre": "scene" }, { "genre": "epic", "subGenre": "black" }, { "genre": "epic", "subGenre": "colorful" }, { "genre": "epic", "subGenre": "bright" }, { "genre": "epic", "subGenre": "abstract" }, { "genre": "epic", "subGenre": "abstract color" }, { "genre": "epic", "subGenre": "room" }, { "genre": "epic", "subGenre": "building" }, { "genre": "epic", "subGenre": "wizard" }, { "genre": "epic", "subGenre": "future" }, { "genre": "epic", "subGenre": "landscape" }, { "genre": "epic", "subGenre": "stars" }, */ { "genre": "dance", "subGenre": "hiphop horizontal" }, { "genre": "dance", "subGenre": "hiphop group horizontal" }, { "genre": "dance", "subGenre": "tiktok horizontal" }, { "genre": "dance", "subGenre": "female street horizontal" }, { "genre": "dance", "subGenre": "male street horizontal" }, { "genre": "dance", "subGenre": "idol horizontal" }, ]; function extractPinIdFromHref(href: string): string | null { // hrefs look like https://www.pinterest.com/pin/123456789012345678/... const m = href.match(/\/pin\/([^\/\?]+)/); return m ? m[1] : null; } async function collectPinIdsForSearch(page: Page, query: string): Promise { const pinIds = new Set(); const searchUrl = `https://www.pinterest.com/search/pins/?q=${encodeURIComponent(query)}`; await page.goto(searchUrl, { waitUntil: 'networkidle2', timeout: 60000 }); // initial collect const collect = async () => { const hrefs = await page.$$eval('a', anchors => (anchors as any[]).map(a => (a as any).href)) as string[]; for (const href of hrefs) { if (!href) continue; if (href.includes('/pin/')) { const id = href.match(/\/pin\/([^\/\?]+)/); if (id && id[1]) pinIds.add(id[1]); if (pinIds.size >= MAX_PIN_IDS_PER_TERM) break; } } }; await collect(); // Scroll a few times to load more results for (let i = 0; i < SCROLL_ITERATIONS && pinIds.size < MAX_PIN_IDS_PER_TERM; i++) { await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); await new Promise(resolve => setTimeout(resolve, SCROLL_DELAY_MS + Math.floor(Math.random() * 800))); await collect(); } return Array.from(pinIds).slice(0, MAX_PIN_IDS_PER_TERM); } (async () => { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'); const results: { genre: string; subGenre: string; pinIds: string[] }[] = []; for (const item of searchList) { const term = `${item.genre} ${item.subGenre}`; try { console.log(`Searching Pinterest for: "${term}"`); const pinIds = await collectPinIdsForSearch(page, term); console.log(` -> Found ${pinIds.length} pinIds for "${term}"`); results.push({ genre: item.genre, subGenre: item.subGenre, pinIds }); // small delay between queries to avoid being throttled await new Promise(resolve => setTimeout(resolve, 600 + Math.floor(Math.random() * 1000))); } catch (err) { console.error(`Error collecting pins for "${term}":`, err); results.push({ genre: item.genre, subGenre: item.subGenre, pinIds: [] }); } } await browser.close(); // Merge results with existing src/pinterest_keywords.json (if present), // then write merged data to both src/pinterest_keywords.json and generated/pinterest_keywords.json const srcPath = path.join(process.cwd(), 'src', 'pinterest_keywords.json'); const outDir = path.join(process.cwd(), 'generated'); try { await fs.mkdir(outDir, { recursive: true }); // load existing entries from src/pinterest_keywords.json (if available) let existing: { genre: string; subGenre: string; pinIds: string[] }[] = []; try { const raw = await fs.readFile(srcPath, 'utf-8'); const parsed = JSON.parse(raw); if (Array.isArray(parsed)) existing = parsed; } catch (e) { // file missing or invalid JSON -> start with empty existing array existing = []; } // Build map keyed by genre||subGenre to merge pinIds (dedupe) const map = new Map(); for (const e of existing) { const key = `${e.genre}||${e.subGenre}`; map.set(key, { genre: e.genre, subGenre: e.subGenre, pinIds: Array.from(new Set(e.pinIds || [])) }); } for (const r of results) { const key = `${r.genre}||${r.subGenre}`; const existingEntry = map.get(key); if (existingEntry) { // preserve existing order, then append any new ids from r const set = new Set(existingEntry.pinIds); for (const id of r.pinIds || []) set.add(id); existingEntry.pinIds = Array.from(set); } else { map.set(key, { genre: r.genre, subGenre: r.subGenre, pinIds: Array.from(new Set(r.pinIds || [])) }); } } const merged = Array.from(map.values()); // Write merged JSON to src and generated folder const writePromises = [ fs.writeFile(srcPath, JSON.stringify(merged, null, 2), 'utf-8'), fs.writeFile(path.join(outDir, 'pinterest_keywords.json'), JSON.stringify(merged, null, 2), 'utf-8') ]; await Promise.all(writePromises); console.log(`Saved ${merged.length} entries to ${srcPath} and ${path.join(outDir, 'pinterest_keywords.json')}`); } catch (err) { console.error('Failed to write output file:', err); // Fallback to printing JSON to stdout console.log(JSON.stringify(results, null, 2)); } })();