BrightData の週次比較

上級

これはAI, Marketing分野の自動化ワークフローで、35個のノードを含みます。主にIf, Set, Code, Gmail, Markdownなどのノードを使用、AI技術を活用したスマート自動化を実現。 Bright Data、GPT-4.1、Google Workspaceを使用した自動ウェブサイト変更監視

前提条件
  • Googleアカウント + Gmail API認証情報
  • Google Drive API認証情報
  • Google Sheets API認証情報
  • OpenAI API Key
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "id": "pNaD8QIgVGDqbCoU",
  "meta": {
    "instanceId": "3af183a3db355380be4f6d2f3dfb18bdaa750e90f99a48f91bd71080ee6bcbe8",
    "templateCredsSetupCompleted": true
  },
  "name": "BrightData Weekly Comparison",
  "tags": [],
  "nodes": [
    {
      "id": "a2966ed3-e998-47ca-83b3-b7dc4832bc8f",
      "name": "構造化出力パーサー",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        700,
        140
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"filename\": \"domain-path-DD-MM-YYYY.md\",\n  \"metadata\": {\n    \"pageTitle\": \"The primary title of the webpage\",\n    \"metaDescription\": \"The meta description content\"\n  },\n  \"headings\": {\n    \"h1\": [\"List of all H1 headings\"],\n    \"h2\": [\"List of all H2 headings\"],\n    \"h3\": [\"List of all H3 headings\"]\n  },\n  \"pricing\": [\n    {\n      \"planName\": \"Name of the pricing plan/tier\",\n      \"currency\": \"USD/EUR/GBP/etc.\",\n      \"interval\": \"monthly/yearly/one-time\",\n      \"price\": \"Numerical price value\",\n      \"features\": [\"List of features or benefits included in this plan\"]\n    }\n  ],\n  \"navigation\": {\n    \"mainMenu\": [\"Primary navigation items\"],\n    \"subMenu\": [\"Secondary navigation items if present\"]\n  },\n  \"callToAction\": [\"All CTA elements and their text\"],\n  \"contactInfo\": {\n    \"phone\": [\"Phone numbers found\"],\n    \"email\": [\"Email addresses found\"],\n    \"address\": [\"Physical addresses found\"],\n    \"formPresent\": true\n  },\n  \"banners\": [\"Content from promotional banners\"],\n  \"faq\": [\n    {\n      \"question\": \"FAQ question\",\n      \"answer\": \"FAQ answer\"\n    }\n  ]\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "6d4b38bd-fb58-4675-9b83-ade043914d65",
      "name": "ワークフロー変数を設定",
      "type": "n8n-nodes-base.set",
      "position": [
        -260,
        -120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "96347cce-576a-413c-9c9b-b2257eced54d",
              "name": "DriveFolderID",
              "type": "string",
              "value": ""
            },
            {
              "id": "b2f5e75f-575d-40ed-89a8-1c2e537d3220",
              "name": "ComparisonSpreadsheetID",
              "type": "string",
              "value": ""
            },
            {
              "id": "f64718d6-a5f2-491e-abec-b26a6e6125e8",
              "name": "ComparisonSpreadsheetSheetName",
              "type": "string",
              "value": "Sheet1"
            },
            {
              "id": "1a71595c-58c3-4eda-9b7b-5c306123db86",
              "name": "Email",
              "type": "string",
              "value": ""
            },
            {
              "id": "ed5fe6bd-b43b-45b1-b1e8-b20beb329e4d",
              "name": "IsTest",
              "type": "boolean",
              "value": false
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "6ddda34f-556e-49a5-a103-7641a3f0598d",
      "name": "ワークフロー変数とGoogleシートデータを結合",
      "type": "n8n-nodes-base.set",
      "position": [
        180,
        -120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e129ca16-8675-485e-9f21-e5d22b76c6e6",
              "name": "ComparisonSpreadsheetFileName",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.ComparisonSpreadsheetFileName }}"
            },
            {
              "id": "5fdee148-82eb-4542-9fe7-1ba37ec09571",
              "name": "ComparisonSpreadsheetSheetName",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.ComparisonSpreadsheetSheetName }}"
            },
            {
              "id": "7cce5924-a67a-45a2-8792-cd9ad28834b8",
              "name": "Email",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.Email }}"
            },
            {
              "id": "e445b570-384f-4558-99d3-12802b0fa900",
              "name": "DriveFolderID",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.DriveFolderID }}"
            },
            {
              "id": "d487666e-4dd3-4d20-8769-d0daf3bab268",
              "name": "IsTest",
              "type": "boolean",
              "value": "={{ $('Set workflow variables').item.json.IsTest }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "45eefb28-dce0-4fc3-81a1-865762c73226",
      "name": "比較スプレッドシートから読み取り",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -40,
        -120
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.ComparisonSpreadsheetSheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.ComparisonSpreadsheetID }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "vnXMSwscCP06bp9u",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
      "name": "各比較URLをループ処理",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        400,
        -115
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
      "name": "ウェブスクレイピングとデータ抽出エージェント",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        652,
        -365
      ],
      "parameters": {
        "text": "=Please scrape the following url {{ $json.URL }}\n",
        "options": {
          "systemMessage": "=## Role\nYou are an expert Web Data Extraction Specialist with a specialization in content analysis, information architecture, and structured data organization.\n\n## Task\nYour primary task is to extract, organize, and present key website components from any URL provided by the user.\nTo achieve this, you will need to perform the following:\n- Scrape the target webpage using the scrape_as_markdown tool to obtain its content\n- Generate a clean filename based on the URL and current date for storing the content as JSON\n- Systematically extract and categorize the following elements from the markdown content\n- Format the extracted data into a structured JSON object containing the processed elements\n\n## Tools\nYou can use the following tools:\n1. **scrape_as_markdown**: Use this tool to extract the full content of a webpage in Markdown format. This tool can bypass bot detection and CAPTCHA systems to ensure reliable extraction.\n\n## Input\nYou will receive input as a URL to the webpage that requires data extraction.\n\n## Output\nYour output must be a single, valid JSON object containing all extracted elements and a clean filename. Do not include any explanatory text before or after the JSON.\n\n{\n  \"filename\": \"domain-path-DD-MM-YYYY.json\",\n  \"metadata\": {\n    \"pageTitle\": \"The primary title of the webpage\",\n    \"metaDescription\": \"The meta description content\"\n  },\n  \"headings\": {\n    \"h1\": [\"List of all H1 headings\"],\n    \"h2\": [\"List of all H2 headings\"],\n    \"h3\": [\"List of all H3 headings\"]\n  },\n  \"pricing\": [\n    {\n      \"planName\": \"Name of the pricing plan/tier\",\n      \"currency\": \"USD/EUR/GBP/etc.\",\n      \"interval\": \"monthly/yearly/one-time\",\n      \"price\": \"Numerical price value\",\n      \"features\": [\"List of features or benefits included in this plan\"]\n    }\n  ],\n  \"navigation\": {\n    \"mainMenu\": [\"Primary navigation items\"],\n    \"subMenu\": [\"Secondary navigation items if present\"]\n  },\n  \"callToAction\": [\"All CTA elements and their text\"],\n  \"contactInfo\": {\n    \"phone\": [\"Phone numbers found\"],\n    \"email\": [\"Email addresses found\"],\n    \"address\": [\"Physical addresses found\"],\n    \"formPresent\": true/false\n  },\n  \"banners\": [\"Content from promotional banners\"],\n  \"faq\": [\n    {\n      \"question\": \"FAQ question\",\n      \"answer\": \"FAQ answer\"\n    }\n  ]\n}\n\nFor any elements not found on the webpage, include an empty array [] or appropriate null value. Ensure the JSON is properly formatted and valid. If the extraction process encounters any errors, include an additional \"errors\" key with relevant details.\n\nWhen extracting pricing information, analyze the webpage carefully to identify all pricing plans. For each plan, determine:\n- The name of the plan (e.g., \"Basic\", \"Pro\", \"Enterprise\")\n- The currency symbol or code used\n- Whether the pricing is monthly, yearly, or one-time\n- The numerical price value\n- All features or details associated with that pricing tier\n\nThe filename should be generated using the following format:\n- Extract the domain name from the URL (without www.)\n- Extract the path (without any query parameters or fragments)\n- Replace slashes with hyphens\n- Add the current date in DD-MM-YYYY format\n- Use .json as the file extension\n- For example, if the URL is https://asana.com/pricing and today is May 20, 2025, the filename would be \"asana-pricing-20-05-2025.json\"\n- Today's date is {{ $now }}\n\nEven if some pricing information is ambiguous or incomplete, make reasonable inferences and include all relevant details in the structured format."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "c1f69dc5-6612-4575-aaf4-1d6a7a70c423",
      "name": "今週のJSONファイルをアップロード",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1280,
        -365
      ],
      "parameters": {
        "name": "={{ $('Web scraping and data extraction agent').item.json.output.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Loop over each comparison URL').item.json.DriveFolderID }}"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ENsCK6J7JBSny3Pv",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "e4a1fd2c-e1a5-4065-a9c8-76d1c854af95",
      "name": "比較シートを今週のファイルデータで更新",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1500,
        -365
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Loop over each comparison URL').item.json.URL }}",
            "Previous Week ID": "={{ $('Loop over each comparison URL').item.json[\"Current Week File ID\"] }}",
            "Current Week File ID": "={{ $json.id }}",
            "Current Week File Link": "={{ $json.webViewLink }}",
            "Previous Week File Link": "={{ $('Loop over each comparison URL').item.json[\"Current Week File Link\"] }}"
          },
          "schema": [
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Previous Week ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week File Link",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Previous Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Current Week File ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File Link",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Current Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Comparison File",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Comparison File",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "URL"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit?usp=drivesdk",
          "cachedResultName": "BrightData Scraping Comparison"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "vnXMSwscCP06bp9u",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "32934604-9e72-4f6a-aa55-fc0abff1d85c",
      "name": "前週ファイルの存在を確認",
      "type": "n8n-nodes-base.if",
      "position": [
        1720,
        -365
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d46019c6-ec3b-4e8b-80b2-44ffb2a82e51",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json[\"Previous Week ID\"] }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "301dfc46-f1d4-4b1a-892b-25ecb4495b77",
      "name": "前週ファイルをダウンロード",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1940,
        -365
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json[\"Previous Week ID\"] }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ENsCK6J7JBSny3Pv",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "036d00c9-7414-4883-ac56-ef9368195b85",
      "name": "前週ファイルをJSONに変換",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        2160,
        -365
      ],
      "parameters": {
        "options": {},
        "operation": "fromJson"
      },
      "typeVersion": 1
    },
    {
      "id": "67b8ee0a-2ab0-43cd-b24f-0c8ba6b04cd1",
      "name": "前週と今週を設定",
      "type": "n8n-nodes-base.set",
      "position": [
        2380,
        -365
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "af75985e-4f86-4493-9fbd-0d0c7b383001",
              "name": "previous",
              "type": "object",
              "value": "={{ $json.data[0].output }}"
            },
            {
              "id": "718aeb81-59e9-49f9-aa5b-dc3c194d2efa",
              "name": "current",
              "type": "object",
              "value": "={{ $('Web scraping and data extraction agent').item.json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "40b828f7-08f2-41ea-a6f7-595c5e4ae3e0",
      "name": "テストモードを確認",
      "type": "n8n-nodes-base.if",
      "position": [
        2600,
        -365
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "650a5f5e-3041-4d2f-a891-1d369b09c17a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $('Loop over each comparison URL').item.json.IsTest }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "af562b9f-3cfc-4715-ae47-779a0554e7d2",
      "name": "前週変更をモック",
      "type": "n8n-nodes-base.code",
      "position": [
        2820,
        -440
      ],
      "parameters": {
        "jsCode": "// Code node in N8n\nconst inputData = $input.first().json;\n\n// Clone the previous data before modifying it\nconst previous = {...inputData.previous};\n\n// Change 1: Increase all numeric prices by $5 in the pricing array\nif (previous?.pricing && Array.isArray(previous.pricing)) {\n  previous.pricing.forEach(plan => {\n    // Check if price is a numeric string\n    if (plan.price && !isNaN(parseFloat(plan.price))) {\n      // Add $5 to the price\n      plan.price = (parseFloat(plan.price) + 5).toString();\n    }\n  });\n}\n\n// Change 2: Modify a feature in the first paid plan (if exists)\nif (previous?.pricing && previous.pricing.length > 1) {\n  const firstPaidPlan = previous.pricing.find(plan => \n    plan.price && plan.price !== \"0\" && !isNaN(parseFloat(plan.price)));\n  \n  if (firstPaidPlan && Array.isArray(firstPaidPlan.features) && firstPaidPlan.features.length > 1) {\n    // Add \"Premium\" prefix to the second feature (if it exists)\n    if (firstPaidPlan.features[1]) {\n      firstPaidPlan.features[1] = \"Premium \" + firstPaidPlan.features[1];\n    }\n  }\n}\n\n// Change 3: Update the first FAQ answer (if exists)\nif (previous?.faq && Array.isArray(previous.faq) && previous.faq.length > 0) {\n  if (previous.faq[0] && previous.faq[0].answer) {\n    // Add a sentence to the end of the answer\n    previous.faq[0].answer += \" For more information, contact our sales team.\";\n  }\n}\n\n// Return the data with current and modified previous\nreturn [{\n  json: {\n    current: inputData.current,\n    previous: previous\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "dd764b6d-d412-44e6-8816-e7b66bbb44c6",
      "name": "週間の変更を検出",
      "type": "n8n-nodes-base.code",
      "position": [
        3040,
        -365
      ],
      "parameters": {
        "jsCode": "// N8n Code Node to compare previous and current data\n// Input: $input.first().json contains previous and current data objects\n\nfunction detectChanges() {\n  const previous = $input.first().json.previous;\n  const current = $input.first().json.current;\n  \n  // Initialize changes object with better structure for Markdown generation\n  const changes = {\n    detected: false,\n    sections: {}, // Organized by section\n    summary: {\n      totalChanges: 0,\n      timestamp: new Date().toISOString()\n    }\n  };\n  \n  // Helper function to add a change to the changes object\n  function addChange(section, path, changeType, changeData) {\n    // Initialize section if it doesn't exist\n    if (!changes.sections[section]) {\n      changes.sections[section] = {\n        name: formatSectionName(section),\n        changes: []\n      };\n    }\n    \n    // Format display path\n    const displayPath = formatPath(path);\n    \n    // Add change to the section\n    changes.sections[section].changes.push({\n      displayPath,\n      type: changeType,\n      ...changeData\n    });\n    \n    // Update global detected flag and counter\n    changes.detected = true;\n    changes.summary.totalChanges++;\n  }\n  \n  // Helper function to format section name for display\n  function formatSectionName(name) {\n    // Convert camelCase to Title Case with spaces\n    return name.replace(/([A-Z])/g, ' $1')\n      .replace(/^./, str => str.toUpperCase())\n      .trim();\n  }\n  \n  // Helper function to format path for display\n  function formatPath(path) {\n    // Format the path elements to be more readable\n    return path.replace(/\\[([^\\]]+)\\]/g, ' ($1)');\n  }\n  \n  // Helper function to compare primitive values\n  function compareValues(prevVal, currVal, path) {\n    if (prevVal !== currVal) {\n      const section = path.split('.')[0];\n      addChange(section, path, 'changed', {\n        old: prevVal,\n        new: currVal\n      });\n      return true;\n    }\n    return false;\n  }\n  \n  // Helper function to compare arrays\n  function compareArrays(prevArr, currArr, path, matchKey = null) {\n    let changed = false;\n    const section = path.split('.')[0];\n    const additions = [];\n    const deletions = [];\n    \n    // Check for deletions\n    for (let i = 0; i < prevArr.length; i++) {\n      const prevItem = prevArr[i];\n      \n      if (matchKey && typeof prevItem === 'object' && prevItem !== null) {\n        // For arrays of objects with a specified match key (like planName or question)\n        const matchFound = currArr.some(currItem => currItem[matchKey] === prevItem[matchKey]);\n        if (!matchFound) {\n          deletions.push(prevItem);\n          changed = true;\n        }\n      } else {\n        // For arrays of primitives\n        if (!currArr.includes(prevItem)) {\n          deletions.push(prevItem);\n          changed = true;\n        }\n      }\n    }\n    \n    // Check for additions\n    for (let i = 0; i < currArr.length; i++) {\n      const currItem = currArr[i];\n      \n      if (matchKey && typeof currItem === 'object' && currItem !== null) {\n        // For arrays of objects with a specified match key\n        const matchFound = prevArr.some(prevItem => prevItem[matchKey] === currItem[matchKey]);\n        if (!matchFound) {\n          additions.push(currItem);\n          changed = true;\n        }\n      } else {\n        // For arrays of primitives\n        if (!prevArr.includes(currItem)) {\n          additions.push(currItem);\n          changed = true;\n        }\n      }\n    }\n    \n    // Check for changes in matching objects\n    if (matchKey) {\n      for (let i = 0; i < currArr.length; i++) {\n        const currItem = currArr[i];\n        if (typeof currItem === 'object' && currItem !== null) {\n          const matchingPrevItem = prevArr.find(prevItem => prevItem[matchKey] === currItem[matchKey]);\n          if (matchingPrevItem) {\n            // Compare the matching objects recursively\n            const itemPath = `${path}[${matchKey}=${currItem[matchKey]}]`;\n            compareObjects(matchingPrevItem, currItem, itemPath);\n          }\n        }\n      }\n    }\n    \n    if (changed) {\n      addChange(section, path, 'array_changed', {\n        additions: additions.length > 0 ? additions : null,\n        deletions: deletions.length > 0 ? deletions : null\n      });\n    }\n    \n    return changed;\n  }\n  \n  // Helper function to compare objects\n  function compareObjects(prevObj, currObj, path = '') {\n    if (!prevObj || !currObj) return false;\n    \n    const allKeys = new Set([...Object.keys(prevObj), ...Object.keys(currObj)]);\n    let changed = false;\n    \n    for (const key of allKeys) {\n      // Skip rawMarkdown as requested\n      if (key === 'rawMarkdown') continue;\n      \n      const keyPath = path ? `${path}.${key}` : key;\n      const section = keyPath.split('.')[0];\n      const prevVal = prevObj[key];\n      const currVal = currObj[key];\n      \n      // Handle missing keys\n      if (!(key in prevObj)) {\n        addChange(section, keyPath, 'added', {\n          value: currVal\n        });\n        changed = true;\n        continue;\n      }\n      \n      if (!(key in currObj)) {\n        addChange(section, keyPath, 'removed', {\n          value: prevVal\n        });\n        changed = true;\n        continue;\n      }\n      \n      // Compare based on type\n      if (Array.isArray(prevVal) && Array.isArray(currVal)) {\n        // Special handling for specific array types\n        if (key === 'pricing') {\n          compareArrays(prevVal, currVal, keyPath, 'planName');\n        } else if (key === 'features') {\n          compareArrays(prevVal, currVal, keyPath);\n        } else if (key === 'faq') {\n          compareArrays(prevVal, currVal, keyPath, 'question');\n        } else {\n          compareArrays(prevVal, currVal, keyPath);\n        }\n      } else if (\n        typeof prevVal === 'object' && prevVal !== null &&\n        typeof currVal === 'object' && currVal !== null\n      ) {\n        compareObjects(prevVal, currVal, keyPath);\n      } else {\n        compareValues(prevVal, currVal, keyPath);\n      }\n    }\n    \n    return changed;\n  }\n  \n  // Start comparison - removed the .output reference\n  compareObjects(previous, current);\n  \n  return [{ json: {previous, current, changes} }];\n}\n\n// Execute the function and return the results\nreturn detectChanges();"
      },
      "typeVersion": 2
    },
    {
      "id": "e5a8b7c1-53ec-4a26-8791-30db494cde92",
      "name": "検出した変更からMarkdownを生成",
      "type": "n8n-nodes-base.code",
      "position": [
        3260,
        -365
      ],
      "parameters": {
        "jsCode": "// N8n Code Node to generate Markdown from structured changes\n// Input: $input.changes contains the comparison results from the improved comparison node\nfunction generateChangelogMarkdown() {\n  // Changed to directly access the changes property from the input\n  const changes = $input.first().json.changes;\n  \n  if (!changes || !changes.detected) {\n    return [{ json: { markdown: \"# Changelog\\n\\nNo changes detected.\" }}];\n  }\n  \n  // Start building the markdown\n  // Getting the filename from the input for the title\n  let fileNameWithoutExt = '';\n  try {\n    // Try to get the filename from the Loop Over Items node if available\n    fileNameWithoutExt = $('Loop over each comparison URL').first().json[\"\"][0];\n  } catch (e) {\n    // Fallback to a generic title if the loop node isn't available\n    fileNameWithoutExt = \"Website\";\n  }\n  \n  let markdown = `# ${fileNameWithoutExt} Changes\\n\\n`;\n  \n  // Process each section in the changes object\n  Object.values(changes.sections).forEach(section => {\n    markdown += `## ${section.name}\\n\\n`;\n    \n    // Process each change in this section\n    section.changes.forEach(change => {\n      switch (change.type) {\n        case 'changed':\n          markdown += `- **${change.displayPath}** changed from \\`${formatValue(change.old)}\\` to \\`${formatValue(change.new)}\\`\\n`;\n          break;\n          \n        case 'added':\n          markdown += `- **${change.displayPath}** was added with value \\`${formatValue(change.value)}\\`\\n`;\n          break;\n          \n        case 'removed':\n          markdown += `- **${change.displayPath}** was removed (previously \\`${formatValue(change.value)}\\`)\\n`;\n          break;\n          \n        case 'array_changed':\n          markdown += `- **${change.displayPath}** has changes:\\n`;\n          \n          // Handle additions\n          if (change.additions && change.additions.length > 0) {\n            markdown += `  - **Added**:\\n`;\n            change.additions.forEach(item => {\n              markdown += `    - \\`${formatValue(item)}\\`\\n`;\n            });\n          }\n          \n          // Handle deletions\n          if (change.deletions && change.deletions.length > 0) {\n            markdown += `  - **Removed**:\\n`;\n            change.deletions.forEach(item => {\n              markdown += `    - \\`${formatValue(item)}\\`\\n`;\n            });\n          }\n          break;\n      }\n    });\n    \n    markdown += '\\n';\n  });\n  \n  // Add summary section\n  markdown += `## Summary\\n\\n`;\n  markdown += `Total changes detected: **${changes.summary.totalChanges}**\\n\\n`;\n  markdown += `Generated on: **${new Date(changes.summary.timestamp).toLocaleDateString('en-US', {\n    year: 'numeric',\n    month: 'long',\n    day: 'numeric'\n  })}**\\n`;\n  \n  // Return in the format expected by n8n\n  return [{ json: { markdown } }];\n}\n\n// Helper function to format values for markdown display\nfunction formatValue(value) {\n  if (value === null || value === undefined) {\n    return 'null';\n  } else if (typeof value === 'object') {\n    if (Array.isArray(value)) {\n      // For arrays, simplify to show length\n      if (value.length === 0) return '[]';\n      if (value.length > 3) {\n        return `[Array with ${value.length} items]`;\n      }\n      // For small arrays, show the items\n      return JSON.stringify(value).substring(0, 60) + (JSON.stringify(value).length > 60 ? '...' : '');\n    }\n    \n    // For objects with a name or key identifier, try to use that\n    if (value.name) return value.name;\n    if (value.title) return value.title;\n    if (value.id) return value.id;\n    if (value.planName) return value.planName;\n    if (value.question) return value.question;\n    \n    // For other objects, shorten to reasonable length\n    const objStr = JSON.stringify(value);\n    return objStr.substring(0, 60) + (objStr.length > 60 ? '...' : '');\n  } else if (typeof value === 'string') {\n    // For strings, add quoting\n    return value;\n  } else {\n    // For other primitives, convert to string\n    return String(value);\n  }\n}\n\n// Execute the function and return the markdown result\nreturn generateChangelogMarkdown();"
      },
      "typeVersion": 2
    },
    {
      "id": "16c9f196-6acf-4d3a-946b-727c121b503a",
      "name": "MarkdownをHTMLに変換",
      "type": "n8n-nodes-base.markdown",
      "position": [
        3480,
        -365
      ],
      "parameters": {
        "mode": "markdownToHtml",
        "options": {},
        "markdown": "={{ $json.markdown }}"
      },
      "typeVersion": 1
    },
    {
      "id": "3df4c31f-db47-40a5-9140-d2de7b1fbf2e",
      "name": "比較ドキュメントを作成",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        3700,
        -365
      ],
      "parameters": {
        "title": "={{ $('Web scraping and data extraction agent').first().json.output.filename.replace(/\\.[^/.]+$/, '') + '-comparison.md' }}",
        "folderId": "default"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "id": "T3HEUOkeb37yLim7",
          "name": "Google Docs account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "da24c1a3-fa3b-4b06-b5b9-78dd6d872756",
      "name": "比較ドキュメントを結果で更新",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        3920,
        -365
      ],
      "parameters": {
        "actionsUi": {
          "actionFields": [
            {
              "text": "={{ $('Convert Markdown to HTML').item.json.data }}",
              "action": "insert"
            }
          ]
        },
        "operation": "update",
        "documentURL": "={{ $json.id }}"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "id": "T3HEUOkeb37yLim7",
          "name": "Google Docs account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "b532d34b-0ac0-4a00-9949-a9a959e27b31",
      "name": "比較スプレッドシートを比較ファイルで更新",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4140,
        -365
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Loop over each comparison URL').item.json.URL }}",
            "Comparison File": "=https://docs.google.com/document/d/{{ $json.documentId }}"
          },
          "schema": [
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week ID",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Previous Week ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week File Link",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Previous Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File ID",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Current Week File ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File Link",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Current Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Comparison File",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Comparison File",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "URL"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit?usp=drivesdk",
          "cachedResultName": "BrightData Scraping Comparison"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "vnXMSwscCP06bp9u",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "7ef3ba20-c79e-4d49-8a68-c11d20c77def",
      "name": "比較結果をメール送信",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4340,
        -260
      ],
      "webhookId": "8d51cb0f-f585-4222-93dd-2fffcead588e",
      "parameters": {
        "sendTo": "dave@emberautomation.com",
        "message": "={{ $('Convert Markdown to HTML').item.json.data }}",
        "options": {},
        "subject": "={{ $now.format('yyyy-MM-dd') }}: {{ $('Loop over each comparison URL').item.json.URL }} weekly comparison"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "nkZOm8cNEGHWhTE4",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a0926fe8-80c2-456b-b9c2-4dc1675c408c",
      "name": "付箋",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -540,
        -1340
      ],
      "parameters": {
        "width": 760,
        "height": 1060,
        "content": "# BrightData Weekly Comparison\n## Overview\nThis workflow tracks changes on web pages, compares data, generates change reports, saves to Drive, and sends email notifications. **The workflow runs automatically on a weekly basis.**\n\n## Prerequisites\n- **Bright Data MCP Server**: Set up a Bright Data MCP server for web scraping\n- **n8n MCP Client Node**: Install the community node from `n8n-nodes-mcp` (https://www.npmjs.com/package/n8n-nodes-mcp)\n\n## Setup Steps\n1. **Duplicate Spreadsheet**\n   - Make a copy of the comparison spreadsheet: [Sheet to Copy](https://docs.google.com/spreadsheets/d/1oPyAaTS8GMqlaBcyCO7G7MRtzMUUaOnA45JfWCzcCa8/edit?usp=sharing)\n   - Update the URLs of web pages to track\n\n2. **Configure Variables**\n   - Open the \"Set workflow variables\" node\n   - Update these values:\n     - `DriveFolderID`: Your Google Drive folder ID\n     - `ComparisonSpreadsheetFileID`: `1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk` (or your copied spreadsheet ID)\n     - `ComparisonSpreadsheetSheetName`: Sheet name (usually \"Sheet1\")\n     - `Email`: Where to send reports\n     - `IsTest`: Set to `true` only for testing (set to `false` for regular operation)\n\n3. **Configure Bright Data MCP**\n   - Set up your Bright Data MCP credentials in the MCP client node\n   - Configure the MCP server using the documentation: https://github.com/luminati-io/brightdata-mcp\n\n4. **Set Up Credentials**\n   - Configure credentials for:\n     - Google Sheets\n     - Google Drive\n     - Google Docs\n     - Gmail\n     - OpenAI (or alternative AI provider)\n     - Bright Data MCP\n\n5. **Run Workflow**\n   - Execute the workflow manually to test\n   - Check your Drive folder and email for results\n   - **Once setup is complete, the workflow will run automatically every week**"
      },
      "typeVersion": 1
    },
    {
      "id": "33c8b369-b6f7-4bb9-87e2-d202d998255d",
      "name": "GPT-4.1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        620,
        -145
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "gpt-4.1"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "NuECwZyKpEfWhSN1",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "700e8bb2-607d-4889-b248-88bf6464c587",
      "name": "スケジュールトリガー",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -480,
        -120
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                3
              ],
              "triggerAtHour": 12
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c2919b53-c13f-4033-86f2-3b4e2e28dfa8",
      "name": "markdownとしてスクレイピング",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        740,
        -145
      ],
      "parameters": {
        "toolName": "scrape_as_markdown",
        "operation": "executeTool",
        "toolParameters": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"
      },
      "credentials": {
        "mcpClientApi": {
          "id": "mO1My0js13704jqM",
          "name": "MCP Client (STDIO) account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0",
      "name": "自動修正出力パーサー",
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "position": [
        640,
        20
      ],
      "parameters": {
        "options": {
          "prompt": "Instructions:\n--------------\n{instructions}\n--------------\nCompletion:\n--------------\n{completion}\n--------------\n\nAbove, the Completion did not satisfy the constraints given in the Instructions.\nError:\n--------------\n{error}\n--------------\n\nPlease try again. Please only respond with an answer that satisfies the constraints laid out in the Instructions:"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f3766efe-53a7-4311-9b53-af9f8d11b292",
      "name": "付箋1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -540,
        -260
      ],
      "parameters": {
        "color": 2,
        "width": 220,
        "height": 340,
        "content": "## Scheduled Weekly"
      },
      "typeVersion": 1
    },
    {
      "id": "93f1107c-8e81-439b-a912-5900e36afd8b",
      "name": "付箋2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -280,
        -260
      ],
      "parameters": {
        "color": 3,
        "width": 620,
        "height": 340,
        "content": "## Initialization\nInitializes the workflow variables, reads the main spreadsheet, then merges the spreadsheet results with the main workflow variables. "
      },
      "typeVersion": 1
    },
    {
      "id": "f4882880-6ee4-4a44-9967-1be01de7151c",
      "name": "付箋3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        580,
        -520
      ],
      "parameters": {
        "color": 4,
        "width": 400,
        "height": 780,
        "content": "## AI Scraping\nFor the given URL, the agent will use the Scrape as Markdown tool to scrape the page getting the content as Markdown. It will then generate a JSON structure, extracting out relevant information from the page. "
      },
      "typeVersion": 1
    },
    {
      "id": "8f6da1fd-c91a-4c99-94f8-b2464a0786be",
      "name": "付箋4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1020,
        -520
      ],
      "parameters": {
        "color": 5,
        "width": 860,
        "height": 400,
        "content": "## Process current week results\nThe agent's response is turned into a binary file and then saved in Google Drive for the next week. Then the main spreadsheet is updated with that file. Finally checking if we have a previous week to compare this week to. If not, we finish and move on to the next item. If we do, then we move on and process the previous week's results vs the current week. "
      },
      "typeVersion": 1
    },
    {
      "id": "25f758b4-2e11-4cde-bcc3-1a8e53106d29",
      "name": "付箋5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1900,
        -520
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 400,
        "content": "## Process previous week results\nRead the previous week's ID and download the file from Google Drive. Then, set variables ready for processing. "
      },
      "typeVersion": 1
    },
    {
      "id": "f8d7c276-9540-431d-860d-10e15b769fe4",
      "name": "付箋6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2560,
        -520
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 400,
        "content": "## Mocking\nIf we are in test mode, then this will mock example changes. Otherwise, it will carry on as normal. "
      },
      "typeVersion": 1
    },
    {
      "id": "c2dfbe5e-e79e-4cc8-91f2-a61bfef2721e",
      "name": "付箋7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3020,
        -520
      ],
      "parameters": {
        "color": 2,
        "width": 1260,
        "height": 400,
        "content": "## Current week vs previous week comparison\nUsing code notes, we detect the changes from the previous week vs the current week and then convert that to a Markdown document and then use the Markdown to HTML node.  Finally, creating a document in Google Docs, and then updating the main spreadsheet with that comparison document. "
      },
      "typeVersion": 1
    },
    {
      "id": "a261bcd8-91a1-40f4-928f-19013b68b998",
      "name": "今週のJSONレスポンスをファイルに変換",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        1060,
        -365
      ],
      "parameters": {
        "options": {},
        "operation": "toJson"
      },
      "typeVersion": 1.1
    },
    {
      "id": "dc49334a-6d00-4476-b84c-7bddfa3c0911",
      "name": "付箋8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4300,
        -520
      ],
      "parameters": {
        "width": 380,
        "height": 400,
        "content": "## Send the comparison email"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "3556e422-eddc-40df-8f4f-860d621258d4",
  "connections": {
    "33c8b369-b6f7-4bb9-87e2-d202d998255d": {
      "ai_languageModel": [
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "700e8bb2-607d-4889-b248-88bf6464c587": {
      "main": [
        [
          {
            "node": "6d4b38bd-fb58-4675-9b83-ade043914d65",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "40b828f7-08f2-41ea-a6f7-595c5e4ae3e0": {
      "main": [
        [
          {
            "node": "af562b9f-3cfc-4715-ae47-779a0554e7d2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "dd764b6d-d412-44e6-8816-e7b66bbb44c6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c2919b53-c13f-4033-86f2-3b4e2e28dfa8": {
      "ai_tool": [
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "6d4b38bd-fb58-4675-9b83-ade043914d65": {
      "main": [
        [
          {
            "node": "45eefb28-dce0-4fc3-81a1-865762c73226",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "16c9f196-6acf-4d3a-946b-727c121b503a": {
      "main": [
        [
          {
            "node": "3df4c31f-db47-40a5-9140-d2de7b1fbf2e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a2966ed3-e998-47ca-83b3-b7dc4832bc8f": {
      "ai_outputParser": [
        [
          {
            "node": "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0": {
      "ai_outputParser": [
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "3df4c31f-db47-40a5-9140-d2de7b1fbf2e": {
      "main": [
        [
          {
            "node": "da24c1a3-fa3b-4b06-b5b9-78dd6d872756",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "af562b9f-3cfc-4715-ae47-779a0554e7d2": {
      "main": [
        [
          {
            "node": "dd764b6d-d412-44e6-8816-e7b66bbb44c6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "dd764b6d-d412-44e6-8816-e7b66bbb44c6": {
      "main": [
        [
          {
            "node": "e5a8b7c1-53ec-4a26-8791-30db494cde92",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "301dfc46-f1d4-4b1a-892b-25ecb4495b77": {
      "main": [
        [
          {
            "node": "036d00c9-7414-4883-ac56-ef9368195b85",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c04cec36-1664-48d7-a9ae-a5665bc2c188": {
      "main": [
        [],
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c1f69dc5-6612-4575-aaf4-1d6a7a70c423": {
      "main": [
        [
          {
            "node": "e4a1fd2c-e1a5-4065-a9c8-76d1c854af95",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7ef3ba20-c79e-4d49-8a68-c11d20c77def": {
      "main": [
        [
          {
            "node": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "45eefb28-dce0-4fc3-81a1-865762c73226": {
      "main": [
        [
          {
            "node": "6ddda34f-556e-49a5-a103-7641a3f0598d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "67b8ee0a-2ab0-43cd-b24f-0c8ba6b04cd1": {
      "main": [
        [
          {
            "node": "40b828f7-08f2-41ea-a6f7-595c5e4ae3e0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "036d00c9-7414-4883-ac56-ef9368195b85": {
      "main": [
        [
          {
            "node": "67b8ee0a-2ab0-43cd-b24f-0c8ba6b04cd1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "32934604-9e72-4f6a-aa55-fc0abff1d85c": {
      "main": [
        [
          {
            "node": "301dfc46-f1d4-4b1a-892b-25ecb4495b77",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c50e3ec4-c3bf-4417-94ad-5b57ad6424da": {
      "main": [
        [
          {
            "node": "a261bcd8-91a1-40f4-928f-19013b68b998",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e5a8b7c1-53ec-4a26-8791-30db494cde92": {
      "main": [
        [
          {
            "node": "16c9f196-6acf-4d3a-946b-727c121b503a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "da24c1a3-fa3b-4b06-b5b9-78dd6d872756": {
      "main": [
        [
          {
            "node": "b532d34b-0ac0-4a00-9949-a9a959e27b31",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a261bcd8-91a1-40f4-928f-19013b68b998": {
      "main": [
        [
          {
            "node": "c1f69dc5-6612-4575-aaf4-1d6a7a70c423",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6ddda34f-556e-49a5-a103-7641a3f0598d": {
      "main": [
        [
          {
            "node": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b532d34b-0ac0-4a00-9949-a9a959e27b31": {
      "main": [
        [
          {
            "node": "7ef3ba20-c79e-4d49-8a68-c11d20c77def",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e4a1fd2c-e1a5-4065-a9c8-76d1c854af95": {
      "main": [
        [
          {
            "node": "32934604-9e72-4f6a-aa55-fc0abff1d85c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

上級 - 人工知能, マーケティング

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
上級
ノード数35
カテゴリー2
ノードタイプ18
難易度説明

上級者向け、16ノード以上の複雑なワークフロー

作成者
Daniel Shashko

Daniel Shashko

@tomax

AI automation specialist and a marketing enthusiast. More than 6 years of experience in SEO/GEO. Senior SEO at Bright Data.

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34