{
  "version": "1.0.0",
  "exported_at": "2026-06-02T02:15:00.000Z",
  "project": {
    "name": "Kakao Map Review Scraper",
    "description": "Scrapes Kakao Map/Kakao Place shop review data from multiple normal Kakao Place store URLs. The workflow opens each place page, opens/loads the review area, parses individual leaf review blocks or reviewer text segments into one row per review, exports Octoparse-equivalent fields to kakao-map-review-scraper.csv, and loops through all configured store URLs. Kakao is dynamic; CAPTCHA, endpoint changes, private reviews, or rate limits may require manual intervention.",
    "color": "bg-[#4589ff]",
    "template_id": "ai-generated"
  },
  "blocks": [
    {
      "block_id": "navigate-1",
      "block_type": "process",
      "title": "Navigate",
      "description": "Go to a URL",
      "position_x": 100,
      "position_y": 220,
      "config": {
        "urls": [
          "https://place.map.kakao.com/2036408963",
          "https://place.map.kakao.com/1645149365"
        ],
        "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": 460,
      "position_y": 220,
      "config": {
        "timeout": 40
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 820,
      "position_y": 220,
      "config": {
        "duration": 3
      }
    },
    {
      "block_id": "inject-javascript-1",
      "block_type": "process",
      "title": "Inject JavaScript",
      "description": "Execute custom JavaScript",
      "position_x": 1180,
      "position_y": 220,
      "config": {
        "jsCode": "(async function(){function sleep(ms){return new Promise(function(r){setTimeout(r,ms);});}function norm(s){return String(s==null?'':s).replace(/\\s+/g,' ').trim();}function visible(el){return !!el&&el.offsetParent!==null&&getComputedStyle(el).display!=='none'&&getComputedStyle(el).visibility!=='hidden';}function attrRow(rows){var old=document.getElementById('uscraper-kakao-review-data');if(old&&old.parentNode)old.parentNode.removeChild(old);var box=document.createElement('div');box.id='uscraper-kakao-review-data';box.style.position='absolute';box.style.left='-99999px';box.style.top='0';box.style.width='1px';box.style.height='1px';box.style.height='1px';box.style.overflow='hidden';document.body.appendChild(box);for(var i=0;i<rows.length;i++){var el=document.createElement('div');el.className='uscraper-kakao-review-row';for(var k in rows[i]){if(Object.prototype.hasOwnProperty.call(rows[i],k))el.setAttribute('data-'+k.replace(/_/g,'-'),norm(rows[i][k]));}box.appendChild(el);}window.USCRAPER_KAKAO_REVIEW_ROWS=rows.length;}function textOf(sel){var el=document.querySelector(sel);return norm(el&&el.textContent);}function meta(n){var el=document.querySelector('meta[property=\"'+n+'\"],meta[name=\"'+n+'\"]');return norm(el&&el.getAttribute('content'));}function parseJson(t){t=String(t||'');try{return JSON.parse(t);}catch(e){var a=t.indexOf('{'),b=t.lastIndexOf('}');if(a>=0&&b>a){try{return JSON.parse(t.substring(a,b+1));}catch(e2){}}}return null;}async function fetchJson(url){try{var r=await fetch(url,{credentials:'include',headers:{accept:'application/json,text/plain,*/*'}});if(!r.ok)return null;return parseJson(await r.text());}catch(e){return null;}}function getVal(obj,keys){var out='';function walk(x,d){if(out||x==null||d>12)return;if(Array.isArray(x)){for(var i=0;i<x.length;i++)walk(x[i],d+1);return;}if(typeof x==='object'){for(var k in x){if(Object.prototype.hasOwnProperty.call(x,k)&&keys.indexOf(k)>=0&&x[k]!=null&&typeof x[k]!=='object'){out=norm(x[k]);return;}}for(var k2 in x){if(Object.prototype.hasOwnProperty.call(x,k2))walk(x[k2],d+1);}}}walk(obj,0);return out;}function numVal(obj,keys){var v=getVal(obj,keys),m=String(v).match(/[0-9]+(?:\\.[0-9]+)?/);return m?m[0]:v;}function collectImagesFromNode(node){var imgs=Array.prototype.slice.call(node.querySelectorAll('img')).map(function(img){return img.currentSrc||img.src||img.getAttribute('data-src')||'';}).filter(function(src){return src&&/kakaomapPhoto\\/review|cthumb\\/local|fname=.*review/i.test(src)&&!/profile|icon_review/i.test(src);});var seen={},out=[];for(var i=0;i<imgs.length;i++){if(!seen[imgs[i]]){seen[imgs[i]]=1;out.push(imgs[i]);}}return out.join(' | ');}function findLists(obj){var lists=[];function score(o){if(!o||typeof o!=='object')return 0;var s=0;if(getVal(o,['contents','content','comment','body','text','description','reviewContent','commentContent']))s+=6;if(getVal(o,['username','userName','nickname','writerName','displayName','name','profileNickname']))s+=4;if(getVal(o,['point','score','rating','star','grade']))s+=3;if(getVal(o,['date','regdt','regDate','writeDate','createdDate','createDate','createdAt']))s+=2;return s;}function walk(x,d){if(x==null||d>12)return;if(Array.isArray(x)){var total=0;for(var i=0;i<x.length;i++)total+=score(x[i]);if(x.length&&total>0)lists.push({arr:x,score:total});for(var j=0;j<x.length;j++)walk(x[j],d+1);return;}if(typeof x==='object'){for(var k in x){if(Object.prototype.hasOwnProperty.call(x,k))walk(x[k],d+1);}}}walk(obj,0);lists.sort(function(a,b){return b.score-a.score||b.arr.length-a.arr.length;});return lists.map(function(x){return x.arr;});}function collectImagesObj(obj){var out=[];function walk(x,d){if(x==null||d>10)return;if(typeof x==='string'){var s=x.trim();if(/kakaocdn|kakaomapPhoto|cthumb|fname=|\\.jpg|\\.jpeg|\\.png|\\.webp/i.test(s)&&!/profile|icon_review/i.test(s))out.push(s);return;}if(Array.isArray(x)){for(var i=0;i<x.length;i++)walk(x[i],d+1);return;}if(typeof x==='object'){for(var k in x){if(Object.prototype.hasOwnProperty.call(x,k))walk(x[k],d+1);}}}walk(obj,0);var seen={},res=[];for(var j=0;j<out.length;j++){if(!seen[out[j]]){seen[out[j]]=1;res.push(out[j]);}}return res.join(' | ');}function parseReviewText(txt,img){txt=norm(txt);var reviewer='';var rm=txt.match(/리뷰어 이름,\\s*(.*?)(?:\\s+(?:골드|실버|브론즈|레벨)|\\s+레벨\\s*\\d+|\\s+후기\\s*\\d+|\\s*별점평균|\\s*팔로워|\\s*메뉴 더보기|\\s*별점\\s*[0-9])/);if(rm)reviewer=norm(rm[1]);else{var m0=txt.match(/^([^,]{1,40}?)(?:\\s+후기\\s*\\d+|\\s*별점)/);if(m0)reviewer=norm(m0[1].replace(/^리뷰어 이름,?/,''));}var reviewCount=(txt.match(/후기\\s*([0-9,]+)/)||[])[1]||'';var avg=(txt.match(/별점평균\\s*([0-9]+(?:\\.[0-9]+)?)/)||[])[1]||'';var follower=(txt.match(/팔로워\\s*([0-9,]+)/)||[])[1]||'';var rating=(txt.match(/별점\\s*([0-9]+(?:\\.[0-9]+)?)/)||[])[1]||'';var date=(txt.match(/(20\\d{2}\\.\\d{1,2}\\.\\d{1,2}\\.?)/)||[])[1]||'';var content='';if(date){var after=txt.substring(txt.indexOf(date)+date.length);after=after.replace(/^\\s*[+\\-]?[0-9.]+\\s*/,'');content=norm(after.split(/위치기반|좋아요 개수|근처 사진|사진 신고|신고|메뉴 더보기/)[0]);}if(!content){var cm=txt.match(/별점\\s*[0-9.]+\\s*20\\d{2}\\.\\d{1,2}\\.\\d{1,2}\\.?\\s*(.*?)(?:위치기반|좋아요 개수|근처 사진|$)/);if(cm)content=norm(cm[1]);}return {reviewer:reviewer,reviewer_review_count:reviewCount,reviewer_average_rating:avg,reviewer_follower_count:follower,review_date:date,rating:rating,review_content:content,review_images:img||''};}var placeId=((location.pathname||'').match(/(\\d{5,})/)||[])[1]||'';var reviewTab=Array.prototype.slice.call(document.querySelectorAll('a,button,[role=\"button\"]')).find(function(el){var t=norm(el.textContent);return visible(el)&&/(후기|리뷰|평가)/.test(t)&&!/메뉴 더보기/.test(t);});if(reviewTab){try{reviewTab.click();await sleep(1600);}catch(e){}}for(var c=0;c<25;c++){window.scrollTo(0,document.body.scrollHeight);await sleep(500);var more=Array.prototype.slice.call(document.querySelectorAll('a,button,[role=\"button\"]')).find(function(el){var t=norm(el.textContent);return visible(el)&&/(후기 더보기|리뷰 더보기|평가 더보기|더보기)/.test(t)&&!/메뉴 더보기|더보기 메뉴/.test(t)&&!/이전/.test(t)&&!/(disabled|DISABLED)/.test(el.className||'');});if(!more)break;try{more.click();await sleep(900);}catch(e2){break;}}var main=await fetchJson('https://place.map.kakao.com/main/v/'+placeId)||{};var scoresum=parseFloat(numVal(main,['scoresum','scoreSum']))||0;var scorecnt=parseFloat(numVal(main,['scorecnt','scoreCount','ratingCount','pointCount']))||0;var body=norm(document.body&&document.body.innerText);var storeName=getVal(main,['placenamefull','placename','placeName','name','title'])||meta('og:title')||textOf('h1,h2.tit_location,.tit_location,.tit_subject')||document.title.replace(/\\s*\\|?\\s*카카오맵.*/,'')||placeId;var store={store_name:storeName,category:getVal(main,['catename','cateName','categoryName','category'])||textOf('.txt_cate,[class*=\"cate\"]'),overall_rating:numVal(main,['averageScore','avgScore','scoreAvg','score','rating','point'])||(scorecnt?String(Math.round(scoresum/scorecnt*10)/10):((body.match(/별점\\s*([0-9]+(?:\\.[0-9]+)?)/)||[])[1]||'')),rating_count:numVal(main,['scorecnt','scoreCount','ratingCount','pointCount']),review_count:numVal(main,['commentcnt','commentCount','reviewCount','allComntcnt','reviewcnt'])||((body.match(/후기\\s*([0-9,]+)/)||[])[1]||''),address:getVal(main,['newaddrfull','fullAddress','roadAddress','roadaddr','address','addr'])||((body.match(/([가-힣]+\\s+[가-힣]+[시군구]\\s+[^\\n]+?\\(우\\)\\d+)/)||[])[1]||''),parcel_address:getVal(main,['addrbunho','jibunAddress','bunji','parcelAddress']),phone:getVal(main,['phonenum','phone','tel','telephone'])};var rows=[],seen={};function pushRow(r){if(!r.reviewer&&!r.review_date&&!r.review_content)return;if(r.review_content&&r.review_content.length>900)r.review_content=r.review_content.substring(0,900);var key=[r.reviewer,r.review_date,r.rating,r.review_content].join('|');if(seen[key])return;seen[key]=1;rows.push(Object.assign({},store,r));}for(var page=1;page<=60;page++){var data=await fetchJson('https://place.map.kakao.com/commentlist/v/'+placeId+'/'+page)||await fetchJson('https://place.map.kakao.com/commentlist/v/'+placeId+'/'+page+'?order=LATEST');if(!data)break;var ls=findLists(data);if(!ls.length)break;var before=rows.length;for(var li=0;li<ls[0].length;li++){var it=ls[0][li];pushRow({reviewer:getVal(it,['username','userName','nickname','writerName','displayName','name','profileNickname']),reviewer_link:(getVal(it,['mapuserid','mapUserId','userId','userid','profileId'])?'https://map.kakao.com/?target=other&tab=review&mapuserid='+getVal(it,['mapuserid','mapUserId','userId','userid','profileId']):getVal(it,['profileUrl','profileLink','link','url'])),reviewer_review_count:numVal(it,['userCommentCount','commentCount','reviewCount','userReviewCount','reviewcnt','profileCommentCount']),reviewer_average_rating:numVal(it,['userAverageScore','averageScore','avgScore','profileScore']),review_date:getVal(it,['date','createdAt','regdt','regDate','writeDate','createdDate','createDate']),rating:numVal(it,['point','score','rating','star','grade']),review_content:getVal(it,['contents','content','comment','body','text','description','reviewContent','commentContent']),review_images:collectImagesObj(it)});}if(rows.length===before&&page>1)break;}if(rows.length===0){var all=Array.prototype.slice.call(document.querySelectorAll('li,article,div')).filter(function(el){var t=norm(el.innerText);return /리뷰어 이름,/.test(t)&&/별점\\s*[0-9]/.test(t)&&/20\\d{2}\\.\\d{1,2}\\.\\d{1,2}/.test(t);});var leaf=all.filter(function(el){return !Array.prototype.slice.call(el.children).some(function(ch){var t=norm(ch.innerText);return /리뷰어 이름,/.test(t)&&/별점\\s*[0-9]/.test(t)&&/20\\d{2}\\.\\d{1,2}\\.\\d{1,2}/.test(t);});});leaf.sort(function(a,b){return norm(a.innerText).length-norm(b.innerText).length;});for(var n=0;n<leaf.length;n++){var pt=parseReviewText(leaf[n].innerText,collectImagesFromNode(leaf[n]));pushRow(pt);}}if(rows.length===0){var parts=body.split(/리뷰어 이름,\\s*/);for(var p=1;p<parts.length;p++){var seg='리뷰어 이름, '+parts[p].split(/리뷰어 이름,\\s*/)[0];var pr=parseReviewText(seg,'');pushRow(pr);}}if(rows.length===0&&(store.store_name||placeId)){pushRow({reviewer:'',reviewer_link:'',reviewer_review_count:'',reviewer_average_rating:'',reviewer_follower_count:'',review_date:'',rating:'',review_content:'NO_PUBLIC_REVIEWS_FOUND_OR_KAKAO_BLOCKED_REVIEW_API',review_images:''});}attrRow(rows);})();",
        "waitForCompletion": true,
        "timeout": 120
      }
    },
    {
      "block_id": "sleep-2",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1540,
      "position_y": 220,
      "config": {
        "duration": 1
      }
    },
    {
      "block_id": "element-exists-1",
      "block_type": "process",
      "title": "Element Exists",
      "description": "Check if element exists",
      "position_x": 1900,
      "position_y": 220,
      "config": {
        "selector": ".uscraper-kakao-review-row"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 2260,
      "position_y": 60,
      "config": {
        "rowSelector": ".uscraper-kakao-review-row",
        "fileName": "kakao-map-review-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "columns": [
          {
            "name": "store_name",
            "selector": "",
            "attribute": "data-store-name"
          },
          {
            "name": "category",
            "selector": "",
            "attribute": "data-category"
          },
          {
            "name": "overall_rating",
            "selector": "",
            "attribute": "data-overall-rating"
          },
          {
            "name": "rating_count",
            "selector": "",
            "attribute": "data-rating-count"
          },
          {
            "name": "review_count",
            "selector": "",
            "attribute": "data-review-count"
          },
          {
            "name": "address",
            "selector": "",
            "attribute": "data-address"
          },
          {
            "name": "parcel_address",
            "selector": "",
            "attribute": "data-parcel-address"
          },
          {
            "name": "phone",
            "selector": "",
            "attribute": "data-phone"
          },
          {
            "name": "reviewer",
            "selector": "",
            "attribute": "data-reviewer"
          },
          {
            "name": "reviewer_link",
            "selector": "",
            "attribute": "data-reviewer-link"
          },
          {
            "name": "reviewer_review_count",
            "selector": "",
            "attribute": "data-reviewer-review-count"
          },
          {
            "name": "reviewer_average_rating",
            "selector": "",
            "attribute": "data-reviewer-average-rating"
          },
          {
            "name": "reviewer_follower_count",
            "selector": "",
            "attribute": "data-reviewer-follower-count"
          },
          {
            "name": "review_date",
            "selector": "",
            "attribute": "data-review-date"
          },
          {
            "name": "rating",
            "selector": "",
            "attribute": "data-rating"
          },
          {
            "name": "review_content",
            "selector": "",
            "attribute": "data-review-content"
          },
          {
            "name": "review_images",
            "selector": "",
            "attribute": "data-review-images"
          }
        ]
      }
    },
    {
      "block_id": "loop-continue-1",
      "block_type": "process",
      "title": "Loop Continue",
      "description": "Continue multi-input loop",
      "position_x": 2620,
      "position_y": 560,
      "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": "inject-javascript-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "inject-javascript-1",
      "from_connector_id": "right",
      "to_block_id": "sleep-2",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "sleep-2",
      "from_connector_id": "right",
      "to_block_id": "element-exists-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "true",
      "to_block_id": "structured-export-1",
      "to_connector_id": "left"
    },
    {
      "from_block_id": "element-exists-1",
      "from_connector_id": "false",
      "to_block_id": "loop-continue-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": 28,
      "position_y": 116,
      "width": 1760,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "navigate-1",
          "wait-for-page-load-1",
          "sleep-1",
          "sleep-2"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1108,
      "position_y": 116,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "inject-javascript-1"
        ]
      }
    },
    {
      "id": "group-pagination",
      "element_type": "group",
      "title": "Pagination Loop",
      "color": "#ff832b",
      "position_x": 1828,
      "position_y": 116,
      "width": 1040,
      "height": 636,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "element-exists-1",
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "group-extract",
      "element_type": "group",
      "title": "Data Extraction",
      "color": "#42be65",
      "position_x": 2188,
      "position_y": -44,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "structured-export-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Scrapes Kakao Map/Kakao Place shop review data from multiple normal Kakao Place store URLs. The workflow opens each place page, opens/loads the review area, parses individual leaf review blocks or reviewer text segments into one row per review, exports Octoparse-equivalent fields to kakao-map-review-scraper.csv, and loops through all configured store URLs. Kakao is dynamic; CAPTCHA, endpoint changes, private reviews, or rate limits may require manual intervention.",
      "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 2 pages. Pair with loop-continue at the end of each iteration.",
      "color": "#ee5396",
      "position_x": 300,
      "position_y": 200,
      "width": 328,
      "height": 107,
      "z_index": 22,
      "data": {
        "block_id": "navigate-1"
      }
    },
    {
      "id": "note-block-inject-javascript-1",
      "element_type": "note",
      "title": "Note: Inject JavaScript",
      "content": "Runs custom JavaScript in the page: `(async function(){function sleep(ms){return new Promise(function(r){setTimeout(r,ms);});}function no...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1380,
      "position_y": 200,
      "width": 340,
      "height": 140,
      "z_index": 22,
      "data": {
        "block_id": "inject-javascript-1"
      }
    },
    {
      "id": "note-block-element-exists-1",
      "element_type": "note",
      "title": "Note: Element Exists",
      "content": "Condition block: checks `.uscraper-kakao-review-row`. True / False branches control which path runs next. Keep enough space between branches so both connector lines are visible.",
      "color": "#ee5396",
      "position_x": 2100,
      "position_y": 200,
      "width": 340,
      "height": 139,
      "z_index": 22,
      "data": {
        "block_id": "element-exists-1"
      }
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Extracts rows matching `.uscraper-kakao-review-row`. Confirm row count > 0 before running at scale.",
      "color": "#ee5396",
      "position_x": 2460,
      "position_y": 40,
      "width": 340,
      "height": 113,
      "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": 2820,
      "position_y": 540,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}