{
  "version": "1.0.0",
  "exported_at": "2026-06-02T22:15:00.000Z",
  "project": {
    "name": "Musinsa Review Scraper",
    "description": "Extracts Musinsa product general reviews from one or more Musinsa product URLs, including product link, product name, product image, overall rating, review writer, review rating, basic evaluation tags, detailed review text, helpful count, and review date. Navigation strategy: uses navigate.urls[] for multiple product URLs, and an injected browser script performs review-page/API pagination for each product, normalizing results into exportable rows. Replace the sample URLs in the Navigate block with up to 20 Musinsa product URLs. Best-effort: Musinsa may change APIs, require region access, or show CAPTCHA/anti-bot checks.",
    "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": 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.musinsa.com/app/goods/3062046",
          "https://www.musinsa.com/app/goods/1884626"
        ],
        "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": 240,
      "config": {
        "timeout": 45,
        "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": 240,
      "config": {
        "jsCode": "(async()=>{const clean=v=>String(v==null?'':v).replace(/\\s+/g,' ').trim();const abs=u=>{try{return new URL(u,location.href).href}catch(e){return clean(u)}};document.querySelector('#uscraper-review-container')?.remove();const box=document.createElement('div');box.id='uscraper-review-container';box.setAttribute('data-uscraper','musinsa-reviews');box.style.cssText='display:block;position:relative;z-index:2147483647;background:#fff;color:#000;padding:8px;border:2px solid #0f62fe;';document.body.prepend(box);const goodsNo=(location.href.match(/(?:goods|products)\\/(\\d+)/)||location.href.match(/[?&](?:goodsNo|goods_no)=(\\d+)/)||document.body.innerHTML.match(/(?:goodsNo|goods_no|goodsNumber)[\"']?\\s*[:=]\\s*[\"']?(\\d{5,})/i)||[])[1]||'';const productLink=(document.querySelector('link[rel=canonical]')?.href||location.href).split('?')[0];const product=clean((document.querySelector('meta[property=\"og:title\"]')?.content||document.querySelector('h1,[class*=product][class*=title],.product_title')?.textContent||'').replace(/\\s*[|｜-]\\s*MUSINSA.*$/i,''));const productImage=abs(document.querySelector('meta[property=\"og:image\"]')?.content||document.querySelector('img[src*=goods_img],img[src*=image\\.msscdn]')?.src||'');const bodyText=document.body.innerText||'';let overallRating='';let om=bodyText.match(/(?:전체평점|평점|rating|score)\\s*([0-5](?:[.]\\d)?)/i);if(om)overallRating=om[1];function walk(o,fn,path=[]){if(!o||typeof o!=='object')return;if(Array.isArray(o)){o.forEach((v,i)=>walk(v,fn,path.concat(i)));return}for(const k of Object.keys(o)){const v=o[k];fn(k,v,o,path);if(v&&typeof v==='object')walk(v,fn,path.concat(k))}}function firstVal(o,regs){let found='';walk(o,(k,v)=>{if(found)return;if(regs.some(r=>r.test(k))&&(typeof v==='string'||typeof v==='number'))found=clean(v)});return found}function allVals(o,regs){const out=[];walk(o,(k,v)=>{if(regs.some(r=>r.test(k))&&(typeof v==='string'||typeof v==='number')){const s=clean(v);if(s)out.push(s)}});return out}function arrays(o){const out=[];walk(o,(k,v)=>{if(Array.isArray(v)&&v.length&&v.some(x=>x&&typeof x==='object'))out.push(v)});return out}function normalize(o){if(!o||typeof o!=='object')return null;let detail=firstVal(o,[/review.*content/i,/content/i,/comment/i,/contents/i,/text/i,/message/i]);const strings=allVals(o,[/.*/]).filter(s=>s.length>12&&!/^https?:/i.test(s));if((!detail||detail.length<8)&&strings.length){strings.sort((a,b)=>b.length-a.length);detail=strings[0]}detail=clean(detail);if(!detail||detail.length<5)return null;let writer=firstVal(o,[/nick/i,/writer/i,/user.*name/i,/member.*name/i,/login/i,/profile.*name/i]);let rating=firstVal(o,[/grade/i,/rating/i,/score/i,/star/i]);let date=firstVal(o,[/date/i,/created/i,/create/i,/reg/i,/write/i]);let helpful=firstVal(o,[/help/i,/like/i,/up.*cnt/i,/recommend/i,/good.*cnt/i]);let basic=allVals(o,[/option/i,/evaluation/i,/satisfaction/i,/answer/i,/selected/i]).filter(s=>/이에요|해요|보통|커요|작아요|빨라요|꼼꼼|편안|적당|선명|밝기|색감|사이즈|발볼|착화감|무게감|배송|포장/.test(s)).join(', ');const dm=detail.match(/(20\\d{2}[.\\-/]\\d{1,2}[.\\-/]\\d{1,2})/);if(!date&&dm)date=dm[1];const rm=String(rating).match(/[0-5](?:[.]\\d)?/);rating=rm?rm[0]:'';const hm=String(helpful).match(/[0-9,]+/);helpful=hm?hm[0].replace(/,/g,''):'';return {writer:clean(writer),rating:clean(rating),basic:clean(basic),detail:detail,helpful:clean(helpful),date:clean(date)}}async function getText(url){try{const r=await fetch(url,{credentials:'include',headers:{'accept':'application/json,text/html,*/*'}});if(!r.ok)return null;return await r.text()}catch(e){return null}}function rowsFromHtml(html){const d=new DOMParser().parseFromString(html,'text/html');const candidates=Array.from(d.querySelectorAll('li,div,article')).filter(el=>{const t=el.innerText||el.textContent||'';return t.length>20&&/(20\\d{2}[.\\-/]\\d{1,2}[.\\-/]\\d{1,2}|LV\\.?\\s*\\d+|도움돼요|평점)/.test(t)});return candidates.map(el=>{const t=clean(el.innerText||el.textContent||'');const date=(t.match(/20\\d{2}[.\\-/]\\d{1,2}[.\\-/]\\d{1,2}/)||[''])[0];const writer=(t.match(/LV\\.?\\s*\\d+\\s*[^\\n\\r]{1,40}/i)||[''])[0];const rating=(t.match(/(?:평점|별점)\\s*([0-5](?:[.]\\d)?)/)||[])[1]||'';const helpful=(t.match(/(?:도움돼요|helpful|추천)\\s*([0-9,]+)/i)||[])[1]||'';return {writer:clean(writer),rating:clean(rating),basic:'',detail:t,helpful:clean(helpful).replace(/,/g,''),date:clean(date)}}).filter(r=>r.detail)}const endpoints=p=>{const base='goodsNo='+goodsNo+'&page='+p+'&size=20&sort=up_cnt_desc&selectedSimilarNo=0';return ['/api2/review/v1/view/list?'+base,'https://www.musinsa.com/api2/review/v1/view/list?'+base,'https://goods-detail.musinsa.com/api2/review/v1/view/list?'+base,'https://goods.musinsa.com/api2/review/v1/view/list?'+base,'/api/goods/v2/review/goods/'+goodsNo+'?page='+p+'&size=20','/app/reviews/lists?type=goods&goods_no='+goodsNo+'&page='+p]};const seen=new Set();const reviews=[];if(goodsNo){for(let p=1;p<=50;p++){let pageRows=[];for(const url of endpoints(p)){const txt=await getText(url);if(!txt)continue;let rows=[];const s=txt.trim();if(s.startsWith('{')||s.startsWith('[')){try{const json=JSON.parse(s);const arrs=arrays(json);for(const a of arrs){for(const item of a){const r=normalize(item);if(r)rows.push(r)}}}catch(e){}}else{rows=rowsFromHtml(txt)}rows=rows.filter(r=>{const key=[r.writer,r.date,r.detail.slice(0,80)].join('|');if(seen.has(key))return false;seen.add(key);return true});if(rows.length){pageRows=rows;break}}if(!pageRows.length)break;reviews.push(...pageRows);if(pageRows.length<2&&p>3)break}}if(!reviews.length){for(const sc of Array.from(document.scripts)){const txt=sc.textContent||'';if(!/(review|goodsNo|reviewContent|후기)/i.test(txt))continue;const jsons=[];if(sc.type==='application/json'||sc.id==='__NEXT_DATA__'){jsons.push(txt)}else{const m=txt.match(/\\{[\\s\\S]{100,}\\}/);if(m)jsons.push(m[0])}for(const j of jsons){try{const data=JSON.parse(j);for(const a of arrays(data)){for(const item of a){const r=normalize(item);if(r){const key=[r.writer,r.date,r.detail.slice(0,80)].join('|');if(!seen.has(key)){seen.add(key);reviews.push(r)}}}}}catch(e){}}}}if(!reviews.length){const domRows=Array.from(document.querySelectorAll('li,div,article')).filter(el=>{const t=el.innerText||'';return t.length>30&&/(20\\d{2}[.\\-/]\\d{1,2}[.\\-/]\\d{1,2}|LV\\.?\\s*\\d+|도움돼요)/.test(t)&&/(후기|평점|사이즈|색감|배송|포장|착화감)/.test(t)}).slice(0,200);for(const el of domRows){const t=clean(el.innerText);const r={writer:clean((t.match(/LV\\.?\\s*\\d+\\s*[^\\n\\r]{1,40}/i)||[''])[0]),rating:clean((t.match(/(?:평점|별점)\\s*([0-5](?:[.]\\d)?)/)||[])[1]||''),basic:clean((t.match(/(사이즈[^\\n]*|밝기[^\\n]*|색감[^\\n]*|발볼[^\\n]*|착화감[^\\n]*|무게감[^\\n]*|배송[^\\n]*|포장[^\\n]*)/)||[''])[0]),detail:t,helpful:clean((t.match(/(?:도움돼요|helpful|추천)\\s*([0-9,]+)/i)||[])[1]||'').replace(/,/g,''),date:clean((t.match(/20\\d{2}[.\\-/]\\d{1,2}[.\\-/]\\d{1,2}/)||[''])[0])};const key=[r.writer,r.date,r.detail.slice(0,80)].join('|');if(!seen.has(key)){seen.add(key);reviews.push(r)}}}if(!overallRating){const ratings=reviews.map(r=>parseFloat(r.rating)).filter(n=>!isNaN(n));if(ratings.length)overallRating=(ratings.reduce((a,b)=>a+b,0)/ratings.length).toFixed(1)}reviews.forEach((r,i)=>{const row=document.createElement('div');row.className='uscraper-review-row';row.style.cssText='padding:4px;border-bottom:1px solid #ddd;';row.setAttribute('data-product-link',productLink);row.setAttribute('data-product',product);row.setAttribute('data-product-image',productImage);row.setAttribute('data-overall-rating',overallRating);row.setAttribute('data-review-writer',r.writer||'');row.setAttribute('data-review-rating',r.rating||'');row.setAttribute('data-basic-review',r.basic||'');row.setAttribute('data-detailed-review',r.detail||'');row.setAttribute('data-helpful-count',r.helpful||'');row.setAttribute('data-review-date',r.date||'');row.textContent=(i+1)+'. '+(r.writer||'')+' '+(r.rating||'')+' '+(r.date||'')+' '+(r.detail||'');box.appendChild(row)});box.setAttribute('data-review-count',String(reviews.length));if(!reviews.length){box.textContent='UScraper could not find public Musinsa review rows for goodsNo '+goodsNo+'. The page may be blocked, changed, or reviews may require an unavailable API.'}return reviews.length;})()",
        "waitForCompletion": true,
        "timeout": 120,
        "color": "bg-[#a56eff]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 1560,
      "position_y": 240,
      "config": {
        "selector": ".uscraper-review-row",
        "timeout": 60,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "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": ".uscraper-review-row",
        "fileName": "musinsa-product-review-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "product_link",
            "selector": "",
            "attribute": "data-product-link"
          },
          {
            "name": "product",
            "selector": "",
            "attribute": "data-product"
          },
          {
            "name": "product_image",
            "selector": "",
            "attribute": "data-product-image"
          },
          {
            "name": "overall_rating",
            "selector": "",
            "attribute": "data-overall-rating"
          },
          {
            "name": "review_writer",
            "selector": "",
            "attribute": "data-review-writer"
          },
          {
            "name": "review_rating",
            "selector": "",
            "attribute": "data-review-rating"
          },
          {
            "name": "basic_review",
            "selector": "",
            "attribute": "data-basic-review"
          },
          {
            "name": "detailed_review",
            "selector": "",
            "attribute": "data-detailed-review"
          },
          {
            "name": "helpful_count",
            "selector": "",
            "attribute": "data-helpful-count"
          },
          {
            "name": "review_date",
            "selector": "",
            "attribute": "data-review-date"
          }
        ]
      }
    },
    {
      "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-[#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": "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": 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"
        ]
      }
    },
    {
      "id": "group-interaction",
      "element_type": "group",
      "title": "Interaction",
      "color": "#a56eff",
      "position_x": 1128,
      "position_y": 136,
      "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": 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": "Extracts Musinsa product general reviews from one or more Musinsa product URLs, including product link, product name, product image, overall rating, review writer, review rating, basic evaluation tags, detailed review text, helpful count, and review date. Navigation strategy: uses navigate.urls[] for multiple product URLs, and an injected browser script performs review-page/API pagination for each product, normalizing results into exportable rows. Replace the sample URLs in the Navigate block with up to 20 Musinsa product URLs. Best-effort: Musinsa may change APIs, require region access, or show CAPTCHA/anti-bot checks.",
      "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==null?'':v).replace(/\\s+/g,' ').trim();const abs=u=>{try{return n...` Verify in browser if results are empty.",
      "color": "#ee5396",
      "position_x": 1400,
      "position_y": 220,
      "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-review-row`. Confirm row count > 0 before running at scale.",
      "color": "#ee5396",
      "position_x": 2120,
      "position_y": 220,
      "width": 340,
      "height": 111,
      "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"
      }
    }
  ]
}