HN投稿の更新

上級

これはHR分野の自動化ワークフローで、16個のノードを含みます。主にSet, Code, Limit, Filter, Airtableなどのノードを使用。 Gemini AIを使用してHacker News投稿を抽出・構造化し、Airtableに保存

前提条件
  • Airtable API Key
  • ターゲットAPIの認証情報が必要な場合あり
  • Google Gemini API Key

カテゴリー

ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "id": "ExmRkYWlTAPhA2IQ",
  "meta": {
    "instanceId": "e19d1d1e8279ed4f1e9dcdd2328b7c5082def05206ccc115a1f38a5872651e05",
    "templateCredsSetupCompleted": true
  },
  "name": "HN Jobs update",
  "tags": [],
  "nodes": [
    {
      "id": "2e510877-4fd3-4e46-a1ad-b44187226b78",
      "name": "分割",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        340,
        400
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "hits"
      },
      "typeVersion": 1
    },
    {
      "id": "b5a9c1f3-f167-4646-8f11-97f4be32ff93",
      "name": "構造化出力パーサー",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        2780,
        600
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"company\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Name of the hiring company\"\n },\n \"title\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Job title/role being advertised\"\n },\n \"location\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Work location including remote/hybrid status\"\n },\n \"type\": {\n \"type\": [\n \"string\",\n null\n ],\n \"enum\": [\n \"FULL_TIME\",\n \"PART_TIME\",\n \"CONTRACT\",\n \"INTERNSHIP\",\n \"FREELANCE\",\n null\n ],\n \"description\": \"Employment type (Full-time, Contract, etc)\"\n },\n \"work_location\": {\n \"type\": [\n \"string\",\n null\n ],\n \"enum\": [\n \"REMOTE\",\n \"HYBRID\",\n \"ON_SITE\",\n null\n ],\n \"description\": \"Work arrangement type\"\n },\n \"salary\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Compensation details if provided\"\n },\n \"description\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Main job description text including requirements and team info\"\n },\n \"apply_url\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Direct application/job posting URL\"\n },\n \"company_url\": {\n \"type\": [\n \"string\",\n null\n ],\n \"description\": \"Company website or careers page\"\n }\n }\n}\n"
      },
      "typeVersion": 1.2
    },
    {
      "id": "80012214-5045-4c54-a5e1-cf7b76a611c3",
      "name": "「Who is hiring」投稿を検索",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        140,
        400
      ],
      "parameters": {
        "url": "https://uj5wyc0l7x-dsn.algolia.net/1/indexes/Item_dev_sort_date/query",
        "method": "POST",
        "options": {},
        "jsonBody": "{\n \"query\": \"\\\"Ask HN: Who is hiring\\\"\",\n \"analyticsTags\": [\n \"web\"\n ],\n \"page\": 0,\n \"hitsPerPage\": 30,\n \"minWordSizefor1Typo\": 4,\n \"minWordSizefor2Typos\": 8,\n \"advancedSyntax\": true,\n \"ignorePlurals\": false,\n \"clickAnalytics\": true,\n \"minProximity\": 7,\n \"numericFilters\": [],\n \"tagFilters\": [\n [\n \"story\"\n ],\n []\n ],\n \"typoTolerance\": \"min\",\n \"queryType\": \"prefixNone\",\n \"restrictSearchableAttributes\": [\n \"title\",\n \"comment_text\",\n \"url\",\n \"story_text\",\n \"author\"\n ],\n \"getRankingInfo\": true\n}",
        "sendBody": true,
        "sendQuery": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "x-algolia-agent",
              "value": "Algolia for JavaScript (4.13.1); Browser (lite)"
            },
            {
              "name": "x-algolia-application-id",
              "value": "UJ5WYC0L7X"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "*/*"
            },
            {
              "name": "Accept-Language",
              "value": "en-GB,en-US;q=0.9,en;q=0.8"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "DNT",
              "value": "1"
            },
            {
              "name": "Origin",
              "value": "https://hn.algolia.com"
            },
            {
              "name": "Referer",
              "value": "https://hn.algolia.com/"
            },
            {
              "name": "Sec-Fetch-Dest",
              "value": "empty"
            },
            {
              "name": "Sec-Fetch-Mode",
              "value": "cors"
            },
            {
              "name": "Sec-Fetch-Site",
              "value": "cross-site"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
            },
            {
              "name": "sec-ch-ua",
              "value": "\"Chromium\";v=\"133\", \"Not(A:Brand\";v=\"99\""
            },
            {
              "name": "sec-ch-ua-mobile",
              "value": "?0"
            },
            {
              "name": "sec-ch-ua-platform",
              "value": "\"macOS\""
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "sV79MeBXuKW0vlk4",
          "name": "Header Auth account"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "58a1f06b-0e41-4f73-9a47-5134806e4249",
      "name": "関連データを取得",
      "type": "n8n-nodes-base.set",
      "position": [
        640,
        400
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "73dd2325-faa7-4650-bd78-5fc97cc202de",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "44918eac-4510-440e-9ac0-bf14d2b2f3af",
              "name": "createdAt",
              "type": "string",
              "value": "={{ $json.created_at }}"
            },
            {
              "id": "00eb6f09-2c22-411c-949c-886b2d95b6eb",
              "name": "updatedAt",
              "type": "string",
              "value": "={{ $json.updated_at }}"
            },
            {
              "id": "2b4f9da6-f60e-46e0-ba9d-3242fa955a55",
              "name": "storyId",
              "type": "string",
              "value": "={{ $json.story_id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d69eb7f3-383f-4e67-a0e7-b5930cfc8b26",
      "name": "最新投稿を取得",
      "type": "n8n-nodes-base.filter",
      "position": [
        920,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d7dd7175-2a50-45aa-bd3e-4c248c9193c4",
              "operator": {
                "type": "dateTime",
                "operation": "after"
              },
              "leftValue": "={{ $json.createdAt }}",
              "rightValue": "={{$now.minus({days: 30})}} "
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "737cce8c-2ef0-4421-bccf-d9bdfa308385",
      "name": "子要素(求人)を分割",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1400,
        400
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "kids"
      },
      "typeVersion": 1
    },
    {
      "id": "13e36405-f049-4d3d-a17c-f14b42817ba1",
      "name": "構造化データに変換",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2540,
        400
      ],
      "parameters": {
        "text": "={{ $json.cleaned_text }}",
        "messages": {
          "messageValues": [
            {
              "message": "Extract the JSON data"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.5
    },
    {
      "id": "40d699ab-bf6d-402b-8192-c485a3525d27",
      "name": "テキストを抽出",
      "type": "n8n-nodes-base.set",
      "position": [
        1800,
        400
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "6affa370-56ce-4ad8-8534-8f753fdf07fc",
              "name": "text",
              "type": "string",
              "value": "={{ $json.text }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a20afe14-6457-4aa3-9135-75733c704723",
      "name": "テキストを整理",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        400
      ],
      "parameters": {
        "jsCode": "// In a Function node in n8n\nconst inputData = $input.all();\n\nfunction cleanAllPosts(data) {\n return data.map(item => {\n try {\n // Check if item exists and has the expected structure\n if (!item || typeof item !== 'object') {\n return { cleaned_text: '', error: 'Invalid item structure' };\n }\n\n // Get the text, with multiple fallbacks\n let text = '';\n if (typeof item === 'string') {\n text = item;\n } else if (item.json && item.json.text) {\n text = item.json.text;\n } else if (typeof item.json === 'string') {\n text = item.json;\n } else {\n text = JSON.stringify(item);\n }\n\n // Make sure text is a string\n text = String(text);\n \n // Perform the cleaning operations\n try {\n text = text.replace(/&#x2F;/g, '/');\n text = text.replace(/&#x27;/g, \"'\");\n text = text.replace(/&\\w+;/g, ' ');\n text = text.replace(/<[^>]*>/g, '');\n text = text.replace(/\\|\\s*/g, '| ');\n text = text.replace(/\\s+/g, ' ');\n text = text.replace(/\\s*(https?:\\/\\/[^\\s]+)\\s*/g, '\\n$1\\n');\n text = text.replace(/\\n{3,}/g, '\\n\\n');\n text = text.trim();\n } catch (cleaningError) {\n console.log('Error during text cleaning:', cleaningError);\n // Return original text if cleaning fails\n return { cleaned_text: text, warning: 'Partial cleaning applied' };\n }\n\n return { cleaned_text: text };\n \n } catch (error) {\n console.log('Error processing item:', error);\n return { \n cleaned_text: '', \n error: `Processing error: ${error.message}`,\n original: item\n };\n }\n }).filter(result => result.cleaned_text || result.error); \n}\n\ntry {\n return cleanAllPosts(inputData);\n} catch (error) {\n console.log('Fatal error:', error);\n return [{ \n cleaned_text: '', \n error: `Fatal error: ${error.message}`,\n input: inputData \n }];\n}\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8ba5a5b4-0d03-46f8-90a1-7550913b77dd",
      "name": "テスト用制限(オプション)",
      "type": "n8n-nodes-base.limit",
      "position": [
        2220,
        400
      ],
      "parameters": {
        "maxItems": 5
      },
      "typeVersion": 1
    },
    {
      "id": "d5535a17-79f1-4dc2-941a-ea4dd6a109a8",
      "name": "結果を airtable に書き込み",
      "type": "n8n-nodes-base.airtable",
      "position": [
        3200,
        400
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "app3Gb4cEMflRuqzy",
          "cachedResultUrl": "https://airtable.com/app3Gb4cEMflRuqzy",
          "cachedResultName": "HN Who is hiring?"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tbl4JrmWPcxiUuCiX",
          "cachedResultUrl": "https://airtable.com/app3Gb4cEMflRuqzy/tbl4JrmWPcxiUuCiX",
          "cachedResultName": "Table 1"
        },
        "columns": {
          "value": {
            "Type": "={{ $json.output.type }}",
            "Title": "={{ $json.output.title }}",
            "Salary": "={{ $json.output.salary }}",
            "Company": "={{ $json.output.company }}",
            "Location": "={{ $json.output.location }}",
            "Apply_url": "={{ $json.output.apply_url }}",
            "Description": "={{ $json.output.description }}",
            "company_url": "={{ $json.output.company_url }}",
            "work_location": "={{ $json.output.work_location }}"
          },
          "schema": [
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Company",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Company",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Type",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "work_location",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "work_location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Salary",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Salary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Apply_url",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Apply_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "company_url",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "company_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "id": "H0gK9cFHnootcYwf",
          "name": "Airtable Personal Access Token account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "e51caae1-c8d1-4954-91a5-d0dfde442346",
      "name": "HI API: 個別の求人投稿を取得",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1600,
        400
      ],
      "parameters": {
        "url": "=https://hacker-news.firebaseio.com/v0/item/{{ $json.kids }}.json?print=pretty",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "880d31e0-41fa-434d-a3d0-ac850ede0b59",
      "name": "HN API: メイン投稿を取得",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1200,
        400
      ],
      "parameters": {
        "url": "=https://hacker-news.firebaseio.com/v0/item/{{ $json.storyId }}.json?print=pretty",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "e1bc30b5-b792-4f1e-8d38-ead61178c5fd",
      "name": "コード",
      "type": "n8n-nodes-base.code",
      "position": [
        2900,
        400
      ],
      "parameters": {
        "jsCode": "function convertSalaryRangeToNumber(salaryStr) {\n  if (!salaryStr) return null;\n\n  // Remove $ and spaces, convert to lowercase\n  salaryStr = salaryStr.replace(/\\$/g, '').replace(/\\s/g, '').toLowerCase();\n\n  // Replace 'k' with '000'\n  salaryStr = salaryStr.replace(/k/g, '000');\n\n  // Split by dash, en dash, em dash\n  const parts = salaryStr.split(/[-–—]/);\n\n  // Extract numbers\n  const numbers = parts.map(part => {\n    // Remove non-digit/non-dot characters\n    const cleaned = part.replace(/[^\\d.]/g, '');\n    return cleaned ? parseFloat(cleaned) : NaN;\n  }).filter(num => !isNaN(num));\n\n  if (numbers.length === 0) return null;\n  if (numbers.length === 1) return numbers[0];\n  if (numbers.length === 2) return (numbers[0] + numbers[1]) / 2;\n\n  // fallback if more than 2 numbers (rare)\n  return numbers[0];\n}\n\n// Example usage inside n8n Function node\n// Assume input data is in items, and salary is in item.json.salary\nfor (let item of items) {\n  const salaryStr = item.json.salary;\n  item.json.salary_numeric = convertSalaryRangeToNumber(salaryStr);\n}\n\nreturn items;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "294d6c73-8946-4ee7-8d60-11b72ecb3964",
      "name": "Google Gemini チャットモデル",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        2600,
        620
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-2.0-flash"
      },
      "credentials": {
        "googlePalmApi": {
          "id": "PyKkDHOogdm7OBzV",
          "name": "Google Gemini(PaLM) Api account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6a6c4536-a57a-4e58-a76f-81eef755fa19",
      "name": "スケジュールトリガー",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -20,
        400
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 2
            }
          ]
        }
      },
      "typeVersion": 1.2
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e5356e09-7a30-467a-a848-507087afb818",
  "connections": {
    "e1bc30b5-b792-4f1e-8d38-ead61178c5fd": {
      "main": [
        [
          {
            "node": "d5535a17-79f1-4dc2-941a-ea4dd6a109a8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2e510877-4fd3-4e46-a1ad-b44187226b78": {
      "main": [
        [
          {
            "node": "58a1f06b-0e41-4f73-9a47-5134806e4249",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a20afe14-6457-4aa3-9135-75733c704723": {
      "main": [
        [
          {
            "node": "8ba5a5b4-0d03-46f8-90a1-7550913b77dd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "40d699ab-bf6d-402b-8192-c485a3525d27": {
      "main": [
        [
          {
            "node": "a20afe14-6457-4aa3-9135-75733c704723",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d69eb7f3-383f-4e67-a0e7-b5930cfc8b26": {
      "main": [
        [
          {
            "node": "880d31e0-41fa-434d-a3d0-ac850ede0b59",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6a6c4536-a57a-4e58-a76f-81eef755fa19": {
      "main": [
        [
          {
            "node": "80012214-5045-4c54-a5e1-cf7b76a611c3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "58a1f06b-0e41-4f73-9a47-5134806e4249": {
      "main": [
        [
          {
            "node": "d69eb7f3-383f-4e67-a0e7-b5930cfc8b26",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "880d31e0-41fa-434d-a3d0-ac850ede0b59": {
      "main": [
        [
          {
            "node": "737cce8c-2ef0-4421-bccf-d9bdfa308385",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "294d6c73-8946-4ee7-8d60-11b72ecb3964": {
      "ai_languageModel": [
        [
          {
            "node": "13e36405-f049-4d3d-a17c-f14b42817ba1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "b5a9c1f3-f167-4646-8f11-97f4be32ff93": {
      "ai_outputParser": [
        [
          {
            "node": "13e36405-f049-4d3d-a17c-f14b42817ba1",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "737cce8c-2ef0-4421-bccf-d9bdfa308385": {
      "main": [
        [
          {
            "node": "e51caae1-c8d1-4954-91a5-d0dfde442346",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "13e36405-f049-4d3d-a17c-f14b42817ba1": {
      "main": [
        [
          {
            "node": "e1bc30b5-b792-4f1e-8d38-ead61178c5fd",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8ba5a5b4-0d03-46f8-90a1-7550913b77dd": {
      "main": [
        [
          {
            "node": "13e36405-f049-4d3d-a17c-f14b42817ba1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "80012214-5045-4c54-a5e1-cf7b76a611c3": {
      "main": [
        [
          {
            "node": "2e510877-4fd3-4e46-a1ad-b44187226b78",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e51caae1-c8d1-4954-91a5-d0dfde442346": {
      "main": [
        [
          {
            "node": "40d699ab-bf6d-402b-8192-c485a3525d27",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
よくある質問

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

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

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

上級 - 人事

有料ですか?

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

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

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

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34