{ "meta": { "instanceId": "f0a68da631efd4ed052a324b63ff90f7a844426af0398a68338f44245d1dd9e5" }, "nodes": [ { "id": "edef59f6-0197-408e-a819-141c1ca8dedd", "name": "When clicking \"Execute Workflow\"", "type": "n8n-nodes-base.manualTrigger", "position": [ -1820, 780 ], "parameters": {}, "typeVersion": 1 }, { "id": "d56deaf5-1ad8-45a2-bbf0-3b71560f8036", "name": "Extract next start value", "type": "n8n-nodes-base.code", "position": [ -640, 480 ], "parameters": { "mode": "runOnceForEachItem", "jsCode": "let nextUrl\n\nif ($json && $json[\"serpapi_pagination\"] && $json[\"serpapi_pagination\"][\"next\"]) {\n nextUrl = $json[\"serpapi_pagination\"][\"next\"];\n\n$input.item.json.start = nextUrl.split('&').find(param => param.startsWith('start=')).split('=')[1];\n}\n\n\nreturn $input.item;" }, "typeVersion": 2 }, { "id": "6562c236-c957-437b-91a9-15e98af09858", "name": "Merge all values from SERPAPI", "type": "n8n-nodes-base.code", "position": [ -140, 680 ], "parameters": { "jsCode": "const allData = []\n\nlet counter = 0;\ndo {\n try {\n const items = $items(\"SERPAPI - Scrape Google Maps URL\", 0, counter).map(item => item.json.local_results);\n allData.push.apply(allData, items);\n } catch (error) {\n return [{json: {allData}}]; \n }\n\n counter++;\n} while(true);\nreturn $input.all();" }, "typeVersion": 2 }, { "id": "357e8a57-dbb5-4241-b9c2-863b3ae3fd96", "name": "Transform data in the right format", "type": "n8n-nodes-base.code", "position": [ 380, 680 ], "parameters": { "jsCode": "console.log($input.all())\n\n\nconst data = $input.all()\n\nconsole.log(\"error\",data)\n\nfunction mergeData(data) {\n let merged = [];\n data.forEach(entry => {\n for (const key in entry.json) {\n merged.push(entry.json[key]);\n }\n });\n return merged;\n}\n\nconst mergedData = mergeData(data);\nconsole.log(mergedData);\n\n\nreturn mergedData.filter(item => item !== null);" }, "typeVersion": 2 }, { "id": "4e8e9ae9-f5e3-4bfd-b0d4-9403a1c38d39", "name": "Add rows in Google Sheets", "type": "n8n-nodes-base.googleSheets", "position": [ 760, 680 ], "parameters": { "columns": { "value": {}, "schema": [ { "id": "position", "type": "string", "display": true, "required": false, "displayName": "position", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "title", "type": "string", "display": true, "required": false, "displayName": "title", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "phone", "type": "string", "display": true, "required": false, "displayName": "phone", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "website", "type": "string", "display": true, "required": false, "displayName": "website", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "rating", "type": "string", "display": true, "required": false, "displayName": "rating", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "reviews", "type": "string", "display": true, "required": false, "displayName": "reviews", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "place_id", "type": "string", "display": true, "removed": false, "required": false, "displayName": "place_id", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "data_id", "type": "string", "display": true, "required": false, "displayName": "data_id", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "data_cid", "type": "string", "display": true, "required": false, "displayName": "data_cid", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "reviews_link", "type": "string", "display": true, "required": false, "displayName": "reviews_link", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "photos_link", "type": "string", "display": true, "required": false, "displayName": "photos_link", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "gps_coordinates", "type": "string", "display": true, "required": false, "displayName": "gps_coordinates", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "place_id_search", "type": "string", "display": true, "required": false, "displayName": "place_id_search", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "provider_id", "type": "string", "display": true, "required": false, "displayName": "provider_id", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "price", "type": "string", "display": true, "required": false, "displayName": "price", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "type", "type": "string", "display": true, "required": false, "displayName": "type", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "types", "type": "string", "display": true, "required": false, "displayName": "types", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "address", "type": "string", "display": true, "required": false, "displayName": "address", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "open_state", "type": "string", "display": true, "required": false, "displayName": "open_state", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "hours", "type": "string", "display": true, "required": false, "displayName": "hours", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "operating_hours", "type": "string", "display": true, "required": false, "displayName": "operating_hours", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "description", "type": "string", "display": true, "required": false, "displayName": "description", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "service_options", "type": "string", "display": true, "required": false, "displayName": "service_options", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "order_online", "type": "string", "display": true, "required": false, "displayName": "order_online", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "thumbnail", "type": "string", "display": true, "required": false, "displayName": "thumbnail", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "editorial_reviews", "type": "string", "display": true, "required": false, "displayName": "editorial_reviews", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "unclaimed_listing", "type": "string", "display": true, "required": false, "displayName": "unclaimed_listing", "defaultMatch": false, "canBeUsedToMatch": true } ], "mappingMode": "autoMapInputData", "matchingColumns": [ "place_id" ] }, "options": { "cellFormat": "RAW" }, "operation": "appendOrUpdate", "sheetName": { "__rl": true, "mode": "list", "value": 2023033319, "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=2023033319", "cachedResultName": "Results" }, "documentId": { "__rl": true, "mode": "url", "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=2023033319" } }, "credentials": { "googleSheetsOAuth2Api": { "id": "2", "name": "Google Sheets account lucas" } }, "typeVersion": 4.2 }, { "id": "90194aa3-5960-47bd-9e0e-efee827004c4", "name": "SERPAPI - Scrape Google Maps URL", "type": "n8n-nodes-base.httpRequest", "onError": "continueErrorOutput", "position": [ -920, 500 ], "parameters": { "url": "https://serpapi.com/search.json", "options": {}, "sendQuery": true, "authentication": "predefinedCredentialType", "queryParameters": { "parameters": [ { "name": "engine", "value": "google_maps" }, { "name": "q", "value": "={{$json?.search_parameters?.q || $json.keyword }} " }, { "name": "ll", "value": "={{ $json?.search_parameters?.ll|| $json.geo }}" }, { "name": "type", "value": "search" }, { "name": "start", "value": "={{ $json.start|| 0 }}" } ] }, "nodeCredentialType": "serpApi" }, "credentials": { "serpApi": { "id": "MP9W6wBcEfhc6ofn", "name": "SerpAPI account" } }, "typeVersion": 4.1 }, { "id": "9cfd1e76-2d7c-4618-86d6-e1f3c7729044", "name": "Remove duplicate items", "type": "n8n-nodes-base.itemLists", "position": [ 580, 680 ], "parameters": { "compare": "selectedFields", "options": {}, "operation": "removeDuplicates", "fieldsToCompare": "place_id" }, "typeVersion": 3.1 }, { "id": "e47dfa17-fc84-4694-950d-165302a9075f", "name": "Split out items", "type": "n8n-nodes-base.itemLists", "position": [ 40, 680 ], "parameters": { "options": {}, "fieldToSplitOut": "allData" }, "typeVersion": 3.1 }, { "id": "decc89ee-f836-4ec2-9a1a-0371a8889ef5", "name": "Remove empty values", "type": "n8n-nodes-base.filter", "position": [ 200, 680 ], "parameters": { "conditions": { "string": [ { "value1": "={{ $json[0] }}", "operation": "isNotEmpty" } ] } }, "typeVersion": 1 }, { "id": "bd7ca3a5-2697-4653-abf6-372088d925e6", "name": "Google Sheets - Get searches to scrap", "type": "n8n-nodes-base.googleSheets", "position": [ -1380, 500 ], "parameters": { "options": {}, "filtersUI": { "values": [ { "lookupColumn": "Status" } ] }, "sheetName": { "__rl": true, "mode": "list", "value": "gid=0", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0", "cachedResultName": "Add your search here" }, "documentId": { "__rl": true, "mode": "url", "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0" } }, "credentials": { "googleSheetsOAuth2Api": { "id": "2", "name": "Google Sheets account lucas" } }, "typeVersion": 4.2 }, { "id": "6d0be482-b1ad-4fa0-8d2e-bef9a4414924", "name": "Extract keyword and location from URL", "type": "n8n-nodes-base.set", "position": [ -1160, 500 ], "parameters": { "fields": { "values": [ { "name": "keyword", "stringValue": "={{ $json.URL.match(/\\/search\\/(.*?)\\//)[1] }}" }, { "name": "geo", "stringValue": "={{ $json.URL.match(/(@[^\\/?]+)/)[1]}}" } ] }, "options": {} }, "typeVersion": 3.2 }, { "id": "f6fb8db2-8444-4605-af9d-22ca71c7937d", "name": "Sticky Note1", "type": "n8n-nodes-base.stickyNote", "position": [ -1920, 200 ], "parameters": { "width": 312.2965981499806, "height": 266.8807730722022, "content": "## Adjust frequency to your own needs" }, "typeVersion": 1 }, { "id": "234b5d18-75d7-495b-960f-06192d9e7c61", "name": "Run workflow every hours", "type": "n8n-nodes-base.scheduleTrigger", "position": [ -1800, 300 ], "parameters": { "rule": { "interval": [ { "field": "hours" } ] } }, "typeVersion": 1.1 }, { "id": "ea2e9b89-e52c-4e25-803a-ce33c41c20fc", "name": "Sticky Note2", "type": "n8n-nodes-base.stickyNote", "position": [ -1460, 200 ], "parameters": { "height": 511.2196121145973, "content": "## Copy my template and connect it to n8n\n\nTemplate link: \n https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit?usp=sharing" }, "typeVersion": 1 }, { "id": "de515d8d-641d-4b91-9472-608ad3878e32", "name": "Sticky Note3", "type": "n8n-nodes-base.stickyNote", "position": [ -980, 169.3107006491615 ], "parameters": { "height": 535.9388810024284, "content": "## Add your SERPAPI API Key\n\nStart a free trial at serpapi.com and get your API key in \"Your account\" section" }, "typeVersion": 1 }, { "id": "a5a63861-7ff3-4072-a669-acce938939d8", "name": "Update Status to Success", "type": "n8n-nodes-base.googleSheets", "position": [ 940, 680 ], "parameters": { "columns": { "value": { "URL": "={{ $('Google Sheets - Get searches to scrap').first().json.URL }}", "Status": "✅" }, "schema": [ { "id": "URL", "type": "string", "display": true, "removed": false, "required": false, "displayName": "URL", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "Status", "type": "string", "display": true, "required": false, "displayName": "Status", "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" ] }, "options": {}, "operation": "update", "sheetName": { "__rl": true, "mode": "list", "value": "gid=0", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0", "cachedResultName": "Add your search url here" }, "documentId": { "__rl": true, "mode": "url", "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0" } }, "credentials": { "googleSheetsOAuth2Api": { "id": "2", "name": "Google Sheets account lucas" } }, "executeOnce": true, "typeVersion": 4.2 }, { "id": "2bdc5b63-e3bb-453e-a236-9c83cd12cc03", "name": "Update Status to Error", "type": "n8n-nodes-base.googleSheets", "position": [ -640, 620 ], "parameters": { "columns": { "value": { "URL": "={{ $('Google Sheets - Get searches to scrap').first().json.URL }}", "Status": "❌" }, "schema": [ { "id": "URL", "type": "string", "display": true, "removed": false, "required": false, "displayName": "URL", "defaultMatch": false, "canBeUsedToMatch": true }, { "id": "Status", "type": "string", "display": true, "required": false, "displayName": "Status", "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" ] }, "options": {}, "operation": "update", "sheetName": { "__rl": true, "mode": "list", "value": "gid=0", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0", "cachedResultName": "Add your search url here" }, "documentId": { "__rl": true, "mode": "url", "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0" } }, "credentials": { "googleSheetsOAuth2Api": { "id": "2", "name": "Google Sheets account lucas" } }, "executeOnce": true, "typeVersion": 4.2 }, { "id": "f413f4ef-fd6d-4967-8df7-a4fee4361246", "name": "Sticky Note", "type": "n8n-nodes-base.stickyNote", "position": [ -1920, 640 ], "parameters": { "width": 312.2965981499806, "height": 310.4703136043695, "content": "## Click on Execute Workflow to run the workflow manually" }, "typeVersion": 1 }, { "id": "cbc53e43-f141-434c-a655-feb1f7d3c65b", "name": "Continue IF Loop is complete", "type": "n8n-nodes-base.if", "position": [ -380, 620 ], "parameters": { "conditions": { "number": [ { "value1": "={{ $json.search_parameters.start }}", "operation": "isNotEmpty" } ], "string": [ { "value1": "={{ $json.serpapi_pagination.next }}", "operation": "isNotEmpty" } ] } }, "typeVersion": 1 }, { "id": "229f9652-b703-490e-aa3c-c28b0fe1f2e8", "name": "Sticky Note4", "type": "n8n-nodes-base.stickyNote", "position": [ -2340, 200 ], "parameters": { "width": 357.33341618921213, "height": 532.3420004517685, "content": "## Read Me\n\nThis workflow allows to scrape Google Maps data in an efficient way using SerpAPI. \n\nYou'll get all data from Gmaps at a cheaper cost than Google Maps API.\n\nAdd as input, your Google Maps search URL and you'll get a list of places with many data points such as:\n- phone number\n- website\n- rating\n- reviews\n- address\n\nAnd much more.\n\n\n**Full guide to implement the workflow is here**: \n\nhttps://lempire.notion.site/Scrape-Google-Maps-places-with-n8n-b7f1785c3d474e858b7ee61ad4c21136?pvs=4" }, "typeVersion": 1 } ], "pinData": {}, "connections": { "Split out items": { "main": [ [ { "node": "Remove empty values", "type": "main", "index": 0 } ] ] }, "Remove empty values": { "main": [ [ { "node": "Transform data in the right format", "type": "main", "index": 0 } ] ] }, "Remove duplicate items": { "main": [ [ { "node": "Add rows in Google Sheets", "type": "main", "index": 0 } ] ] }, "Extract next start value": { "main": [ [ { "node": "Continue IF Loop is complete", "type": "main", "index": 0 } ] ] }, "Run workflow every hours": { "main": [ [ { "node": "Google Sheets - Get searches to scrap", "type": "main", "index": 0 } ] ] }, "Add rows in Google Sheets": { "main": [ [ { "node": "Update Status to Success", "type": "main", "index": 0 } ] ] }, "Continue IF Loop is complete": { "main": [ [ { "node": "SERPAPI - Scrape Google Maps URL", "type": "main", "index": 0 } ], [ { "node": "Merge all values from SERPAPI", "type": "main", "index": 0 } ] ] }, "Merge all values from SERPAPI": { "main": [ [ { "node": "Split out items", "type": "main", "index": 0 } ] ] }, "SERPAPI - Scrape Google Maps URL": { "main": [ [ { "node": "Extract next start value", "type": "main", "index": 0 } ], [ { "node": "Update Status to Error", "type": "main", "index": 0 } ] ] }, "When clicking \"Execute Workflow\"": { "main": [ [ { "node": "Google Sheets - Get searches to scrap", "type": "main", "index": 0 } ] ] }, "Transform data in the right format": { "main": [ [ { "node": "Remove duplicate items", "type": "main", "index": 0 } ] ] }, "Extract keyword and location from URL": { "main": [ [ { "node": "SERPAPI - Scrape Google Maps URL", "type": "main", "index": 0 } ] ] }, "Google Sheets - Get searches to scrap": { "main": [ [ { "node": "Extract keyword and location from URL", "type": "main", "index": 0 } ] ] } } }