#!/usr/bin/env python3 """Fetch Kickstarter data via FlareSolverr — handles HTML-wrapped JSON""" import urllib.request, json, time, sys, re FLARE = "http://localhost:8191/v1" all_projects = [] for page in range(1, 6): url = f"https://www.kickstarter.com/discover/advanced?category_id=34&sort=end_date&state=live&page={page}&format=json" payload = json.dumps({"cmd": "request.get", "url": url, "maxTimeout": 60000}).encode() req = urllib.request.Request(FLARE, data=payload, headers={"Content-Type": "application/json"}, method="POST") try: with urllib.request.urlopen(req, timeout=90) as resp: fs_resp = json.loads(resp.read()) except Exception as e: print(f"Page {page}: ERROR {e}", file=sys.stderr) continue if fs_resp.get('status') != 'ok': print(f"Page {page}: FS status={fs_resp.get('status')}", file=sys.stderr) continue raw = fs_resp['solution']['response'] # Extract JSON from
tag if wrapped in HTML
if '' in raw:
match = re.search(r'\s*(.+?)\s*
', raw, re.DOTALL)
if match:
raw = match.group(1)
try:
inner = json.loads(raw)
except json.JSONDecodeError as e:
print(f"Page {page}: JSON decode error: {e}, first 200 chars: {raw[:200]}", file=sys.stderr)
continue
projects = inner.get('projects', [])
print(f"Page {page}: {len(projects)} projects")
for p in projects:
photo = ''
if isinstance(p.get('photo'), dict):
photo = p['photo'].get('1024x576', '')
all_projects.append({
'name': p.get('name', ''),
'slug': p.get('slug', ''),
'url': f"https://www.kickstarter.com/projects/{p.get('slug','')}",
'photo': photo,
'pledged': float(p.get('pledged', 0) or 0),
'goal': float(p.get('goal', 0) or 0),
'backers': int(p.get('backers_count', 0) or 0),
'deadline': p.get('deadline', ''),
'state': p.get('state', ''),
'currency': p.get('currency', 'USD'),
})
time.sleep(2)
# Filter live
live = [p for p in all_projects if p['state'] == 'live']
print(f"\nTotal: {len(all_projects)}, Live: {len(live)}")
# Save
with open('/home/hermes/workspace/ks_data.json', 'w') as f:
json.dump(live, f, indent=2, ensure_ascii=False)
# Top 5
for i, p in enumerate(sorted(live, key=lambda x: x['pledged'], reverse=True)[:5]):
pct = round(p['pledged']/max(p['goal'],1)*100, 1)
print(f"{i+1}. {p['name']}: ${p['pledged']:,.0f} ({pct}%) - {p['backers']} backers")