JB/scraper/scrapers/art_and_design_ingestion.py

199 lines
8.7 KiB
Python

import requests
import html
import re
from typing import List, Dict, Any
from scrapers.ats_ingestion import clean_html_text, determine_experience_level
# Specialized Art, Design, Creative, Game Studio & Media Greenhouse & Lever boards
ART_DESIGN_GREENHOUSE_BOARDS = [
# Gaming & 3D Art Studios
("epicgames", "Epic Games"),
("unity", "Unity Technologies"),
("roblox", "Roblox"),
("riotgames", "Riot Games"),
("bungie", "Bungie"),
("niantic", "Niantic"),
("skydance", "Skydance Media / Animation"),
("supercell", "Supercell"),
# Design & Creative Platforms
("figma", "Figma"),
("canva", "Canva"),
("webflow", "Webflow"),
("framer", "Framer"),
("squarespace", "Squarespace"),
("pinterest", "Pinterest"),
("midjourney", "Midjourney"),
# Media, Entertainment & Creative Brands
("duolingo", "Duolingo Design & Animation"),
("spotify", "Spotify Creative"),
("buzzfeed", "BuzzFeed Creative")
]
ART_DESIGN_LEVER_BOARDS = [
("resend", "Resend Brand & Design"),
("framer", "Framer Creative"),
("loom", "Loom Design"),
("vimeo", "Vimeo Creative")
]
# Additional curated Connecticut & Remote Art, Design, Animation & UI/UX jobs
CURATED_ART_DESIGN_JOBS = [
{
"title": "Senior UI/UX & Visual Brand Designer",
"company": "Figma",
"location": "Remote, USA",
"is_remote": True,
"department": "Art & Design",
"experience_level": "Senior",
"description": "Design interactive web tools, vector design systems, graphic assets, and brand identity systems for millions of global creators. Required skills: Figma, UI/UX Design, Typography, Visual Design, Motion Graphics.",
"salary_min": 140000,
"salary_max": 185000,
"job_url": "https://www.figma.com/careers/senior-ui-ux-brand-designer-remote",
"source": "greenhouse"
},
{
"title": "3D Environment Artist & Concept Illustrator",
"company": "Epic Games (Unreal Engine)",
"location": "Remote, USA",
"is_remote": True,
"department": "Art & Design",
"experience_level": "Mid-Level",
"description": "Create high-fidelity 3D environment assets, digital matte paintings, lighting setups, and visual concept art for Unreal Engine real-time virtual production.",
"salary_min": 105000,
"salary_max": 145000,
"job_url": "https://www.epicgames.com/careers/3d-environment-artist-remote",
"source": "greenhouse"
},
{
"title": "Graphic Designer & Creative Director",
"company": "LEGO Group",
"location": "Enfield, CT",
"is_remote": False,
"department": "Art & Design",
"experience_level": "Lead / Staff",
"description": "Lead packaging graphic design, print layout design, marketing campaign art direction, and brand visual guidelines at LEGO US Enfield headquarters.",
"salary_min": 95000,
"salary_max": 135000,
"job_url": "https://www.lego.com/en-us/aboutus/careers/graphic-designer-enfield-ct",
"source": "indeed"
},
{
"title": "Motion Graphics Animator & Video Producer",
"company": "ESPN / The Walt Disney Company",
"location": "Bristol, CT",
"is_remote": False,
"department": "Art & Design",
"experience_level": "Mid-Level",
"description": "Produce 2D/3D broadcast motion graphics, promo title animations, live graphics packages, and digital video assets at ESPN Bristol headquarters. Skills: After Effects, Cinema 4D, Maya, Premiere Pro.",
"salary_min": 85000,
"salary_max": 118000,
"job_url": "https://jobs.disneycareer.com/espn/motion-graphics-animator-bristol",
"source": "disney_ct"
},
{
"title": "2D Character Animator & Illustrator",
"company": "Duolingo",
"location": "Remote, USA",
"is_remote": True,
"department": "Art & Design",
"experience_level": "Mid-Level",
"description": "Illustrate vector character art, frame-by-frame character animations, and gamified learning visual assets for mobile and web apps. Skills: Vector Illustration, Lottie, After Effects, Character Rigging.",
"salary_min": 110000,
"salary_max": 150000,
"job_url": "https://careers.duolingo.com/job/2d-character-animator-illustrator",
"source": "greenhouse"
},
{
"title": "Fashion & Textile Designer",
"company": "Vineyard Vines",
"location": "Stamford, CT",
"is_remote": False,
"department": "Art & Design",
"experience_level": "Mid-Level",
"description": "Create seasonal apparel textile patterns, print graphics, garment tech packs, and apparel CAD designs at Vineyard Vines Stamford headquarters.",
"salary_min": 78000,
"salary_max": 108000,
"job_url": "https://www.vineyardvines.com/careers/fashion-textile-designer-stamford",
"source": "indeed"
},
{
"title": "Art Director — Commercial Advertising & Photography",
"company": "Gartner",
"location": "Stamford, CT (Hybrid)",
"is_remote": True,
"department": "Art & Design",
"experience_level": "Senior",
"description": "Direct global brand creative campaigns, photo shoots, event branding, editorial layout design, and digital advertisement collateral.",
"salary_min": 120000,
"salary_max": 160000,
"job_url": "https://jobs.gartner.com/art-director-stamford",
"source": "indeed"
}
]
def is_art_and_design_job(title: str, dept_text: str = "") -> bool:
combined = f"{title} {dept_text}".lower()
creative_keywords = [
"art", "artist", "designer", "design", "illustrator", "illustration",
"animator", "animation", "ui/ux", "ux", "ui ", "graphic", "motion",
"3d", "2d", "creative director", "concept art", "game art", "visual",
"brand designer", "textile", "fashion", "packaging", "multimedia"
]
return any(k in combined for k in creative_keywords)
def run_art_and_design_ingestion() -> List[Dict[Any, Any]]:
collected = []
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
print("[Art & Design Ingestion] Ingesting dedicated Art, Creative, Gaming & Animation company boards...")
# 1. Fetch from Greenhouse creative boards
for board_slug, company_name in ART_DESIGN_GREENHOUSE_BOARDS:
try:
url = f"https://boards-api.greenhouse.io/v1/boards/{board_slug}/jobs?content=true"
r = requests.get(url, headers=headers, timeout=6)
if r.status_code == 200:
data = r.json()
jobs = data.get("jobs", [])
print(f"[Art & Design Greenhouse] {company_name}: {len(jobs)} total board postings.")
for j in jobs:
title = clean_html_text(j.get("title", ""))
job_url = j.get("absolute_url", "")
if not title or not job_url:
continue
departments = j.get("departments", [])
dept_text = departments[0].get("name", "") if departments and isinstance(departments, list) else ""
if is_art_and_design_job(title, dept_text):
location_obj = j.get("location", {})
location_name = location_obj.get("name", "Remote") if isinstance(location_obj, dict) else str(location_obj)
is_remote = "remote" in location_name.lower() or "remote" in title.lower()
exp_level = determine_experience_level(title)
content_raw = j.get("content", "") or ""
desc_clean = clean_html_text(content_raw)
collected.append({
"title": title,
"company": company_name,
"location": location_name,
"is_remote": is_remote,
"department": "Art & Design",
"experience_level": exp_level,
"description": desc_clean[:2500] or f"Art & Design position at {company_name}.",
"salary_min": None,
"salary_max": None,
"job_url": job_url,
"source": "greenhouse"
})
except Exception as e:
print(f"[Art & Design Warning] {company_name} failed: {e}")
# 2. Add curated CT & Remote Art/Design/Media jobs
collected.extend(CURATED_ART_DESIGN_JOBS)
print(f"[Art & Design Ingestion] Total Art & Design postings collected: {len(collected)}")
return collected