8
n8n 中文网amn8n.com

发票 OCR → 自动追加到表格(内部)

中级

这是一个Invoice Processing, AI Summarization领域的自动化工作流,包含 14 个节点。主要使用 Code, GoogleDrive, HttpRequest, GoogleSheets, ScheduleTrigger 等节点。 通过 OCR.Space、GPT 和 Google Sheets 实现发票数据提取的自动化

前置要求
  • Google Drive API 凭证
  • 可能需要目标 API 的认证凭证
  • Google Sheets API 凭证
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "<your_workflow_id>",
  "meta": {
    "instanceId": "<your_instance_id>",
    "templateCredsSetupCompleted": true
  },
  "name": "发票 OCR → 自动追加到表格(内部)",
  "tags": [],
  "nodes": [
    {
      "id": "c79d74f7-f2d7-4e35-891d-c428fcfc5dcc",
      "name": "计划触发器(每周扫描)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        368,
        -416
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 20
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "acb76a11-4ee8-468c-8023-a4f886f428c2",
      "name": "获取父文件夹",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        640,
        -416
      ],
      "parameters": {
        "filter": {},
        "options": {},
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "=支払い請求書自動計算用フォルダ"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "<your_google_drive_credential_id>",
          "name": "<your_google_drive_credential_name>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "499da8a9-f455-4e8e-bf38-f3b5334ec442",
      "name": "获取月度子文件夹",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        848,
        -416
      ],
      "parameters": {
        "filter": {},
        "options": {},
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "='{{$json[\"id\"]}}' in parents and mimeType='application/vnd.google-apps.folder' and name contains '{{$now.setZone(\"Asia/Tokyo\").format(\"yyyy年MM月\")}}分'",
        "searchMethod": "query"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "<your_google_drive_credential_id>",
          "name": "<your_google_drive_credential_name>"
        }
      },
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "6c95fb12-8dcd-4df3-a611-d099c3298274",
      "name": "列出文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1040,
        -416
      ],
      "parameters": {
        "filter": {},
        "options": {
          "fields": [
            "webViewLink",
            "id",
            "mimeType",
            "name"
          ]
        },
        "resource": "fileFolder",
        "queryString": "='{{$json[\"id\"]}}' in parents and (mimeType='application/pdf' or mimeType contains 'image/')\n",
        "searchMethod": "query"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "<your_google_drive_credential_id>",
          "name": "<your_google_drive_credential_name>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "93009ba2-3af8-4ba0-9044-cf5fa15e0965",
      "name": "下载文件(来自 Drive 的二进制文件)",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1232,
        -416
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{$json[\"id\"]}}"
        },
        "options": {
          "binaryPropertyName": "data"
        },
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "<your_google_drive_credential_id>",
          "name": "<your_google_drive_credential_name>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "b0761836-e013-4728-bb12-dc2e760cfa7f",
      "name": "OCR(OCR.Space 解析)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1440,
        -416
      ],
      "parameters": {
        "url": "https://api.ocr.space/parse/image",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "language",
              "value": "jpn"
            },
            {
              "name": "isOverlayRequired",
              "value": "false"
            },
            {
              "name": "OCREngine",
              "value": "2"
            },
            {
              "name": "isTable",
              "value": "true"
            },
            {
              "name": "scale",
              "value": "true"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "=apikey",
              "value": "=<your_ocr_api_key>"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "2f843a4c-82dd-45ae-8be8-b438d93fb8ea",
      "name": "清理 OCR 文本(去除噪音)",
      "type": "n8n-nodes-base.code",
      "position": [
        1680,
        -416
      ],
      "parameters": {
        "jsCode": "// 各アイテムごとにOCR結果を整形して返す\nreturn items.map(item => {\n  const parsed = item.json[\"ParsedResults\"]?.[0];\n  let text = parsed?.ParsedText || \"\";\n\n  // ノイズ除去・整形\n  text = text\n    .replace(/\\r/g, \"\\n\")             // 改行コード統一\n    .replace(/\\n{2,}/g, \"\\n\")         // 余分な改行を削除\n    .replace(/[^\\S\\n]+/g, \" \")        // 不要な空白を削除\n    .replace(/ /g, \" \")              // 全角スペースを半角に\n    .replace(/[“”]/g, '\"')            // 変な引用符を統一\n    .replace(/[‘’]/g, \"'\")\n    .replace(/[円¥]/g, \"円\");         // 円記号を統一\n\n  return {\n    json: {\n      text: text.trim()\n    }\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "888bed82-b755-4416-948c-4db664c1b371",
      "name": "AI 提取(生成结构化 JSON)",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        304,
        -32
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are an AI assistant that analyzes Japanese invoice OCR text and accurately extracts the information required for accounting.\n\n# Input\nBelow is invoice text extracted by OCR.\nIt contains noise, line breaks, and layout issues.\nCarefully reconstruct the content and convert it into structured data as accurately as possible.\n\n---\n{{ $json.text }}\n---\n\n# Output Format\nReturn ONLY the following JSON. Do not include any explanations, chatty text, or code fences.\n\n{\n  \"invoice_date\": \"YYYY-MM-DD\",\n  \"due_date\": \"YYYY-MM-DD\",\n  \"client_name\": \"e.g., Your Client Company\",\n  \"subtotal\": 0,\n  \"tax\": 0,\n  \"total\": 0,\n  \"bank_info\": {\n    \"bank_name\": \"\",\n    \"branch\": \"\",\n    \"account_type\": \"ordinary|checking|savings|unknown\",\n    \"account_number\": \"\",\n    \"account_name\": \"\"\n  },\n  \"items\": [\n    {\n      \"description\": \"\",\n      \"quantity\": 0,\n      \"unit_price\": 0,\n      \"amount\": 0\n    }\n  ],\n  \"notes\": \"\"\n}\n\n# Extraction Rules\n- Identify dates from labels like \"請求日/発行日\" (invoice/issue date) and \"支払期限/お支払い期日\" (due date), then normalize to YYYY-MM-DD.\n- Normalize amounts (subtotal, tax, total) by removing commas, currency symbols, and the \"円\" unit, and output integers. Ensure consistency for tax-inclusive/exclusive totals when needed.\n- For bank info, prioritize extracting the set: bank name, branch, account type, account number, and account holder. Ignore values that cannot be confidently linked.\n- If there are multiple line items, return multiple objects in the items array. When quantity/unit_price/amount are unknown, use 0 (not \"unknown\").\n- Prefer client names that end with honorifics like \"御中\" or \"様\" when present.\n- For unknown fields, use \"unknown\". Always include all keys.\n- Return valid JSON only. No extra characters or leading/trailing newlines.\n"
            },
            {
              "content": "=={{$json.text}}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "id": "<your_openai_credential_id>",
          "name": "<your_openai_credential_name>"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "2805e6a9-0304-4842-b5b6-eb4996b08dec",
      "name": "解析 AI 输出为 JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        656,
        -32
      ],
      "parameters": {
        "jsCode": "// 各アイテム(PDFごと)を独立して処理\nreturn items.map(item => {\n  const content = item.json.message?.content;\n\n  // JSON構造を安全にパース\n  let parsed = {};\n  try {\n    parsed = typeof content === \"string\" ? JSON.parse(content) : content;\n  } catch (e) {\n    parsed = { error: \"Invalid JSON\", raw: content };\n  }\n\n  // 各アイテムとして出力(個別にスプレッドシートに渡る)\n  return { json: parsed };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "0d2e5f79-3c09-4352-af43-d7d895669991",
      "name": "追加到 Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        848,
        -32
      ],
      "parameters": {
        "columns": {
          "value": {
            "合計": "={{ $json.total }}",
            "小計": "={{ $json.subtotal }}",
            "消費税": "={{ $json.tax }}",
            "請求日": "={{ $json.invoice_date }}",
            "銀行名": "={{ $json.bank_info.bank_name }} {{ $json.bank_info.branch }} {{ $json.bank_info.account_type }}",
            "PDFリンク": "={{ $('List Files').item.json.webViewLink }}",
            "取引先名": "={{ $json.client_name }}",
            "口座名義": "={{ $json.bank_info.account_name }}",
            "口座番号": "={{ $json.bank_info.account_number }}",
            "支払期限": "={{ $json.due_date }}"
          },
          "schema": [
            {
              "id": "請求日",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "請求日",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "支払期限",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "支払期限",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "取引先名",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "取引先名",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "小計",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "小計",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "消費税",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "消費税",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "合計",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "合計",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "銀行名",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "銀行名",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "口座番号",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "口座番号",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "口座名義",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "口座名義",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "PDFリンク",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "PDFリンク",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ ($item(0).$node[\"Get Monthly Subfolder\"].json.name || \"請求書台帳\").trim() }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ \"<your_google_sheet_id>\" }}\n"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "<your_google_sheets_credential_id>",
          "name": "<your_google_sheets_credential_name>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "07e4ec6a-0526-44e6-a7ef-95b2d3e7cc22",
      "name": "计划触发器(循环执行)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        -640
      ],
      "parameters": {
        "color": 3,
        "width": 336,
        "height": 384,
        "content": "## 计划触发器(循环执行)"
      },
      "typeVersion": 1
    },
    {
      "id": "7175d70d-bd7a-46c5-96c1-71691e215da5",
      "name": "Google Drive 文件夹发现",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        624,
        -640
      ],
      "parameters": {
        "color": 2,
        "width": 752,
        "height": 384,
        "content": "## Google Drive 文件夹发现"
      },
      "typeVersion": 1
    },
    {
      "id": "7c0a7024-98f7-42f9-8937-4aced9dcbf7a",
      "name": "AI 提取与表格追加",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        -224
      ],
      "parameters": {
        "color": 4,
        "width": 848,
        "height": 384,
        "content": "## AI 结构化提取与 Google Sheets 追加"
      },
      "typeVersion": 1
    },
    {
      "id": "bb521714-8b47-4a03-abc0-9e18a471021c",
      "name": "OCR 处理(PDF → 文本清理)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1392,
        -640
      ],
      "parameters": {
        "color": 6,
        "width": 400,
        "height": 384,
        "content": "## OCR 处理(PDF → 文本清理)"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "<your_version_id>",
  "connections": {
    "List Files": {
      "main": [
        [
          {
            "node": "Download File (Binary from Drive)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Parent Folder": {
      "main": [
        [
          {
            "node": "Get Monthly Subfolder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Monthly Subfolder": {
      "main": [
        [
          {
            "node": "List Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OCR (OCR.Space Parsing)": {
      "main": [
        [
          {
            "node": "Clean OCR Text (Noise Removal)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Output to JSON": {
      "main": [
        [
          {
            "node": "Append to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean OCR Text (Noise Removal)": {
      "main": [
        [
          {
            "node": "AI Extraction (Generate Structured JSON)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger (Weekly Scan)": {
      "main": [
        [
          {
            "node": "Get Parent Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download File (Binary from Drive)": {
      "main": [
        [
          {
            "node": "OCR (OCR.Space Parsing)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Extraction (Generate Structured JSON)": {
      "main": [
        [
          {
            "node": "Parse AI Output to JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

中级 - 发票处理, AI 摘要总结

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
中级
节点数量14
分类2
节点类型7
难度说明

适合有一定经验的用户,包含 6-15 个节点的中等复杂度工作流

外部链接
在 n8n.io 查看

分享此工作流