{
  "version": "1.0.0",
  "exported_at": "2026-05-31T18:20:00.000Z",
  "project": {
    "name": "Bing Maps Store Scraper",
    "description": "Best-effort Bing Maps business scraper equivalent to the Octoparse template. Default query is cafes London; edit the navigate.urls list to add more Bing Maps keyword/location URLs. The workflow handles Bing Maps as an infinite-scroll listing by auto-scrolling result panels, then exports business fields such as keyword, category, title, address, phone, rating, reviews, opening/status text, delivery options, website, and social links when present in loaded Bing Maps result markup. Facebook and Instagram sample social URLs from the Octoparse preview may require login and are not scraped directly.",
    "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": {
        "urls": [
          "https://www.bing.com/maps?q=cafes%20London"
        ],
        "color": "bg-[#08bdba]"
      }
    },
    {
      "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": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Run custom JavaScript on the page",
      "position_x": 1200,
      "position_y": 220,
      "config": {
        "jsCode": "(()=>{const labels=['accept','agree','i agree','accept all','got it','allow all'];for(const el of document.querySelectorAll('button,input[type=button],input[type=submit],a[role=button]')){const t=(el.innerText||el.value||el.getAttribute('aria-label')||'').trim().toLowerCase();if(labels.some(l=>t===l||t.includes(l))){try{el.click();return 'Clicked possible consent button: '+t;}catch(e){}}}return 'No consent button clicked';})()",
        "waitForCompletion": true,
        "timeout": 10,
        "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": 3,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "inject-javascript-2",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Run custom JavaScript on the page",
      "position_x": 1920,
      "position_y": 220,
      "config": {
        "jsCode": "(async()=>{const wait=ms=>new Promise(r=>setTimeout(r,ms));const clean=s=>(s||'').replace(/\\s+/g,' ').trim();const abs=u=>{try{return new URL(u,location.href).href}catch(e){return u||''}};const parseCount=v=>{v=clean(v);const m=v.match(/^([\\d.]+)\\s*k$/i);if(m)return String(Math.round(parseFloat(m[1])*1000));return v.replace(/,/g,'')};const keyword=clean(new URL(location.href).searchParams.get('q')||'');function scrollables(){return Array.from(document.querySelectorAll('div,main,section,aside')).filter(e=>e.scrollHeight>e.clientHeight+220).sort((a,b)=>b.scrollHeight-a.scrollHeight).slice(0,6)}let last=-1,stable=0;for(let i=0;i<28;i++){for(const s of scrollables()){try{s.scrollTop=s.scrollHeight}catch(e){}}window.scrollTo(0,document.body.scrollHeight);await wait(850);const c=document.querySelectorAll('[data-entityid],.entity-list-item,[role=article],[role=listitem]').length;if(c===last)stable++;else stable=0;last=c;if(stable>=4&&c>0)break}let candidates=[];for(const sel of ['[data-entityid]','.entity-list-item','[role=article]','[role=listitem]'])candidates=candidates.concat(Array.from(document.querySelectorAll(sel)));if(candidates.length===0)candidates=Array.from(document.querySelectorAll('a')).map(a=>a.closest('[data-entityid],li,[role=article],[role=listitem],div')).filter(Boolean);const seenEls=new Set(),rows=[];const socialRe=/facebook\\.com|twitter\\.com|x\\.com|youtube\\.com|youtu\\.be|instagram\\.com|pinterest\\.|linkedin\\.com/i;const isNoiseLine=(l,title,address,phone)=>!l||l===title||l===address||l===phone||/reviews?|\\/5|out of\\s*5|stars?|open\\b|closed\\b|directions|website|save|share|nearby|\\+?\\d[\\d\\s().-]{7,}\\d/i.test(l);for(const el of candidates){if(!el||seenEls.has(el))continue;seenEls.add(el);const txt=(el.innerText||'').trim();if(txt.length<25)continue;if(/sign in|log in|privacy|terms|copyright/i.test(txt)&&!/open|closed|review|phone|address|stars|\\/5|out of 5/i.test(txt))continue;const lines=txt.split(/\\n+/).map(clean).filter(Boolean);const links=Array.from(el.querySelectorAll('a[href]')).map(a=>abs(a.getAttribute('href'))).filter(Boolean);const h=el.querySelector('[role=heading],h1,h2,h3,.title,.name,[aria-label]');let title=clean(h&&((h.innerText||h.getAttribute('aria-label'))));if(!title)title=lines.find(l=>!/(open|closed|directions|website|reviews?|stars?|\\/5|out of 5|km|mi)$/i.test(l))||lines[0]||'';let address=lines.find(l=>l!==title&&/\\bLondon\\b/i.test(l)&&!/reviews?|\\/5|out of\\s*5|open\\b|closed\\b|\\+?\\d[\\d\\s().-]{7,}\\d/i.test(l))||'';if(!address){const am=txt.match(/(?:[A-Z][A-Za-z'.& -]+,\\s*)?\\d+(?:-\\d+)?\\s+[A-Za-z0-9'.& -]+,\\s*London(?:\\s+[A-Z0-9 ]+)?/i);address=am?clean(am[0]):''}const phone=(txt.match(/(?:\\+?\\d[\\d\\s().-]{7,}\\d)/)||[''])[0];const ratingMatch=txt.match(/\\b\\d(?:\\.\\d)?\\/5\\b|\\b\\d(?:\\.\\d)?\\s*out of\\s*5\\.?/i);const rating=ratingMatch?clean(ratingMatch[0]):'';const reviewMatch=txt.match(/\\(([\\d.,]+K?)\\s+reviews?\\)|([\\d.,]+K?)\\s+reviews?/i);const review_number=reviewMatch?parseCount(reviewMatch[1]||reviewMatch[2]||''):'';const category=lines.find((l,i)=>i>0&&l.length<60&&!isNoiseLine(l,title,address,phone)&&!/^\\d+(?:\\.\\d+)?$/.test(l)&&!/^[£$€]{1,4}$/.test(l))||'';const price_range=lines.find(l=>/^[£$€]{1,4}$/.test(l))||'';let status=lines.find(l=>/^(open|closed)\\b/i.test(l))||'';status=clean(status.replace(/\\s*·\\s*\\+?\\d[\\d\\s().-]{7,}\\d.*/,'').replace(/\\s+\\+?\\d[\\d\\s().-]{7,}\\d.*/,''));const opening_hours=lines.filter(l=>/^(monday|tuesday|wednesday|thursday|friday|saturday|sunday|mon|tue|wed|thu|fri|sat|sun)\\b/i.test(l)||/\\d{1,2}:\\d{2}\\s*[-–]\\s*\\d{1,2}:\\d{2}/.test(l)).join(' ');const delivery=lines.filter(l=>/(dine-in|takeout|take-out|delivery|pickup|pick-up)/i.test(l)).join(' · ');const longLines=lines.filter(l=>l.length>60&&!/privacy|terms|copyright/i.test(l));const short_description=longLines[0]||'';const findLink=re=>links.find(u=>re.test(u))||'';const facebook=findLink(/facebook\\.com/i);const x_twitter=findLink(/(?:twitter\\.com|x\\.com)/i);const youtube=findLink(/youtube\\.com|youtu\\.be/i);const instagram=findLink(/instagram\\.com/i);const pinterest=findLink(/pinterest\\./i);const linked_in=findLink(/linkedin\\.com/i);const website=links.find(u=>!/bing\\.com|microsoft\\.com|mailto:|tel:/i.test(u)&&!socialRe.test(u))||'';const bing_maps_url=links.find(u=>/bing\\.com\\/maps/i.test(u))||location.href;const key=[title,address,phone].join('|').toLowerCase();if(!title||rows.some(r=>r.key===key))continue;rows.push({key,keyword,category,title,address,phone_number:phone,rating,review_number,price_range,details:short_description,status,opening_hours,short_description,delivery,facebook,x_twitter,youtube,instagram,pinterest,linked_in,website,bing_maps_url,raw_text:clean(txt).slice(0,1200)})}let root=document.getElementById('uscraper-bing-maps-results');if(root)root.remove();root=document.createElement('div');root.id='uscraper-bing-maps-results';root.style.cssText='display:none';document.body.appendChild(root);for(const r of rows){const d=document.createElement('div');d.className='uscraper-business-row';for(const [k,v] of Object.entries(r)){if(k!=='key')d.setAttribute('data-'+k.replace(/_/g,'-'),v||'')}root.appendChild(d)}return 'Materialized '+rows.length+' Bing Maps business rows with improved rating/review/category parsing';})()",
        "waitForCompletion": true,
        "timeout": 90,
        "color": "bg-[#ff832b]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 2280,
      "position_y": 220,
      "config": {
        "selector": "#uscraper-bing-maps-results .uscraper-business-row",
        "timeout": 30,
        "visible": false,
        "color": "bg-[#42be65]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2640,
      "position_y": 220,
      "config": {
        "rowSelector": "#uscraper-bing-maps-results .uscraper-business-row",
        "fileName": "bing-maps-store-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "keyword",
            "selector": "",
            "attribute": "data-keyword"
          },
          {
            "name": "category",
            "selector": "",
            "attribute": "data-category"
          },
          {
            "name": "title",
            "selector": "",
            "attribute": "data-title"
          },
          {
            "name": "address",
            "selector": "",
            "attribute": "data-address"
          },
          {
            "name": "phone_number",
            "selector": "",
            "attribute": "data-phone-number"
          },
          {
            "name": "rating",
            "selector": "",
            "attribute": "data-rating"
          },
          {
            "name": "review_number",
            "selector": "",
            "attribute": "data-review-number"
          },
          {
            "name": "price_range",
            "selector": "",
            "attribute": "data-price-range"
          },
          {
            "name": "details",
            "selector": "",
            "attribute": "data-details"
          },
          {
            "name": "status",
            "selector": "",
            "attribute": "data-status"
          },
          {
            "name": "opening_hours",
            "selector": "",
            "attribute": "data-opening-hours"
          },
          {
            "name": "short_description",
            "selector": "",
            "attribute": "data-short-description"
          },
          {
            "name": "delivery",
            "selector": "",
            "attribute": "data-delivery"
          },
          {
            "name": "facebook",
            "selector": "",
            "attribute": "data-facebook"
          },
          {
            "name": "x_twitter",
            "selector": "",
            "attribute": "data-x-twitter"
          },
          {
            "name": "youtube",
            "selector": "",
            "attribute": "data-youtube"
          },
          {
            "name": "instagram",
            "selector": "",
            "attribute": "data-instagram"
          },
          {
            "name": "pinterest",
            "selector": "",
            "attribute": "data-pinterest"
          },
          {
            "name": "linked_in",
            "selector": "",
            "attribute": "data-linked-in"
          },
          {
            "name": "website",
            "selector": "",
            "attribute": "data-website"
          },
          {
            "name": "bing_maps_url",
            "selector": "",
            "attribute": "data-bing-maps-url"
          },
          {
            "name": "raw_text",
            "selector": "",
            "attribute": "data-raw-text"
          }
        ],
        "color": "bg-[#42be65]"
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 3000,
      "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": "inject-javascript-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-2",
      "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-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": 2120,
      "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": 1040,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1",
          "inject-javascript-2"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2568,
      "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": 2928,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Best-effort Bing Maps business scraper equivalent to the Octoparse template. Default query is cafes London; edit the navigate.urls list to add more Bing Maps keyword/location URLs. The workflow handles Bing Maps as an infinite-scroll listing by auto-scrolling result panels, then exports business fields such as keyword, category, title, address, phone, rating, reviews, opening/status text, delivery options, website, and social links when present in loaded Bing Maps result markup. Facebook and Instagram sample social URLs from the Octoparse preview may require login and are not scraped directly.",
      "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: `(()=>{const labels=['accept','agree','i agree','accept all','got it','allow all'];for(const el of do...` 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-inject-javascript-2",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(async()=>{const wait=ms=>new Promise(r=>setTimeout(r,ms));const clean=s=>(s||'').replace(/\\s+/g,' '...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 200,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-2"
      }
    },
    {
      "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": 3200,
      "position_y": 200,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}