{
  "version": "1.0.0",
  "exported_at": "2026-05-31T00:00:00.000Z",
  "project": {
    "name": "Bookingcom Hotel Listing Scraper",
    "description": "Scrapes Booking.com hotel/accommodation detail URLs equivalent to the Octoparse Booking.com Hotel Listing Scraper. Extracts hotel title, location, link, distance, review score, review description, review count, property details, price, room type, availability dates, amenities, property description, and image URL. Navigation strategy: multi-URL loop over Booking.com hotel URLs using navigate.urls with structured-export in append mode and loop-continue so all supplied hotel pages are collected into one CSV. Booking.com may personalize or hide prices/availability by date, region, cookies, bot checks, or CAPTCHA; fields not publicly shown may export blank.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 120,
      "position_y": 220,
      "config": {
        "urls": [
          "https://www.booking.com/hotel/cn/stey-wangfujing.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/beijing-guizhou.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/beijing-zhong-an.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/bei-jing-tian-lun-song-he-da-fan-dian.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/holiday-inn-express-beijing-dongzhimen.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/park-plaza-beijing-wangfujing.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/bei-jing-bao-chen-fan-dian.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl",
          "https://www.booking.com/hotel/cn/7days-inn-beijing-west-railway-station-south-square-metro-station.html?aid=304142&checkin=2024-04-20&checkout=2024-04-21&group_adults=2&no_rooms=1&group_children=0#hotelTmpl"
        ],
        "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": 480,
      "position_y": 220,
      "config": {
        "timeout": 45
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 840,
      "position_y": 220,
      "config": {
        "duration": 2
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "selector": "h1",
        "timeout": 30,
        "visible": true
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1560,
      "position_y": 220,
      "config": {
        "rowSelector": "body",
        "fileName": "booking_com_scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "title",
            "selector": "(() => { const d=ROW.ownerDocument; const meta=(key,val)=>Array.from(d.getElementsByTagName('meta')).find(m=>m.getAttribute(key)===val)?.content||''; const h=d.querySelector('h1'); let t=h?h.textContent.trim():''; if(!t) t=meta('property','og:title') || d.title || ''; t=t.replace(/\\s*\\([^)]*\\).*$/,'').replace(/\\s+/g,' ').trim(); return t; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "location",
            "selector": "(() => { const d=ROW.ownerDocument; const clean=s=>(s||'').replace(/\\s+/g,' ').trim(); const city=Array.from(d.querySelectorAll(\"a[href*='/city/']\")).map(a=>clean(a.textContent)).find(t=>t && !/Cities|Hotels|Home/i.test(t)) || ''; const district=Array.from(d.querySelectorAll(\"a[href*='/district/']\")).map(a=>clean(a.textContent)).find(t=>t && !/Districts/i.test(t)) || ''; if(district && city) return district + ', ' + city; const addr=clean(d.querySelector('[data-testid=address]')?.textContent || d.querySelector('.hp_address_subtitle')?.textContent || ''); const m=addr.match(/,\\s*([^,]+),\\s*\\d{4,}\\s+([^,]+),\\s*China/i); if(m) return clean(m[1] + ', ' + m[2]); return addr || city; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "link",
            "selector": "(() => ROW.ownerDocument.location.href)()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "distance",
            "selector": "(() => { const txt=(ROW.innerText||'').replace(/\\s+/g,' '); const m=txt.match(/\\b\\d+(?:\\.\\d+)?\\s*(?:miles?|mi|km)\\s+from\\s+(?:the\\s+)?center\\b/i); return m?m[0]:''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "review_score",
            "selector": "(() => { const d=ROW.ownerDocument; const el=d.querySelector('.hp_review_score') || d.querySelector('[data-testid=review-score-component]') || d.querySelector('a[href*=blockdisplay4]'); const txt=(el?el.textContent:'').replace(/\\s+/g,' '); const nums=txt.match(/\\d+(?:\\.\\d+)?/g)||[]; for(const n of nums){ if(/^\\d\\.\\d\\d+/.test(n)) return n.slice(0,3); const v=parseFloat(n.replace(/,/g,'')); if(v>=1 && v<=10) return String(v); } return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "review_description",
            "selector": "(() => { const d=ROW.ownerDocument; const el=d.querySelector('.hp_review_score') || d.querySelector('[data-testid=review-score-component]') || d.querySelector('a[href*=blockdisplay4]'); const txt=(el?el.textContent:'').replace(/\\s+/g,' '); const m=txt.match(/\\b(Exceptional|Wonderful|Excellent|Very Good|Good|Pleasant|Fair|Poor)\\b/i); return m?m[1].replace(/\\b\\w/g,c=>c.toUpperCase()):''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "number_of_reviews",
            "selector": "(() => { const d=ROW.ownerDocument; const candidates=[...Array.from(d.querySelectorAll('a[href*=blockdisplay4]')), d.querySelector('.hp_review_score'), d.querySelector('[data-testid=review-score-component]')].filter(Boolean); for(const el of candidates){ const txt=(el.textContent||'').replace(/\\s+/g,' '); const re=/([0-9][0-9,]*)\\s*(?:guest\\s+)?(?:external\\s+)?reviews/i; const m=re.exec(txt); if(m){ let val=m[1]; const idx=m.index; if(idx>0 && txt[idx-1]==='.' && val.length>2) val=val.slice(1); return val; } const p=txt.match(/Guest reviews\\s*\\(([0-9,]+)\\)/i); if(p) return p[1]; } const body=(d.body.innerText||'').replace(/\\s+/g,' '); const b=body.match(/Guest reviews\\s*\\(([0-9,]+)\\)/i); return b?b[1]:''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "details",
            "selector": "(() => { const d=ROW.ownerDocument; const meta=(key,val)=>Array.from(d.getElementsByTagName('meta')).find(m=>m.getAttribute(key)===val)?.content||''; const body=d.body.innerText||''; if(/Sustainability certification/i.test(body)) return 'Sustainability certification'; return (meta('name','description') || meta('property','og:description') || '').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "price",
            "selector": "(() => { const d=ROW.ownerDocument; const priceEl=d.querySelector('[data-testid=price-and-discounted-price]') || d.querySelector('.prco-valign-middle-helper') || d.querySelector('.bui-price-display__value'); if(priceEl) return priceEl.textContent.replace(/\\s+/g,' ').trim(); const txt=(d.querySelector('#availability')?.innerText || d.body.innerText || '').replace(/\\s+/g,' '); const m=txt.match(/(?:US\\$|\\$|€|£)\\s?[0-9][0-9,]*(?:\\.[0-9]{2})?/); return m?m[0]:''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "room_type",
            "selector": "(() => { const d=ROW.ownerDocument; const el=d.querySelector('[data-testid=room-name]') || d.querySelector('.hprt-roomtype-icon-link') || d.querySelector('#hprt-table tbody tr td'); return el ? el.textContent.replace(/\\s+/g,' ').trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "available_dates",
            "selector": "(() => { const u=new URL(ROW.ownerDocument.location.href); const checkin=u.searchParams.get('checkin')||''; const checkout=u.searchParams.get('checkout')||''; return checkin || checkout ? checkin + ' to ' + checkout : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "property_description",
            "selector": "(() => { const d=ROW.ownerDocument; const meta=(key,val)=>Array.from(d.getElementsByTagName('meta')).find(m=>m.getAttribute(key)===val)?.content||''; return (meta('name','description') || meta('property','og:description') || '').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "amenities",
            "selector": "(() => { const d=ROW.ownerDocument; const vals=Array.from(d.querySelectorAll('[data-testid=facility-icon]')).map(el => (el.closest('li') || el.parentElement)?.innerText || '').map(s => s.replace(/\\s+/g,' ').trim()).filter(Boolean); return Array.from(new Set(vals)).slice(0,20).join('; '); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "image_url",
            "selector": "(() => { const d=ROW.ownerDocument; const meta=(key,val)=>Array.from(d.getElementsByTagName('meta')).find(m=>m.getAttribute(key)===val)?.content||''; return meta('property','og:image') || meta('name','twitter:image') || d.querySelector('img[src*=bstatic]')?.src || ''; })()",
            "attribute": "text",
            "isJs": true
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 1920,
      "position_y": 220,
      "config": {}
    }
  ],
  "connections": [
    {
      "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": "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": "loop-continue-1",
      "to_connector_id": "left"
    }
  ],
  "canvas_elements": [
    {
      "id": "group-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 48,
      "position_y": 116,
      "width": 1400,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "wait-for-element-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 1488,
      "position_y": 116,
      "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": 1848,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Booking.com hotel/accommodation detail URLs equivalent to the Octoparse Booking.com Hotel Listing Scraper. Extracts hotel title, location, link, distance, review score, review description, review count, property details, price, room type, availability dates, amenities, property description, and image URL. Navigation strategy: multi-URL loop over Booking.com hotel URLs using navigate.urls with structured-export in append mode and loop-continue so all supplied hotel pages are collected into one CSV. Booking.com may personalize or hide prices/availability by date, region, cookies, bot checks, or CAPTCHA; fields not publicly shown may export blank.",
      "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 8 pages. Pair with loop-continue at the end of each iteration.",
      "color": "#ee5396",
      "position_x": 320,
      "position_y": 200,
      "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 (title, location, link, distance, review_score). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 200,
      "width": 340,
      "height": 129,
      "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": 2120,
      "position_y": 200,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}