ローカルのイベントをGoogleカレンダーに自動同期
中級
これはAI分野の自動化ワークフローで、11個のノードを含みます。主にCode, Html, HttpRequest, GoogleCalendar, ScheduleTriggerなどのノードを使用、AI技術を活用したスマート自動化を実現。 n8nを使ってローカルのイベントをGoogleカレンダーに自動同期
前提条件
- •ターゲットAPIの認証情報が必要な場合あり
カテゴリー
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"id": "y1ZOHX6Zq13C68dP",
"meta": {
"instanceId": "60046904b104f0f72b2629a9d88fe9f676be4035769f1f08dad1dd38a76b9480"
},
"name": "AutoSync_Local_Events_to_Google_Calendar",
"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": "## 🧭 **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": "付箋1",
"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": "付箋2",
"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": "付箋9",
"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": "付箋4",
"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": "付箋5",
"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
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
中級 - 人工知能
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
Bright Dataを使って起こるべきイベントをスクレイピング
Bright Dataとn8nによる自動イベント発見
Code
Html
Http Request
+
Code
Html
Http Request
11 ノードYaron Been
人工知能
Bright Dataを活用した競合価格監視
Bright Dataとn8nを使用した自動のな競合価格モニタリング
If
Code
Html
+
If
Code
Html
15 ノードYaron Been
人工知能
Bright Dataを使った自動化フォーラムモニタリング
Bright Dataとn8nを使ったフォーラム監視の自動化
Set
Code
Html
+
Set
Code
Html
17 ノードYaron Been
人工知能
研究論文スパイダーをGoogleスプシへ
Bright Dataとn8nを使った研究論文収集の自動化
Set
Code
Html
+
Set
Code
Html
12 ノードYaron Been
人工知能
CrunchBase投資家データ
投資家インテリジェンスの自動化:CrunchBaseからGoogleシートデータコレクター
Code
Http Request
Google Sheets
+
Code
Http Request
Google Sheets
8 ノードYaron Been
財務
Bright Data を通じた自動フリーランスター gigs スクレイピング
Bright Dataとn8nを使用したフリーランスのフリーランス仕事フォインダーの自動化
Set
Html
Http Request
+
Set
Html
Http Request
11 ノード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で表示 →
このワークフローを共有