// Transfermarkt FIWC participants page → public/data/squadvalues.json // One page lists all 48 squads with total + average market value — far more // robust than scraping 48 squad pages. Values move slowly, so this is a // build-time artifact (re-run data:build to refresh). Used by the squad-value // model layer and the team/squad UI; never overrides results-based ratings. import { writeFileSync, mkdirSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; import { canonicalTeam, isKnownTeam } from '../src/lib/teams'; const URL = 'https://www.transfermarkt.com/weltmeisterschaft/teilnehmer/pokalwettbewerb/FIWC'; const OUT_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'public', 'data'); function euros(num: string, unit: string): number { const n = Number(num); return Math.round(n * (unit === 'bn' ? 1e9 : unit === 'm' ? 1e6 : 1e3)); } async function main(): Promise { const res = await fetch(URL, { headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 'Accept-Language': 'en-US,en;q=0.9', }, signal: AbortSignal.timeout(30_000), }); if (!res.ok) throw new Error(`transfermarkt ${res.status}`); const html = await res.text(); const out: Record = {}; for (const tr of html.split(']*title="([^"]+)"[^>]*href="\/[a-z0-9\-]+\/startseite\/verein\/\d+"/); const vals = [...tr.matchAll(/€([\d.]+)(bn|m|k)/g)].map((m) => euros(m[1]!, m[2]!)); if (!link || vals.length < 1) continue; const team = canonicalTeam(link[1]!); if (!isKnownTeam(team) || out[team]) continue; // 48 qualifiers only, first table wins const totalValue = Math.max(...vals); const avgValue = vals.length > 1 ? Math.min(...vals) : Math.round(totalValue / 26); out[team] = { totalValue, avgValue }; } const teams = Object.keys(out); if (teams.length < 40) { throw new Error(`only parsed ${teams.length}/48 squads — page layout may have changed; aborting (stale file kept)`); } mkdirSync(OUT_DIR, { recursive: true }); writeFileSync( join(OUT_DIR, 'squadvalues.json'), JSON.stringify({ fetchedAt: new Date().toISOString(), source: 'transfermarkt.com', teams: out }), ); const top = teams.sort((a, b) => out[b]!.totalValue - out[a]!.totalValue).slice(0, 6) .map((t) => `${t} €${(out[t]!.totalValue / 1e9).toFixed(2)}bn`).join(', '); console.log(`squad values → public/data/squadvalues.json (${teams.length} teams)`); console.log(` top: ${top}`); } main().catch((e) => { console.error(e); process.exit(1); });