自动同步本地事件到Google日历
中级
这是一个AI领域的自动化工作流,包含 11 个节点。主要使用 Code, Html, HttpRequest, GoogleCalendar, ScheduleTrigger 等节点,结合人工智能技术实现智能自动化。 使用n8n自动同步本地事件到Google日历
前置要求
- •可能需要目标 API 的认证凭证
分类
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "y1ZOHX6Zq13C68dP",
"meta": {
"instanceId": "60046904b104f0f72b2629a9d88fe9f676be4035769f1f08dad1dd38a76b9480"
},
"name": "自动同步本地事件到Google日历",
"tags": [],
"nodes": [
{
"id": "433e4192-599f-4f3d-a251-651b81db4960",
"name": "每日事件同步触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2740,
220
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "94f20c26-9a90-43ba-8ab1-b1107c17345c",
"name": "获取事件页面(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": "提取事件数据(HTML解析器)",
"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": "清理和格式化事件数据",
"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日历事件",
"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": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2800,
-540
],
"parameters": {
"color": 5,
"width": 440,
"height": 980,
"content": "## 🧭 **第一部分:事件数据获取器**"
},
"typeVersion": 1
},
{
"id": "aa5624b4-6c2e-4d70-a05b-4e038ee82dfb",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2300,
-660
],
"parameters": {
"color": 3,
"width": 440,
"height": 1100,
"content": "## 🧩 **第二部分:智能事件提取器**"
},
"typeVersion": 1
},
{
"id": "b19c44ba-1abb-4d0b-a854-1d844163ffdf",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1800,
-240
],
"parameters": {
"color": 6,
"width": 320,
"height": 680,
"content": "## 📅 **第三部分:自动日历创建器**"
},
"typeVersion": 1
},
{
"id": "85488a2c-a51a-4561-8f7d-44901a3a04a1",
"name": "便签9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4600,
-500
],
"parameters": {
"color": 4,
"width": 1300,
"height": 320,
"content": "======================================="
},
"typeVersion": 1
},
{
"id": "2395bf91-efa9-4149-b411-38d18924c5c5",
"name": "便签4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4600,
-160
],
"parameters": {
"color": 4,
"width": 1289,
"height": 2298,
"content": "# **📅 自动同步本地事件到Google日历**"
},
"typeVersion": 1
},
{
"id": "f4286f93-9457-4042-9b4d-bbb8304eaac1",
"name": "便签5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1420,
-240
],
"parameters": {
"color": 7,
"width": 380,
"height": 240,
"content": "## 如果您通过此链接加入Bright Data,我将获得少量佣金——感谢您支持更多免费内容!"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "69086b47-9272-4887-8844-db532999a0ba",
"connections": {
"Daily Event Sync Trigger": {
"main": [
[
{
"node": "Fetch Event Page (Bright Data)",
"type": "main",
"index": 0
}
]
]
},
"Clean & Format Event Data": {
"main": [
[
{
"node": "Create Google Calendar Events",
"type": "main",
"index": 0
}
]
]
},
"Fetch Event Page (Bright Data)": {
"main": [
[
{
"node": "Extract Event Data (HTML Parser)",
"type": "main",
"index": 0
}
]
]
},
"Extract Event Data (HTML Parser)": {
"main": [
[
{
"node": "Clean & Format Event Data",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - 人工智能
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用 Bright Data 抓取即将发生的事件
使用 Bright Data 和 n8n 的自动化事件发现
Code
Html
Http Request
+3
11 节点Yaron Been
人工智能
通过Bright Data进行竞争对手价格监控
使用Bright Data和n8n的自动竞争对手价格监控
If
Code
Html
+6
15 节点Yaron Been
人工智能
自动化论坛监控_via_Bright_data
使用Bright Data和n8n的论坛监控自动化
Set
Code
Html
+6
17 节点Yaron Been
人工智能
通过 Bright Data 监控运动鞋价格下降
基于 Bright Data 和 n8n 的运动鞋降价提醒
If
Code
Html
+5
13 节点Yaron Been
人工智能
研究论文爬虫到Google Sheets
使用Bright Data和n8n自动化研究论文收集
Set
Code
Html
+4
12 节点Yaron Been
人工智能
CrunchBase 投资者数据
自动化投资者情报:CrunchBase到Google Sheets数据采集器
Code
Http Request
Google Sheets
+2
8 节点Yaron Been
财务
工作流信息
难度等级
中级
节点数量11
分类1
节点类型6
作者
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
外部链接
在 n8n.io 查看 →
分享此工作流