← back to Japan Enrich
onboard_new_wallcoverings.py
71 lines
#!/usr/bin/env python3
"""Onboard the 9 NEW Sangetsu wallcovering patterns the sitemap missed (they sit in the
'uncategorized' category). Colorways come from the Store API pa_full-collection attribute
terms; per-colorway images from the variations; distributor brand scraped from the page.
Appends to staging/sangetsu-staging.jsonl (our format) + staging/sangetsu-brands.json. $0 local."""
import json, os, re, subprocess, urllib.request
HERE = os.path.dirname(__file__)
STORE = os.path.join(HERE, 'staging', 'sangetsu-storeapi.jsonl')
STAGING = os.path.join(HERE, 'staging', 'sangetsu-staging.jsonl')
BRANDS = os.path.join(HERE, 'staging', 'sangetsu-brands.json')
CHROME = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'
NEW = {'park-tweed-wallpaper','paisley-park-wallpaper','felt-wallpaper','summer-weave-wallpaper',
'moondust-rays-wallpaper','cleas-2025-28-wallpaper','essential-wallpaper','trail-line-wallpaper','debonair-wallpaper'}
def api(u): return json.loads(urllib.request.urlopen(urllib.request.Request(u, headers={'User-Agent': UA}), timeout=30).read().decode('utf-8','ignore'))
BR = re.compile(r'psg-single-brands-main"?>(.*?)</div>', re.S | re.I); LN = re.compile(r'/brand/([a-z0-9-]+)/"[^>]*>([^<]+)<', re.I)
def brand_of(url):
try:
h = subprocess.run([CHROME,"--headless=new","--disable-gpu","--no-sandbox","--virtual-time-budget=12000","--dump-dom",url],
capture_output=True, timeout=45, text=True, errors='ignore').stdout
m = BR.search(h or ''); a = LN.search(m.group(1)) if m else None
import html as H
return (H.unescape(a.group(2).strip()), a.group(1)) if a else (None, None)
except Exception: return (None, None)
def main():
prods = {}
for l in open(STORE):
p = json.loads(l); s = (p.get('slug') or '').lower()
perm = (p.get('permalink') or '').rstrip('/').split('/')[-1].lower()
if s in NEW or perm in NEW: prods[perm or s] = p
print(f"matched {len(prods)}/9 new patterns")
brands = json.load(open(BRANDS)) if os.path.exists(BRANDS) else {}
added = 0
with open(STAGING, 'a') as out:
for key, p in prods.items():
url = p['permalink']
# colorway SKUs from pa_full-collection terms
skus = []
for at in (p.get('attributes') or []):
if at.get('taxonomy') == 'pa_full-collection':
skus = [t['name'] for t in at.get('terms', [])]
# per-colorway images from variations (match variation attr value → image)
imgs = {}
try:
for v in api(f"https://www.sangetsu-goodrich.co.th/wp-json/wc/store/v1/products?type=variation&per_page=100&parent={p['id']}"):
val = None
for va in (v.get('attributes') or []):
if 'collection' in (va.get('name','').lower()): val = va.get('value')
src = (v.get('images') or [{}])[0].get('src')
if val and src: imgs[val] = src
except Exception: pass
if not imgs and p.get('images'): # fallback: main image for all
for s in skus: imgs[s] = p['images'][0]
dist, slug = brand_of(url)
rec = {"source":"sangetsu","source_url":url,"pattern":p['name'],"overview":None,
"spec":{"width":None,"type":None,"weight":None,"backing":None,"is_grasscloth":False,"is_metallic":False},
"colorway_skus":skus,"colorway_count":len(skus),"sku_images":imgs,
"mfr_prefix":None,"status":"storeapi-new","distributor":dist,"distributor_direct":False}
out.write(json.dumps(rec, ensure_ascii=False) + '\n')
brands[url] = {"distributor": dist, "slug": slug}
added += 1
print(f" + {p['name']:28s} {len(skus):3d} colorways brand={dist}")
json.dump(brands, open(BRANDS,'w'), ensure_ascii=False, indent=0)
print(f"\nappended {added} new wallcovering patterns to staging + brand map")
if __name__ == '__main__':
main()