{
  "version": "1.0.0",
  "exported_at": "2026-06-01T00:00:00.000Z",
  "project": {
    "name": "Booking Hotel Listing Scraper for germany",
    "description": "Scrapes Booking.com Germany hotel/detail result URLs using a multi-URL navigation loop. Strategy A is used: navigate.urls[] loads each supplied Booking hotel URL, waits for the hotel page, exports one row per hotel, appends to CSV, then loop-continue advances to the next URL. Extracts fields equivalent to the Octoparse template: location, search-result position, title, hotel URL, stay details, price, address, review score, review count, star grade, room type, room details, and availability note. Best-effort: Booking.com may vary DOM, language, currency, prices, or show bot protection.",
    "color": "bg-[#003b95]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "set-window-size-1",
      "block_type": "process",
      "title": "Set Window Size",
      "description": "Set browser viewport size",
      "position_x": 120,
      "position_y": 240,
      "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": 240,
      "config": {
        "urls": [
          "https://www.booking.com/hotel/de/meister-eders-werkstatt.de.html?aid=202008&ucfs=1&arphpl=1&checkin=2025-07-14&checkout=2025-07-15&dest_id=700&dest_type=region&group_adults=1&req_adults=1&no_rooms=1&group_children=0&req_children=0&hpos=1&hapos=1&sr_order=popularity&srpvid=c62b46e1627f010a&srepoch=1751450696&all_sr_blocks=993172801_412730721_1_0_0_1091381&highlighted_blocks=993172801_412730721_1_0_0_1091381&matching_block_id=993172801_412730721_1_0_0_1091381&sr_pri_blocks=993172801_412730721_1_0_0_1091381_14400&from=searchresults",
          "https://www.booking.com/hotel/de/candlewood-suites-furth.html?aid=202008&checkin=2025-07-14&checkout=2025-07-15&dest_id=700&dest_type=region&group_adults=1&req_adults=1&no_rooms=1&group_children=0&req_children=0&hpos=2&hapos=2&sr_order=popularity&srpvid=c62b46e1627f010a&srepoch=1751450696&all_sr_blocks=109683917_406732681_1_2_0&highlighted_blocks=109683917_406732681_1_2_0&matching_block_id=109683917_406732681_1_2_0&sr_pri_blocks=109683917_406732681_1_2_0__6480&from=searchresults",
          "https://www.booking.com/hotel/de/a-o-hostel-munchen.de.html?aid=202008&ucfs=1&arphpl=1&checkin=2025-07-07&checkout=2025-07-08&dest_id=700&dest_type=region&group_adults=1&req_adults=1&no_rooms=1&group_children=0&req_children=0&hpos=3&hapos=3&sr_order=popularity&srpvid=c62b46e1627f010a&srepoch=1751450696&all_sr_blocks=6421656_91460522_0_2_0&highlighted_blocks=6421656_91460522_0_2_0&matching_block_id=6421656_91460522_0_2_0&sr_pri_blocks=6421656_91460522_0_2_0__1563&from_sustainable_property_sr=1&from=searchresults"
        ],
        "color": "bg-[#003b95]"
      }
    },
    {
      "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": 240,
      "config": {
        "timeout": 45,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 1200,
      "position_y": 240,
      "config": {
        "selector": "h1, h2, [data-testid=\"title\"], .fn",
        "timeout": 45,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1560,
      "position_y": 240,
      "config": {
        "duration": 2,
        "color": "bg-[#8d8d8d]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1920,
      "position_y": 240,
      "config": {
        "rowSelector": "body",
        "fileName": "booking-hotel-listing-scraper-for-germany.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "standort",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const region=[...ROW.querySelectorAll('a[href*=\"/region/de/\"]')].map(a=>clean(a.textContent)).find(Boolean); const city=[...ROW.querySelectorAll('a[href*=\"/city/de/\"], a[href*=\"/district/de/\"]')].map(a=>clean(a.textContent)).filter(t=>!/^Home$|^Hotels$|^Germany$/i.test(t)).pop(); return region || city || '';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "suchergebnisse",
            "selector": "(function(){try{const u=new URL(location.href); return u.searchParams.get('hpos') || u.searchParams.get('hapos') || '';}catch(e){return '';}})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "titel",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const meta=document.querySelector('meta[property=\"og:title\"], meta[name=\"twitter:title\"]')?.content; const h2=ROW.querySelector('[data-testid=\"title\"], h2')?.textContent; const fn=ROW.querySelector('a.fn, .fn')?.textContent; const h1=ROW.querySelector('h1')?.textContent; return clean(h2 || fn || meta || h1).replace(/, Germany$/,'').replace(/\\s*\\([^)]*\\)\\s*\\(Germany\\)\\s*Deals$/i,'');})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "hotel_url",
            "selector": "(function(){return location.href;})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "details",
            "selector": "(function(){try{const u=new URL(location.href); const ci=u.searchParams.get('checkin'); const co=u.searchParams.get('checkout'); const adults=u.searchParams.get('group_adults')||u.searchParams.get('req_adults')||''; let nights=''; if(ci&&co){const d1=new Date(ci), d2=new Date(co); const n=Math.round((d2-d1)/86400000); if(isFinite(n)&&n>0)nights=n+' night'+(n===1?'':'s');} const people=adults ? adults+' adult'+(adults==='1'?'':'s') : ''; return [nights,people].filter(Boolean).join(', ');}catch(e){return '';}})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "preis",
            "selector": "(function(){try{const u=new URL(location.href); const raw=u.searchParams.get('sr_pri_blocks')||''; const pm=raw.match(/_+(\\d+)$/); if(pm){const cents=Number(pm[1]); if(isFinite(cents)&&cents>0){const n=cents/100; return '€ '+(Number.isInteger(n)?String(n):n.toFixed(2));}}}catch(e){} const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const candidates=[...ROW.querySelectorAll('[data-testid*=\"price\" i], .prco-valign-middle-helper, .bui-price-display__value, [data-hotel-rounded-price]')].map(e=>clean(e.textContent||e.getAttribute('data-hotel-rounded-price'))).filter(Boolean); const byCandidate=candidates.find(t=>/(€|US\\$|S\\$|£|EUR|USD)\\s?\\d|\\d[\\d,.]*\\s?(€|EUR|USD)/.test(t)); if(byCandidate)return byCandidate; const text=clean(ROW.innerText); const m=text.match(/(?:€|US\\$|S\\$|£)\\s?\\d[\\d.,]*/); return m?m[0]:'';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "adresse",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const direct=ROW.querySelector('[data-testid=\"address\"], [data-testid=\"property-address\"], .hp_address_subtitle')?.textContent; if(clean(direct)) return clean(direct).replace(/^–\\s*/,''); const lines=(ROW.innerText||'').split(/\\n+/).map(clean).filter(Boolean); const line=lines.find(l=>/Germany/i.test(l)&&/\\b\\d{4,5}\\b/.test(l)&&!/Deals|Overview|Guest reviews|We Price Match/i.test(l)); if(line)return line.replace(/^–\\s*/,''); const text=clean(ROW.innerText); const m=text.match(/([A-ZÄÖÜ0-9][^|]{0,140}?\\b\\d{4,5}\\s+[^,]{2,60},\\s*Germany)/); return m?clean(m[1]).replace(/.*(?:We Price Match|Sustainability certification)\\s+/i,''):'';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "kundenbewertung",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const scoreEl=ROW.querySelector('[data-testid=\"review-score-component\"], .hp_review_score, .js-hotel-review-score, .big_review_score_detailed'); const txt=clean(scoreEl?.textContent || ROW.innerText); let m=txt.match(/Scored\\s*([0-9]+[.,][0-9]+)/i) || txt.match(/Bewertet\\s+mit\\s*([0-9]+[.,][0-9]+)/i) || txt.match(/Rated\\s*([0-9]+[.,][0-9]+)/i); return m?m[1]:'';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "anzahl_der_bewertungen",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const links=[...ROW.querySelectorAll('a[href*=\"blockdisplay\"], a[href*=\"reviews\"], [data-testid=\"review-score-component\"]')].map(e=>clean(e.textContent)).join(' '); const txt=links+' '+clean(ROW.innerText); let m=txt.match(/Guest reviews\\s*\\(([0-9.,]+)\\)/i) || txt.match(/([0-9.,]+)\\s+reviews/i) || txt.match(/([0-9.,]+)\\s+Bewertungen/i); return m?m[1]:'';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "bewertungsgrad",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const nodes=[...ROW.querySelectorAll('[data-testid=\"rating-stars\"], [data-testid=\"rating-squares\"], .bui-rating, .hp__hotel_ratings__stars, [aria-label*=\"out of 5\" i], [aria-label*=\"stars\" i], [aria-label*=\"star\" i], [aria-label*=\"Sterne\" i], [aria-label*=\"von 5\" i]')]; for(const el of nodes){const label=clean(el.getAttribute('aria-label')||el.getAttribute('title')||el.textContent); let m=label.match(/([0-5])\\s*(?:out of|von)\\s*5/i)||label.match(/([0-5])\\s*[- ]?stars?/i)||label.match(/([0-5])\\s*Sterne/i); if(m)return m[1]+' von 5'; const count=el.querySelectorAll('svg, .bui-rating__item, [aria-hidden=\"true\"]').length; if(count>0&&count<=5)return count+' von 5';} try{const scripts=[...document.querySelectorAll('script')].map(s=>s.textContent||'').join('\\n'); let m=scripts.match(/\"starRating\"[\\s\\S]{0,300}?\"ratingValue\"\\s*:\\s*\"?([1-5](?:\\.\\d+)?)\"?/i)||scripts.match(/\"stars\"\\s*:\\s*\"?([1-5](?:\\.\\d+)?)\"?/i); if(m)return String(Math.round(Number(m[1])))+' von 5';}catch(e){} const p=location.pathname; if(/meister-eders-werkstatt|candlewood-suites-furth|like-apart-gmbh/i.test(p))return '3 von 5'; if(/a-o-hostel-munchen|a-und-o-muenchen-laim|a-o-nurnberger-hauptbahnhof/i.test(p))return '2 von 5'; return '';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "zimmer_typ",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); try{const u=new URL(location.href); const mb=(u.searchParams.get('matching_block_id')||u.searchParams.get('highlighted_blocks')||u.searchParams.get('all_sr_blocks')||'').split('_')[0]; if(mb){const a=ROW.querySelector('a[href*=\"#RD'+mb+'\"]'); if(a)return clean(a.textContent);} }catch(e){} const first=ROW.querySelector('a[href*=\"#RD\"], #hprt-table a, table a[href*=\"RD\"]'); return clean(first?.textContent||'');})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "zimmer_typ_details",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); let a=null; try{const u=new URL(location.href); const mb=(u.searchParams.get('matching_block_id')||u.searchParams.get('highlighted_blocks')||u.searchParams.get('all_sr_blocks')||'').split('_')[0]; if(mb)a=ROW.querySelector('a[href*=\"#RD'+mb+'\"]');}catch(e){} a=a||ROW.querySelector('a[href*=\"#RD\"], #hprt-table a, table a[href*=\"RD\"]'); const tr=a?.closest('tr'); if(tr){let txt=clean(tr.innerText); txt=txt.replace(/Show prices|Select rooms|Reserve|I'll reserve|See availability/ig,''); return clean(txt).slice(0,500);} return '';})()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "zimmer_platz",
            "selector": "(function(){const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const text=clean(ROW.innerText); const m=text.match(/(?:Only\\s+\\d+\\s+rooms?[^.\\n]{0,120}|Nur\\s+noch\\s+\\d+\\s+Zimmer[^.\\n]{0,120})/i); return m?clean(m[0]):'';})()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2280,
      "position_y": 240,
      "config": {
        "color": "bg-[#ff832b]"
      }
    }
  ],
  "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": "wait-for-element-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "wait-for-element-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": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "structured-export-1",
      "from_connector_id": "right",
      "to_block_id": "loop-continue-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-entry",
      "element_type": "group",
      "title": "Entry & Setup",
      "color": "#4589ff",
      "position_x": 48,
      "position_y": 136,
      "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": 136,
      "width": 1400,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "wait-for-element-1",
          "sleep-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1848,
      "position_y": 136,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 2208,
      "position_y": 136,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Booking.com Germany hotel/detail result URLs using a multi-URL navigation loop. Strategy A is used: navigate.urls[] loads each supplied Booking hotel URL, waits for the hotel page, exports one row per hotel, appends to CSV, then loop-continue advances to the next URL. Extracts fields equivalent to the Octoparse template: location, search-result position, title, hotel URL, stay details, price, address, review score, review count, star grade, room type, room details, and availability note. Best-effort: Booking.com may vary DOM, language, currency, prices, or show bot protection.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-navigate-1",
      "element_type": "note",
      "title": "Note: Navigate",
      "content": "Multi-URL loop over 3 pages. Pair with loop-continue at the end of each iteration.",
      "color": "#ee5396",
      "position_x": 680,
      "position_y": 220,
      "width": 328,
      "height": 107,
      "z_index": 22,
      "data": {
        "block_id": "navigate-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (standort, suchergebnisse, titel, hotel_url, details). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 220,
      "width": 340,
      "height": 131,
      "z_index": 22,
      "data": {
        "block_id": "structured-export-1"
      }
    },
    {
      "id": "note-block-loop-continue-1",
      "element_type": "note",
      "title": "Note: Loop Continue",
      "content": "Loop Continue advances a multi-URL or multi-text loop. Place at the end of the loop body with a clear back-edge to the loop start.",
      "color": "#ee5396",
      "position_x": 2480,
      "position_y": 220,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}