{
  "version": "1.0.0",
  "exported_at": "2026-05-31T09:00:00.000Z",
  "project": {
    "name": "Tabelog Details Scraper",
    "description": "Best-effort UScraper equivalent of the Octoparse Tabelog Details Scraper. Scrapes restaurant detail-style fields such as store name, address, transportation/access, operating hours, holidays, budget, payment, seats, smoking, parking, homepage, telephone, remarks, courses and dishes from a multi-URL input list. Navigation strategy: known URL list using navigate.urls[] with structured-export fileMode=append and loop-continue so each supplied restaurant URL is processed. Note: attached analysis shows these URLs are official/third-party restaurant homepages rather than actual Tabelog detail pages; Tabelog-only fields such as rating, opening day, and first reviewers may be blank. One supplied URL redirects to an unrelated website in analysis, so extraction there will be limited.",
    "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": 200,
      "config": {
        "urls": [
          "https://ton-worry.owst.jp/",
          "http://www.naka-sei.com/uchi/",
          "https://tonkan.jp"
        ],
        "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": 200,
      "config": {
        "timeout": 30,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "wait-for-element-1",
      "block_type": "process",
      "title": "Wait for Element",
      "description": "Wait until element appears",
      "position_x": 840,
      "position_y": 200,
      "config": {
        "selector": "body",
        "timeout": 30,
        "visible": true,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "sleep-1",
      "block_type": "process",
      "title": "Sleep",
      "description": "Wait for specified time",
      "position_x": 1200,
      "position_y": 200,
      "config": {
        "duration": 2,
        "color": "bg-[#08bdba]"
      }
    },
    {
      "block_id": "structured-export-1",
      "block_type": "process",
      "title": "Structured Export",
      "description": "Export data with custom columns",
      "position_x": 1560,
      "position_y": 200,
      "config": {
        "rowSelector": "body",
        "fileName": "tabelog-details-scraper.csv",
        "saveLocation": "C:\\Users\\theskd\\Documents\\UScraper\\templates",
        "includeHeaders": true,
        "fileMode": "append",
        "color": "bg-[#42be65]",
        "columns": [
          {
            "name": "source_url",
            "selector": "(() => ROW.ownerDocument.location.href)()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "store_name",
            "selector": "(() => { const d=ROW.ownerDocument; return (d.querySelector('h1.headerShopName span:not(.shopStatus)')?.textContent || d.querySelector('.l-header__logo img')?.alt || d.querySelector('meta[property=\"og:site_name\"]')?.content || d.querySelector('meta[property=\"og:title\"]')?.content || d.title || '').replace(/\\s+/g,' ').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "rating",
            "selector": "(() => '')()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "address",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); const cut=(a,b,last=false)=>{const i=last?one.lastIndexOf(a):one.indexOf(a); if(i<0)return ''; const j=b?one.indexOf(b,i+a.length):-1; return one.slice(i+a.length,j>=0?j:undefined).replace(/\\s+/g,' ').trim();}; if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('店舗詳細情報'))); const i=s.indexOf('住所'), j=s.indexOf('アクセス',i); return i>=0?s.slice(i+2,j>=0?j:undefined).trim():'';} if(host.includes('tonkan')) return cut('【住所】','【営業時間】',true); return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "transportation",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('店舗詳細情報'))); const i=s.indexOf('アクセス'), j=s.indexOf('電話番号',i); return i>=0?s.slice(i+4,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "operating_hours",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); const between=(s,a,b)=>{const i=s.indexOf(a); if(i<0)return ''; const j=b?s.indexOf(b,i+a.length):-1; return s.slice(i+a.length,j>=0?j:undefined).replace(/\\s+/g,' ').trim();}; if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('店舗詳細情報'))); return between(s,'営業時間','お問い合わせ時間');} if(host.includes('tonkan')){const i=one.lastIndexOf('【営業時間】'); if(i<0)return ''; const j=one.indexOf('【連絡先】',i); return one.slice(i+6,j>=0?j:undefined).replace(/\\s+/g,' ').trim();} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "shop_holidays",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('店舗詳細情報'))); const i=s.indexOf('定休日'), j=s.indexOf('関連ページ',i); return i>=0?s.slice(i+3,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "budget",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('詳細情報'))); const i=s.indexOf('平均予算'), j=s.indexOf('クレジットカード',i); return i>=0?s.slice(i+4,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "method_of_payment",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('詳細情報'))); const i=s.indexOf('クレジットカード'), j=s.indexOf('感染症対策',i); return i>=0?s.slice(i,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "table_money",
            "selector": "(() => '')()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "number_of_seats",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('お席情報'))); const i=s.indexOf('総席数'), j=s.indexOf('最大宴会収容人数',i); return i>=0?s.slice(i+3,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "private_dining_room",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('お席情報'))); const i=s.indexOf('個室'), j=s.indexOf('座敷',i); return i>=0?s.slice(i+2,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "private_use",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('お席情報'))); const i=s.indexOf('貸切'), j=s.indexOf('夜景がきれいなお席',i); return i>=0?s.slice(i+2,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "no_smoking_or_smoking",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const s=one.slice(Math.max(0,one.indexOf('たばこ'))); const i=s.indexOf('禁煙・喫煙'), j=s.indexOf('喫煙専用室',i); return i>=0?s.slice(i+5,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "parking_lot",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const seat=one.indexOf('お席情報'); const eq=one.indexOf('設備',seat>=0?seat:0); const s=eq>=0?one.slice(eq):one; const i=s.indexOf('駐車場'), j=s.indexOf('カラオケ設備',i); return i>=0?s.slice(i+3,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "space_and_facilities",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const seat=one.indexOf('お席情報'); const eq=one.indexOf('設備',seat>=0?seat:0); if(eq<0)return ''; const s=one.slice(eq); const j=s.indexOf('その他'); return s.slice(0,j>=0?j:undefined).replace(/\\s+/g,' ').trim();} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "course",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname; if(host.includes('ton-worry')) return Array.from(d.querySelectorAll('a[href*=\"/courses/\"]')).map(a=>a.textContent.replace(/\\s+/g,' ').trim()).filter(Boolean).slice(0,6).join(' | '); if(host.includes('tonkan')) return Array.from(d.querySelectorAll('.menu_list li')).map(li=>li.textContent.replace(/\\s+/g,' ').trim()).find(t=>t.includes('宴会コース')) || ''; return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "drink",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname; if(host.includes('ton-worry')){const el=d.querySelector('#drink'); return el ? el.innerText.replace(/\\s+/g,' ').trim().slice(0,600) : '';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "dishes",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname; if(host.includes('ton-worry')) return Array.from(d.querySelectorAll('.homeFoodImgContents')).map(li=>li.textContent.replace(/\\s+/g,' ').trim()).filter(Boolean).slice(0,5).join(' | '); if(host.includes('tonkan')) return Array.from(d.querySelectorAll('.menu_list li')).map(li=>li.textContent.replace(/\\s+/g,' ').trim()).filter(Boolean).join(' | '); return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "occasion",
            "selector": "(() => '')()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "location",
            "selector": "(() => { const d=ROW.ownerDocument; return d.querySelector('a[href*=\"maps.google\"], a[href*=\"google.co.jp/maps\"], a[href*=\"google.com/maps\"]')?.href || ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "service",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const seat=one.indexOf('お席情報'); const eq=one.indexOf('設備',seat>=0?seat:0); const other=one.indexOf('その他',eq>=0?eq:0); if(other<0)return ''; const s=one.slice(other); const j=s.indexOf('関連店舗'); return s.slice(0,j>=0?j:undefined).replace(/\\s+/g,' ').trim();} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "with_children",
            "selector": "(() => { const d=ROW.ownerDocument, host=d.location.hostname, one=ROW.innerText.replace(/\\u00a0/g,' ').replace(/\\s+/g,' '); if(host.includes('ton-worry')){const seat=one.indexOf('お席情報'); const eq=one.indexOf('設備',seat>=0?seat:0); const other=one.indexOf('その他',eq>=0?eq:0); const s=other>=0?one.slice(other):one; const i=s.indexOf('お子様連れ'), j=s.indexOf('ウェディング',i); return i>=0?s.slice(i+5,j>=0?j:undefined).trim():'';} return ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "the_homepage",
            "selector": "(() => ROW.ownerDocument.location.href)()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "the_opening_day",
            "selector": "(() => '')()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "tel",
            "selector": "(() => { const d=ROW.ownerDocument; const tel=d.querySelector('a[href^=\"tel:\"]')?.textContent || d.querySelector('a[href^=\"tel:\"]')?.href?.replace('tel:',''); if(tel) return tel.replace(/\\s+/g,' ').trim(); const t=ROW.innerText; const m=t.match(/(?:電話番号|【連絡先】|連絡先)\\s*[:：]?\\s*([0-9０-９\\-ー]+)/); return m ? m[1].trim() : ''; })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "remarks",
            "selector": "(() => { const d=ROW.ownerDocument; return (d.querySelector('meta[name=\"description\"]')?.content || d.querySelector('meta[property=\"og:description\"]')?.content || '').replace(/\\s+/g,' ').trim(); })()",
            "attribute": "text",
            "isJs": true
          },
          {
            "name": "first_reviewers",
            "selector": "(() => '')()",
            "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": 200,
      "config": {
        "color": "bg-[#8d8d8d]"
      }
    }
  ],
  "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": "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-load",
      "element_type": "group",
      "title": "Page Load",
      "color": "#08bdba",
      "position_x": 48,
      "position_y": 96,
      "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": 1488,
      "position_y": 96,
      "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": 96,
      "width": 380,
      "height": 296,
      "z_index": 20,
      "data": {
        "memberBlockIds": [
          "loop-continue-1"
        ]
      }
    },
    {
      "id": "note-overview",
      "element_type": "note",
      "title": "Overview",
      "content": "Best-effort UScraper equivalent of the Octoparse Tabelog Details Scraper. Scrapes restaurant detail-style fields such as store name, address, transportation/access, operating hours, holidays, budget, payment, seats, smoking, parking, homepage, telephone, remarks, courses and dishes from a multi-URL input list. Navigation strategy: known URL list using navigate.urls[] with structured-export fileMode=append and loop-continue so each supplied restaurant URL is processed. Note: attached analysis shows these URLs are official/third-party restaurant homepages rather than actual Tabelog detail pages; Tabelog-only fields such as rating, opening day, and first reviewers may be blank. One supplied URL redirects to an unrelated website in analysis, so extraction there will be limited.",
      "color": "#f1c21b",
      "position_x": 80,
      "position_y": 20,
      "width": 480,
      "height": 160,
      "z_index": 22,
      "data": {}
    },
    {
      "id": "note-block-structured-export-1",
      "element_type": "note",
      "title": "Note: Structured Export",
      "content": "Structured export with JS columns (source_url, store_name, rating, address, transportation). These selectors are fragile — update if the site layout changes.",
      "color": "#ee5396",
      "position_x": 1760,
      "position_y": 180,
      "width": 340,
      "height": 132,
      "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": 180,
      "width": 340,
      "height": 123,
      "z_index": 22,
      "data": {
        "block_id": "loop-continue-1"
      }
    }
  ]
}