save changes
This commit is contained in:
531
src/generate_pinterest_keywords.ts
Normal file
531
src/generate_pinterest_keywords.ts
Normal file
@ -0,0 +1,531 @@
|
||||
import puppeteer from 'puppeteer';
|
||||
import type { Page } from 'puppeteer';
|
||||
import dotenv from 'dotenv';
|
||||
import * as fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
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" },
|
||||
];
|
||||
|
||||
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<string[]> {
|
||||
const pinIds = new Set<string>();
|
||||
|
||||
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();
|
||||
|
||||
// Output JSON to file (generated/pinterest_keywords.json)
|
||||
const outDir = path.join(process.cwd(), 'generated');
|
||||
try {
|
||||
await fs.mkdir(outDir, { recursive: true });
|
||||
const outPath = path.join(outDir, 'pinterest_keywords.json');
|
||||
await fs.writeFile(outPath, JSON.stringify(results, null, 2), 'utf-8');
|
||||
console.log(`Saved ${results.length} entries to ${outPath}`);
|
||||
} catch (err) {
|
||||
console.error('Failed to write output file:', err);
|
||||
// Fallback to printing JSON to stdout
|
||||
console.log(JSON.stringify(results, null, 2));
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user