{
  "version": "1.0.0",
  "exported_at": "2026-06-02T00:00:00.000Z",
  "project": {
    "name": "Rushbet Scraper",
    "description": "Rushbet Colombia football odds scraper inferred from the Octoparse template. Extracts Titulo_Ficha/country, Liga/competition, Fecha_Hora, Equipo1, Equipo2, Cuota1, CuotaEmpate, Cuota2, Total_Goles1, and Total_Goles2. Rushbet is a dynamic Kambi sportsbook SPA rather than a numbered paginated listing; this template opens the football route, dismisses cookies best-effort, reads the sportsbook JSON endpoints already loaded by the page, renders normalized hidden rows, then exports those rows. This avoids unreliable visible DOM headers such as DEPORTES, Competición, or Todo Fútbol. If JSON endpoints are unavailable, the script falls back to visible event cards with blank country/league. CAPTCHA, geo-blocking, login, age checks, or changed Kambi endpoint structure may require manual intervention.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "set-window-size-1",
      "block_type": "process",
      "title": "Set Window Size",
      "description": "Set browser window dimensions",
      "position_x": 120,
      "position_y": 220,
      "config": {
        "width": 1920,
        "height": 1080,
        "color": "bg-[#4589ff]"
      }
    },
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 480,
      "position_y": 220,
      "config": {
        "url": "https://www.rushbet.co/?page=sportsbook#filter/football",
        "color": "bg-[#4589ff]"
      }
    },
    {
      "block_id": "wait-for-page-load-1",
      "block_type": "process",
      "title": "Wait for Page Load",
      "description": "Wait for page to finish loading",
      "position_x": 840,
      "position_y": 220,
      "config": {
        "timeout": 45,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Run JavaScript on the page",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "jsCode": "(async () => { const clean = v => String(v || '').replace(/\\s+/g, ' ').trim(); const txt = e => clean((e && (e.innerText || e.textContent)) || ''); const clickables = Array.from(document.querySelectorAll('button, [role=button], a')); const consentRe = /(accept|aceptar|acepto|allow|agree|continuar|entendido|permitir)/i; clickables.filter(el => consentRe.test(txt(el))).slice(0, 5).forEach(el => { try { el.click(); } catch (e) {} }); Array.from(document.querySelectorAll('[aria-expanded=false], button[class*=expand], button[class*=collapsed], [class*=accordion] button')).slice(0, 150).forEach(el => { try { el.click(); } catch (e) {} }); window.scrollTo(0, document.body.scrollHeight); await new Promise(r => setTimeout(r, 1200)); window.scrollTo(0, 0); const urls = new Set(); try { performance.getEntriesByType('resource').forEach(e => { const u = e.name || ''; if (/offering\\/v\\d+\\//i.test(u) && /\\.json/i.test(u) && /(football|soccer|fútbol|futbol|listView|event)/i.test(u)) urls.add(u); }); } catch (e) {} Array.from(document.scripts).forEach(s => { const st = s.textContent || ''; let m = st.match(/https?:\\/\\/[^\\s'\\\"<>]+offering\\/v\\d+\\/[^\\s'\\\"<>]+?\\.json[^\\s'\\\"<>]*/gi) || []; m.forEach(u => { if (/(football|soccer|fútbol|futbol|listView|event)/i.test(u)) urls.add(u.replace(/\\\\u0026/g, '&')); }); }); const rows = []; const seen = new Set(); const badLabel = /^(fútbol|football|soccer|todo fútbol|todo futbol|deportes|competición|competicion)$/i; function odd(o) { let v = o && (o.oddsDecimal || o.decimalOdds || o.oddsAmerican || o.americanOdds || o.odds || o.price || o.value); if (v == null) return ''; if (typeof v === 'number') { if (v >= 1000) return (v / 1000).toFixed(2); return String(v); } v = clean(v); const m = v.match(/[+-]?\\d+(?:\\.\\d+)?/); return m ? m[0] : v; } function pathNames(ev) { const p = ev && (ev.path || ev.categoryPath || ev.eventPath || ev.breadcrumbs); if (Array.isArray(p)) return p.map(x => clean((x && (x.name || x.label || x.title)) || x)).filter(Boolean).filter(x => !badLabel.test(x)); return []; } function teams(ev) { let h = clean(ev.homeName || ev.homeTeamName || ev.home || ev.participant1Name || ev.team1Name); let a = clean(ev.awayName || ev.awayTeamName || ev.away || ev.participant2Name || ev.team2Name); if ((!h || !a) && Array.isArray(ev.participants)) { const ps = ev.participants.map(p => clean(p.name || p.label || p.participantName)).filter(Boolean); h = h || ps[0] || ''; a = a || ps[1] || ''; } if ((!h || !a) && ev.name) { const parts = clean(ev.name).split(/\\s+(?:-|v|vs|vs\\.)\\s+/i).map(clean).filter(Boolean); h = h || parts[0] || ''; a = a || parts[1] || ''; } return [h, a]; } function eventTime(ev) { const v = ev.start || ev.startTime || ev.eventStart || ev.openDate || ev.startDate || ev.date; if (!v) return ''; try { return new Date(v).toISOString().replace('T', ' ').slice(0, 19); } catch (e) { return clean(v); } } function add(item, ctx) { const ev = item.event || item.fixture || item.match || item; if (!ev || typeof ev !== 'object') return; const ts = teams(ev); if (!ts[0] || !ts[1]) return; const key = ts[0] + '|' + ts[1] + '|' + eventTime(ev); if (seen.has(key)) return; let offers = item.betOffers || item.betoffers || item.markets || ev.betOffers || ev.markets || []; if (!Array.isArray(offers)) offers = Object.values(offers || {}); let three = null; let totals = null; for (const bo of offers) { const outs = Array.isArray(bo.outcomes) ? bo.outcomes : Array.isArray(bo.selections) ? bo.selections : []; const label = clean((bo.criterion && (bo.criterion.label || bo.criterion.name)) || bo.label || bo.name || bo.marketName || bo.type); if (!three && outs.length >= 3 && (/(resultado|ganador|1x2|match odds|full time)/i.test(label) || offers.indexOf(bo) === 0)) three = outs; if (!totals && outs.length >= 2 && /(total|goles|goals|over\\/under|más de|mas de|menos de)/i.test(label)) totals = outs; } const p = pathNames(ev); const liga = clean(ev.leagueName || ev.competitionName || ev.tournamentName || ev.eventGroupName || ev.groupName || ev.group || ev.league || ev.competition || ctx.league || p[p.length - 1] || ''); const titulo = clean(ev.countryName || ev.regionName || ev.categoryName || ev.country || ev.region || ctx.country || (p.length > 1 ? p[p.length - 2] : '') || ''); seen.add(key); rows.push({ titulo: badLabel.test(titulo) ? '' : titulo, liga: badLabel.test(liga) ? '' : liga, fecha: eventTime(ev), e1: ts[0], e2: ts[1], c1: ts[0] + ':' + (three ? odd(three[0]) : ''), ce: three ? odd(three[1]) : '', c2: ts[1] + ':' + (three ? odd(three[2]) : ''), tg1: totals ? odd(totals[0]) : '', tg2: totals ? odd(totals[1]) : '' }); } function walk(x, ctx = {}, depth = 0) { if (!x || depth > 8) return; if (Array.isArray(x)) { x.forEach(v => walk(v, ctx, depth + 1)); return; } if (typeof x !== 'object') return; if (x.event || x.homeName || x.awayName || x.participants || x.betOffers || x.markets) add(x, ctx); let nctx = ctx; const nm = clean(x.name || x.label || x.title); if (nm && !badLabel.test(nm)) { if (/country|region/i.test(String(x.type || x.kind || x.categoryType || ''))) nctx = Object.assign({}, ctx, { country: nm }); if (/league|competition|tournament|group/i.test(String(x.type || x.kind || x.categoryType || ''))) nctx = Object.assign({}, ctx, { league: nm }); } for (const k of Object.keys(x)) { if (/^(parent|children)$/i.test(k)) continue; if (/(eventGroups|competitions|leagues|events|fixtures|matches|items|coupons|groups|sports)/i.test(k) || typeof x[k] === 'object') walk(x[k], nctx, depth + 1); } } const candidates = Array.from(urls).filter(u => !/statistics|participant|image|translation/i.test(u)).slice(0, 20); for (const u of candidates) { try { const res = await fetch(u, { credentials: 'include' }); if (!res.ok) continue; const json = await res.json(); walk(json); } catch (e) {} } if (!rows.length) { const rowSel = '.KambiBC-event-item, .KambiBC-event-list__event, [data-testid*=event-list-item], [class*=event-card], [class*=eventItem]'; Array.from(document.querySelectorAll(rowSel)).forEach(r => { const names = Array.from(r.querySelectorAll('.KambiBC-event-participants__name, [class*=participant][class*=name], [class*=competitor][class*=name], [data-testid*=participant]')).map(txt).filter(Boolean); const odds = Array.from(r.querySelectorAll('.KambiBC-mod-outcome__odds, [class*=outcome][class*=odds], [class*=odds]')).map(txt).filter(t => /^[+-]?\\d+(?:\\.\\d+)?$/.test(t)); if (names[0] && names[1]) rows.push({ titulo: '', liga: '', fecha: txt(r.querySelector('time, [datetime], [class*=start-time], [class*=event-time], [class*=date], [data-testid*=time]')), e1: names[0], e2: names[1], c1: names[0] + ':' + (odds[0] || ''), ce: odds[1] || '', c2: names[1] + ':' + (odds[2] || ''), tg1: odds[3] || '', tg2: odds[4] || '' }); }); } document.querySelectorAll('#uscraper-rushbet-normalized').forEach(e => e.remove()); const root = document.createElement('div'); root.id = 'uscraper-rushbet-normalized'; root.style.cssText = 'display:block; position:absolute; left:-99999px; top:0; width:1px; height:1px; overflow:hidden;'; rows.forEach(r => { const d = document.createElement('div'); d.className = 'uscraper-rushbet-row'; d.innerHTML = '<span class=\"titulo\"></span><span class=\"liga\"></span><span class=\"fecha\"></span><span class=\"e1\"></span><span class=\"e2\"></span><span class=\"c1\"></span><span class=\"ce\"></span><span class=\"c2\"></span><span class=\"tg1\"></span><span class=\"tg2\"></span>'; d.querySelector('.titulo').textContent = r.titulo || ''; d.querySelector('.liga').textContent = r.liga || ''; d.querySelector('.fecha').textContent = r.fecha || ''; d.querySelector('.e1').textContent = r.e1 || ''; d.querySelector('.e2').textContent = r.e2 || ''; d.querySelector('.c1').textContent = r.c1 || ''; d.querySelector('.ce').textContent = r.ce || ''; d.querySelector('.c2').textContent = r.c2 || ''; d.querySelector('.tg1').textContent = r.tg1 || ''; d.querySelector('.tg2').textContent = r.tg2 || ''; root.appendChild(d); }); document.body.appendChild(root); return rows.length; })();",
        "waitForCompletion": true,
        "timeout": 30,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "duration": 4,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until normalized rows appear",
      "position_x": 1920,
      "position_y": 220,
      "config": {
        "selector": ".uscraper-rushbet-row",
        "timeout": 45,
        "visible": false,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2280,
      "position_y": 220,
      "config": {
        "rowSelector": ".uscraper-rushbet-row",
        "fileName": "rushbet-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "create",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "Titulo_Ficha",
            "selector": ".titulo",
            "attribute": "text"
          },
          {
            "name": "Liga",
            "selector": ".liga",
            "attribute": "text"
          },
          {
            "name": "Fecha_Hora",
            "selector": ".fecha",
            "attribute": "text"
          },
          {
            "name": "Equipo1",
            "selector": ".e1",
            "attribute": "text"
          },
          {
            "name": "Equipo2",
            "selector": ".e2",
            "attribute": "text"
          },
          {
            "name": "Cuota1",
            "selector": ".c1",
            "attribute": "text"
          },
          {
            "name": "CuotaEmpate",
            "selector": ".ce",
            "attribute": "text"
          },
          {
            "name": "Cuota2",
            "selector": ".c2",
            "attribute": "text"
          },
          {
            "name": "Total_Goles1",
            "selector": ".tg1",
            "attribute": "text"
          },
          {
            "name": "Total_Goles2",
            "selector": ".tg2",
            "attribute": "text"
          }
        ]
      }
    },
    {
      "block_id": "end-1",
      "block_type": "output",
      "title": "End",
      "description": "Terminate execution flow",
      "position_x": 2640,
      "position_y": 220,
      "config": {
        "color": "bg-[#8d8d8d]"
      }
    }
  ],
  "connections": [
    {
      "from_block_id": "set-window-size-1",
      "from_connector_id": "right",
      "to_block_id": "navigate-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "navigate-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-page-load-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-page-load-1",
      "from_connector_id": "right",
      "to_block_id": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-1",
      "from_connector_id": "right",
      "to_block_id": "sleep-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-1",
      "from_connector_id": "right",
      "to_block_id": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-1",
      "from_connector_id": "right",
      "to_block_id": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-1",
      "from_connector_id": "right",
      "to_block_id": "end-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-entry",
      "element_type": "group",
      "title": "Entry & Setup",
      "color": "#4589ff",
      "position_x": 48,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "set-window-size-1"
        ]
      }
    },
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 408,
      "position_y": 116,
      "width": 1760,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1128,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2208,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-control",
      "element_type": "group",
      "title": "Control Flow",
      "color": "#8d8d8d",
      "position_x": 2568,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "end-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Rushbet Colombia football odds scraper inferred from the Octoparse template. Extracts Titulo_Ficha/country, Liga/competition, Fecha_Hora, Equipo1, Equipo2, Cuota1, CuotaEmpate, Cuota2, Total_Goles1, and Total_Goles2. Rushbet is a dynamic Kambi sportsbook SPA rather than a numbered paginated listing; this template opens the football route, dismisses cookies best-effort, reads the sportsbook JSON endpoints already loaded by the page, renders normalized hidden rows, then exports those rows. This avoids unreliable visible DOM headers such as DEPORTES, Competición, or Todo Fútbol. If JSON endpoints are unavailable, the script falls back to visible event cards with blank country/league. CAPTCHA, geo-blocking, login, age checks, or changed Kambi endpoint structure may require manual intervention.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(async () => { const clean = v => String(v || '').replace(/\\s+/g, ' ').trim(); const txt = e => clea...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 200,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Extracts rows matching `.uscraper-rushbet-row`. Confirm row count > 0 before running at scale.",
      "color": "#ee5396",
      "position_x": 2480,
      "position_y": 200,
      "width": 340,
      "height": 111,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    }
  ]
}