205 lines
8.8 KiB
Python
205 lines
8.8 KiB
Python
import requests
|
|
import html
|
|
import re
|
|
import concurrent.futures
|
|
from typing import List, Dict, Any
|
|
from scrapers.ats_ingestion import clean_html_text, determine_experience_level, parse_is_us_remote
|
|
|
|
# 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 photorealistic 3D environments, textures, lighting, and concept digital paintings using Unreal Engine 5, Blender, Maya, and Substance Painter.",
|
|
"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 fetch_art_greenhouse_board(item: tuple, headers: dict) -> List[Dict[str, Any]]:
|
|
board_slug, company_name = item
|
|
results = []
|
|
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", [])
|
|
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, USA") if isinstance(location_obj, dict) else str(location_obj)
|
|
|
|
content_raw = j.get("content", "") or ""
|
|
desc_clean = clean_html_text(content_raw)
|
|
is_remote = parse_is_us_remote(location_name, title, desc_clean)
|
|
|
|
exp_level = determine_experience_level(title)
|
|
|
|
results.append({
|
|
"title": title,
|
|
"company": company_name,
|
|
"location": location_name if location_name != "Remote" else "Remote, USA",
|
|
"is_remote": is_remote,
|
|
"department": "Art, Design & Creative",
|
|
"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}")
|
|
return results
|
|
|
|
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] Concurrently fetching dedicated Art & Creative boards...")
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
|
|
results = executor.map(lambda item: fetch_art_greenhouse_board(item, headers), ART_DESIGN_GREENHOUSE_BOARDS)
|
|
for batch in results:
|
|
collected.extend(batch)
|
|
|
|
# 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
|