Automatische Synchronisation lokaler Ereignisse mit Google Kalender
Dies ist ein AI-Bereich Automatisierungsworkflow mit 11 Nodes. Hauptsächlich werden Code, Html, HttpRequest, GoogleCalendar, ScheduleTrigger und andere Nodes verwendet, kombiniert mit KI-Technologie für intelligente Automatisierung. Automatische Synchronisation lokaler Ereignisse mit Google Kalender mit n8n
- •Möglicherweise sind Ziel-API-Anmeldedaten erforderlich
Verwendete Nodes (11)
Kategorie
{
"id": "y1ZOHX6Zq13C68dP",
"meta": {
"instanceId": "60046904b104f0f72b2629a9d88fe9f676be4035769f1f08dad1dd38a76b9480"
},
"name": "AutoSync_Local_Events_to_Google_Calendar",
"tags": [],
"nodes": [
{
"id": "433e4192-599f-4f3d-a251-651b81db4960",
"name": "Täglicher Ereignis-Sync-Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2740,
220
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "94f20c26-9a90-43ba-8ab1-b1107c17345c",
"name": "Ereignisseite abrufen (Bright Data)",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2520,
220
],
"parameters": {
"url": "https://api.brightdata.com/request",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "zone",
"value": "n8n_unblocker"
},
{
"name": "url",
"value": "https://www.nypl.org/events/calendar"
},
{
"name": "country",
"value": "us"
},
{
"name": "format",
"value": "raw"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer API_KEY"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "e55c8584-f673-4201-bda7-42cdbadf49bf",
"name": "Ereignisdaten extrahieren (HTML Parser)",
"type": "n8n-nodes-base.html",
"position": [
-2220,
220
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"extractionValues": {
"values": [
{
"key": "Title",
"cssSelector": ".event-title",
"returnArray": true
},
{
"key": "Location",
"cssSelector": ".event-location",
"returnArray": true
},
{
"key": "Audience",
"cssSelector": ".event-audience",
"returnArray": true
},
{
"key": "Time",
"cssSelector": ".event-time",
"returnArray": true
}
]
}
},
"typeVersion": 1.2
},
{
"id": "48196549-0378-4cd9-8e1d-f289c4b50180",
"name": "Ereignisdaten bereinigen & formatieren",
"type": "n8n-nodes-base.code",
"position": [
-2000,
220
],
"parameters": {
"jsCode": "const data = items[0].json;\n\n// Extract arrays\nconst titles = data.Title || [];\nconst locations = data.Location || [];\nconst audiences = data.Audience || [];\nconst rawTimes = data.Time || [];\n\n// Step 1: Remove invalid \"time\" placeholders\nconst invalidTimeLabels = [\"Date/Time\", \"Title/Description\", \"Location\", \"Audience\"];\nconst times = rawTimes.filter(time => !invalidTimeLabels.includes(time.trim()));\n\n// Step 2: Safely calculate number of valid events\nconst eventCount = Math.min(titles.length, locations.length, audiences.length, times.length);\n\n// Helper: Convert \"Today @ 10 AM\" → ISO string with timezone\nfunction parseTimeToISO(rawTime) {\n const match = rawTime.match(/@ ([0-9]{1,2})(?::([0-9]{2}))?\\s?(AM|PM)/i);\n const now = new Date();\n\n if (!match) return null;\n\n let hour = parseInt(match[1]);\n const minute = match[2] ? parseInt(match[2]) : 0;\n const meridian = match[3].toUpperCase();\n\n if (meridian === \"PM\" && hour !== 12) hour += 12;\n if (meridian === \"AM\" && hour === 12) hour = 0;\n\n const start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute);\n const end = new Date(start.getTime() + 60 * 60 * 1000); // 1-hour event\n\n const offsetMinutes = start.getTimezoneOffset();\n const offsetHours = Math.floor(Math.abs(offsetMinutes) / 60);\n const offsetMins = Math.abs(offsetMinutes) % 60;\n const offsetSign = offsetMinutes > 0 ? \"-\" : \"+\";\n const offset = `${offsetSign}${String(offsetHours).padStart(2, \"0\")}:${String(offsetMins).padStart(2, \"0\")}`;\n\n const toISOStringWithOffset = (d) => {\n const pad = (n) => n.toString().padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:00${offset}`;\n };\n\n return {\n start: toISOStringWithOffset(start),\n end: toISOStringWithOffset(end),\n };\n}\n\n// Step 3: Build cleaned and enriched event objects\nconst results = [];\n\nfor (let i = 0; i < eventCount; i++) {\n const titleText = titles[i];\n const timeText = times[i]?.trim();\n const parsedTime = parseTimeToISO(timeText);\n\n results.push({\n json: {\n title: titleText.split('\\n')[0]?.trim(),\n description: titleText.trim(),\n location: locations[i]?.trim(),\n audience: audiences[i]?.trim(),\n time: timeText,\n start: { dateTime: parsedTime?.start || null },\n end: { dateTime: parsedTime?.end || null },\n sourceUrl: \"https://www.nypl.org\" + (titleText.match(/\\[([^\\]]+)\\]/)?.[1] || '')\n }\n });\n}\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "945e912a-609a-42e0-82a4-c3d36623a767",
"name": "Google Kalenderereignisse erstellen",
"type": "n8n-nodes-base.googleCalendar",
"position": [
-1700,
220
],
"parameters": {
"end": "={{ $json.end.dateTime }}",
"start": "={{ $json.start.dateTime }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "f14d18c7802fe01f77d5200ada9658c96cbc69b3cb9ff7b2914dc63bf6f263e3@group.calendar.google.com",
"cachedResultName": "Community Events"
},
"additionalFields": {
"attendees": [],
"description": "=Title: {{ $json.title }}\nDescription: {{ $json.description }}\nLocation: {{ $json.location }}\nAudience: {{ $json.audience }}\nTime: {{ $json.time }}"
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"id": "ZiXaTJAXCcyzY5iy",
"name": "Google Calendar account"
}
},
"typeVersion": 1.3
},
{
"id": "6c5825a7-6a1e-485c-820b-ed4188c6b718",
"name": "Notizzettel",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2800,
-540
],
"parameters": {
"color": 5,
"width": 440,
"height": 980,
"content": "## 🧭 **Section 1: Event Data Fetcher**\n\n### 🔁 `🕒 Daily Event Sync Trigger`\n\n> **Node:** *Schedule Trigger*\n> ⏰ This node sets **when** your automation runs. For example, you might want it to run every morning at 8:00 AM to check for new community events.\n\n🔍 Why it matters:\n\n> This ensures your public calendar is always up to date without manual work.\n\n---\n\n### 🌐 `🌐 Fetch Event Page (Bright Data)`\n\n> **Node:** *HTTP Request using Bright Data Web Unlocker*\n> 🛡 This node sends a request to a **local government or library event page** using Bright Data’s **Web Unlocker proxy**, which helps bypass blocks or bot detection.\n\n🔧 What’s special here:\n\n* It uses your **Bright Data proxy zone**\n* It targets a public events URL (e.g., a `.gov` or `.org`)\n* Makes sure you get the raw HTML page — even if the site tries to hide it\n\n✅ Benefit:\n\n> This lets you scrape data reliably from websites that are normally hard to reach for bots.\n\n---\n\n"
},
"typeVersion": 1
},
{
"id": "aa5624b4-6c2e-4d70-a05b-4e038ee82dfb",
"name": "Notizzettel1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2300,
-660
],
"parameters": {
"color": 3,
"width": 440,
"height": 1100,
"content": "## 🧩 **Section 2: Smart Event Extractor**\n\n### 🧩 `🧩 Extract Event Data (HTML Parser)`\n\n> **Node:** *HTML*\n> 📄 This node parses the raw HTML response from the website and extracts useful information like:\n\n* 🏷 Event Titles\n* 📍 Locations\n* 👥 Target Audience\n* ⏰ Raw Times\n\nIt uses selectors (like CSS) to grab content from specific parts of the page.\n\n🎯 Goal:\n\n> Transform messy website code into **structured data** you can actually use.\n\n---\n\n### 🧠 `🧠 Clean & Format Event Data`\n\n> **Node:** *Code*\n> 🧼 This is the brain of your workflow. It takes the raw extracted data and:\n\n* Matches titles with their correct time/location\n* Skips garbage data like `\"Date/Time\"` headers\n* 🧮 Converts time to proper ISO format (like `2025-06-21T11:00:00-07:00`) for Google Calendar\n\n🚀 Bonus:\n\n> This ensures only **valid**, well-structured events are passed forward — nothing broken, empty, or misaligned.\n\n---\n\n"
},
"typeVersion": 1
},
{
"id": "b19c44ba-1abb-4d0b-a854-1d844163ffdf",
"name": "Notizzettel2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1800,
-240
],
"parameters": {
"color": 6,
"width": 320,
"height": 680,
"content": "## 📅 **Section 3: Auto Calendar Creator**\n\n### 📅 `📅 Create Google Calendar Events`\n\n> **Node:** *Google Calendar*\n> 🧙♂️ This node automatically **creates public calendar events** using the cleaned-up data.\n\nHere’s what it sets:\n\n* **Summary:** Event title\n* **Description:** Full details (e.g., location, what it’s about)\n* **Start/End Time:** In the correct Google Calendar format\n\n"
},
"typeVersion": 1
},
{
"id": "85488a2c-a51a-4561-8f7d-44901a3a04a1",
"name": "Notizzettel9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4600,
-500
],
"parameters": {
"color": 4,
"width": 1300,
"height": 320,
"content": "=======================================\n WORKFLOW ASSISTANCE\n=======================================\nFor any questions or support, please contact:\n Yaron@nofluff.online\n\nExplore more tips and tutorials here:\n - YouTube: https://www.youtube.com/@YaronBeen/videos\n - LinkedIn: https://www.linkedin.com/in/yaronbeen/\n=======================================\n"
},
"typeVersion": 1
},
{
"id": "2395bf91-efa9-4149-b411-38d18924c5c5",
"name": "Notizzettel4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4600,
-160
],
"parameters": {
"color": 4,
"width": 1289,
"height": 2298,
"content": "# **📅 AutoSync Local Events to Google Calendar**\n\n### *A No-Code Automation to Scrape, Clean, and Publish Community Events*\n\n---\n## 🧭 **Section 1: Event Data Fetcher**\n\n### 🔁 `🕒 Daily Event Sync Trigger`\n\n> **Node:** *Schedule Trigger*\n> ⏰ This node sets **when** your automation runs. For example, you might want it to run every morning at 8:00 AM to check for new community events.\n\n🔍 Why it matters:\n\n> This ensures your public calendar is always up to date without manual work.\n\n---\n\n### 🌐 `🌐 Fetch Event Page (Bright Data)`\n\n> **Node:** *HTTP Request using Bright Data Web Unlocker*\n> 🛡 This node sends a request to a **local government or library event page** using Bright Data’s **Web Unlocker proxy**, which helps bypass blocks or bot detection.\n\n🔧 What’s special here:\n\n* It uses your **Bright Data proxy zone**\n* It targets a public events URL (e.g., a `.gov` or `.org`)\n* Makes sure you get the raw HTML page — even if the site tries to hide it\n\n✅ Benefit:\n\n> This lets you scrape data reliably from websites that are normally hard to reach for bots.\n\n---\n\n## 🧩 **Section 2: Smart Event Extractor**\n\n### 🧩 `🧩 Extract Event Data (HTML Parser)`\n\n> **Node:** *HTML*\n> 📄 This node parses the raw HTML response from the website and extracts useful information like:\n\n* 🏷 Event Titles\n* 📍 Locations\n* 👥 Target Audience\n* ⏰ Raw Times\n\nIt uses selectors (like CSS) to grab content from specific parts of the page.\n\n🎯 Goal:\n\n> Transform messy website code into **structured data** you can actually use.\n\n---\n\n### 🧠 `🧠 Clean & Format Event Data`\n\n> **Node:** *Code*\n> 🧼 This is the brain of your workflow. It takes the raw extracted data and:\n\n* Matches titles with their correct time/location\n* Skips garbage data like `\"Date/Time\"` headers\n* 🧮 Converts time to proper ISO format (like `2025-06-21T11:00:00-07:00`) for Google Calendar\n\n🚀 Bonus:\n\n> This ensures only **valid**, well-structured events are passed forward — nothing broken, empty, or misaligned.\n\n---\n\n## 📅 **Section 3: Auto Calendar Creator**\n\n### 📅 `📅 Create Google Calendar Events`\n\n> **Node:** *Google Calendar*\n> 🧙♂️ This node automatically **creates public calendar events** using the cleaned-up data.\n\nHere’s what it sets:\n\n* **Summary:** Event title\n* **Description:** Full details (e.g., location, what it’s about)\n* **Start/End Time:** In the correct Google Calendar format\n\n🫶 Why this matters:\n\n> Now your scraped community events are published straight to a **Google Calendar** — which you can embed on a website, share with citizens, or subscribe to.\n\n---\n\n## 🧩 Summary: Why This Workflow Rocks\n\n| 🔧 Step | 📌 What It Does | 🎁 Benefit to You |\n| -------------------- | ----------------------------------------------------- | -------------------------------------------- |\n| **Schedule Trigger** | Starts the automation daily | Keeps your calendar always fresh |\n| **HTTP Request** | Grabs raw event info from a gov/library site | Reliable access to public event data |\n| **HTML Parser** | Pulls structured info from messy HTML | Turns code into useful content |\n| **Code Node** | Fixes formatting, converts time, aligns titles & more | Clean data ready for use |\n| **Calendar Node** | Publishes events into your Google Calendar | Fully automated public calendar — no effort! |\n\n---\n\n"
},
"typeVersion": 1
},
{
"id": "f4286f93-9457-4042-9b4d-bbb8304eaac1",
"name": "Notizzettel5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1420,
-240
],
"parameters": {
"color": 7,
"width": 380,
"height": 240,
"content": "## I’ll receive a tiny commission if you join Bright Data through this link—thanks for fueling more free content!\n\n### https://get.brightdata.com/1tndi4600b25"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "69086b47-9272-4887-8844-db532999a0ba",
"connections": {
"433e4192-599f-4f3d-a251-651b81db4960": {
"main": [
[
{
"node": "94f20c26-9a90-43ba-8ab1-b1107c17345c",
"type": "main",
"index": 0
}
]
]
},
"48196549-0378-4cd9-8e1d-f289c4b50180": {
"main": [
[
{
"node": "945e912a-609a-42e0-82a4-c3d36623a767",
"type": "main",
"index": 0
}
]
]
},
"94f20c26-9a90-43ba-8ab1-b1107c17345c": {
"main": [
[
{
"node": "e55c8584-f673-4201-bda7-42cdbadf49bf",
"type": "main",
"index": 0
}
]
]
},
"e55c8584-f673-4201-bda7-42cdbadf49bf": {
"main": [
[
{
"node": "48196549-0378-4cd9-8e1d-f289c4b50180",
"type": "main",
"index": 0
}
]
]
}
}
}Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Fortgeschritten - Künstliche Intelligenz
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Yaron Been
@yaron-nofluffBuilding AI Agents and Automations | Growth Marketer | Entrepreneur | Book Author & Podcast Host If you need any help with Automations, feel free to reach out via linkedin: https://www.linkedin.com/in/yaronbeen/ And check out my Youtube channel: https://www.youtube.com/@YaronBeen/videos
Diesen Workflow teilen