n8n: распознавание чеков и счетов (PDF/фото) и занесение данных в таблицу - Блог Папы Карло

Опубликовано: 5 месяцев назад
Просмотров: 131

Привет. Я бы тут делал так: n8n принимает PDF или фотку чека, гонит файл в OCR, вытаскивает продавца, дату, номер документа, валюту и сумму, потом нормализует поля и закидывает всё в Google Sheets. На практике это реально экономит часы ручной рутины, особенно когда чеки сыпятся из почты, мессенджера или общей папки.

В этой статье покажу рабочую схему, на каких нодах её собирать, как развести PDF и фото по разным веткам, где чаще всего всплывают косяки с OCR и что сделать, чтобы таблица не пухла от дублей. Плюс дам пример структуры полей, кусок кода для нормализации и чек-лист перед запуском.

Кому пригодится: мастерским, небольшим сервисам, бухгалтерам на потоке, продавцам на маркетплейсах и всем, кто устал копировать суммы руками из сканов и файлов.

Содержание

Ноутбук с таблицей расходов, бумажный счет и смартфон с фото кассового чека на столе

Что получится на выходе

Если собрать это дело нормально, на выходе у тебя будет не просто кучка распознанного текста, а аккуратная табличка с понятными колонками: дата документа, тип документа, продавец или контрагент, номер, валюта, сумма, налог, ссылка на исходный файл, статус проверки и техничный ключ для дедупликации. А если захочешь, можно ещё разворачивать позиции товара в отдельные строки.

Я обычно делаю два режима. Первый — одна строка на один документ, когда важна общая сумма. Второй — одна строка на одну позицию, если потом нужно считать категории, закупки или сверять состав счета. Для первого режима workflow собирается быстрее. Для второго приходится чуть дольше поковыряться с массивом items, зато аналитика потом куда приятнее.

Если уже работаешь с n8n, можешь заодно подсмотреть мой материал про вебхуки и защиту от дублей запросов. Там ровно тот участок, на котором новички чаще всего наступают на грабли при приёме файлов.

Как выглядит workflow в n8n

Я люблю простую, читаемую схему, чтобы потом не сидеть ночью и не вспоминать, где именно поломалась ветка с фотками. Каркас у меня обычно такой:

  1. Триггер: Webhook, Google Drive Trigger, Gmail Trigger, Telegram Trigger или папка на диске.
  2. Получение бинарного файла и служебных полей: имя, MIME-тип, размер, ссылка на исходник.
  3. Ветка по типу файла: PDF отправляю в одну сторону, JPG/PNG/HEIC — в другую.
  4. OCR или document AI: получаю текст или уже полуготовые поля.
  5. Нормализация через Edit Fields или Code.
  6. Проверка обязательных полей: дата, сумма, поставщик.
  7. Проверка дублей по своему ключу.
  8. Append row в Google Sheets.
  9. Логирование статуса и уведомление, если документ не распознался как надо.

Вот тут важный момент. Если PDF текстовый, иногда хватает простого извлечения текста и дальнейшего парсинга. Но если это скан, мятый чек с телефона или счёт в виде картинки внутри PDF, я сразу иду в OCR-сервис, а не пытаюсь выжать чудо из обычного чтения PDF. Так стабильнее.

Для развилки по файлам ставлю If или Switch: если MIME содержит pdf — маршрут на обработку документов; если image — на ветку фото. Это полезно ещё и потому, что разные OCR-движки по-разному едят входные данные. В одной ветке можно ждать многостраничный файл, в другой — одиночное фото с перспективой и тенями.

Логику записи в таблицу удобно сверять с материалом про обработку данных в Google Sheets через n8n. Там принцип тот же: сначала приводим поля к чистому виду, потом уже пишем строку, а не наоборот.

Какой OCR брать под чеки и счета

Тут я бы не женился на одном сервисе навсегда. Под разные задачи заходят разные варианты. Ниже короткая таблица, как я обычно выбираю движок.

Вариант Когда беру Чем нравится На что смотрю внимательно
Mistral OCR Сканы, фото, многостраничные PDF Хорошо вытаскивает текст документа целиком После OCR всё равно прогоняю через схему полей
Mindee Когда нужен именно invoice/receipt OCR Умеет сразу отдавать поля документа Проверяю, все ли нужные поля есть в ответе
AWS Textract Если уже живёшь в экосистеме AWS Неплохо работает по счетам Схема становится тяжелее по настройке
OpenAI + схема полей Когда нужен гибкий разбор текста и фото Удобно просить сразу JSON нужного формата Важно жёстко задать структуру ответа
Google Drive OCR как запасной вариант Когда нужен бюджетный черновой проход Быстро проверить гипотезу На таблицах и кривых сканах бывает капризным

Мой совет такой: если задача звучит как распознавание чеков по фото, OCR чеков PDF или извлечение данных из счета в таблицу, я сначала смотрю на Mistral OCR или Mindee. Они ближе к реальной задаче, чем голое выдёргивание текста. А уже потом поверх этого можно навесить Information Extractor, Structured Output Parser или обычную LLM-цепочку, чтобы привести ответ к единому JSON.

Если хочется стартануть быстрее, глянь подборку готовых шаблонов n8n. Часто проще взять каркас, чем собирать всё с нуля и потом искать потерявшийся бинарник между нодами.

Какие поля лучше сразу складывать в таблицу

Самая частая ошибка — тащить в таблицу весь распознанный хаос. Не надо. Таблица любит порядок. Я обычно держу такой набор колонок:

  • source_filename
  • source_url
  • document_type
  • vendor_name
  • document_number
  • document_date
  • currency
  • subtotal
  • tax
  • total
  • payment_method
  • items_json
  • ocr_text
  • dedupe_key
  • parse_status
  • review_comment
  • created_at

Зачем так много? Потому что через месяц ты сам себе скажешь спасибо. Когда OCR внезапно распознал общую сумму как номер счёта, поле review_comment спасает нервную систему. А items_json помогает не терять позиции товара, даже если в основную таблицу пишешь только одну строку на документ.

Для чеков я обычно добавляю ещё merchant_category или expense_type, если дальше нужен учёт расходов. Для счетов полезно поле due_date и отдельный статус: received, parsed, needs_review, approved. Тогда по таблице уже можно строить отчёты, напоминания и ежедневные сводки.

Как просить ИИ вернуть чистую структуру

Я формулирую задачу жёстко: верни JSON, где есть document_type, vendor_name, document_number, document_date, currency, total, tax и массив items. Если какого-то поля нет, верни null, а не фантазию. Это важнее, чем красивая формулировка промпта. Документный поток любит дисциплину.

Если потом захочешь на этой базе собирать уведомления, пригодится и схема про автосводку из Google Sheets в Telegram: там уже можно собрать ежедневный дайджест по новым чекам и счетам.

Как не словить дубли и кривые суммы

Вот здесь начинается взрослая жизнь. Один и тот же файл может прилететь дважды: из почты, из папки и ещё вручную через форму. Плюс люди любят пересылать один и тот же чек повторно. Поэтому я почти всегда делаю dedupe_key.

Самый практичный ключ — это склейка из названия продавца, номера документа, даты и нормализованной суммы. Если номер документа пустой, тогда беру vendor + дата + сумма + имя файла. Неидеально, но в бытовом потоке работает очень бодро.

return items.map(item => {
  const j = item.json;

  const total = Number(
    String(j.total ?? '')
      .replace(',', '.')
      .replace(/[^\d.]/g, '')
  );

  const dedupeKey = [
    (j.vendor_name || '').trim().toLowerCase(),
    (j.document_number || '').trim().toLowerCase(),
    (j.document_date || '').trim(),
    Number.isFinite(total) ? total.toFixed(2) : ''
  ].join('|');

  return {
    json: {
      ...j,
      total_normalized: Number.isFinite(total) ? total : null,
      dedupe_key: dedupeKey
    }
  };
});

Дальше этот ключ гоню в Remove Duplicates. Если поток идёт постоянно, очень удобно включать проверку не только внутри текущего запуска, но и между предыдущими исполнениями workflow. Так ты перестаёшь плодить повторные строки в таблице после случайных перезапусков.

Ещё один момент — формат суммы. OCR легко путается в запятых, пробелах и символах валюты. Поэтому на входе в Google Sheets я всегда держу отдельное число total_normalized и отдельно currency. Не надо складывать их в одну ячейку вида 1 250,50 руб., если потом хочешь что-то считать формулами.

Где чаще всего ломается схема

Я чаще всего вижу пять типовых проблем.

  1. Фото снято под углом, часть текста ушла в перспективу.
  2. На чеке бледная термопечать, и OCR съедает цифры.
  3. В PDF лежит картинка, а не текст, а человек думает, что это обычный PDF.
  4. ИИ выдумывает номер документа, когда его нет.
  5. Google Sheets получает поля в разном формате и строки едут криво.

Лечится это довольно приземлённо. Для фото — добавить шаг с проверкой качества или хотя бы отправлять такие документы в ручную проверку. Для бледных чеков — хранить сырой OCR-текст и ссылку на файл. Для фантазий модели — требовать null вместо догадок. Для таблицы — держать одну жёсткую схему колонок и не менять её на лету.

Отдельно советую собрать ветку ошибок с уведомлением. Очень выручает сценарий по контролю ошибок в n8n: retries, error workflow и нормальное оповещение экономят кучу времени, когда OCR-сервис внезапно отвечает не тем, что ты ждал.

Чек-лист перед запуском

  • Определи, откуда прилетает файл: папка, почта, форма, бот, webhook.
  • Разведи PDF и фото по разным веткам.
  • Выбери OCR-провайдера под свои документы, а не по красивому демо.
  • Задай жёсткую схему JSON-полей.
  • Нормализуй дату, сумму и валюту до записи в таблицу.
  • Сделай dedupe_key и включи проверку дублей.
  • Пиши в таблицу только чистые поля, сырой текст храни отдельно.
  • Добавь статус needs_review для сомнительных документов.
  • Настрой уведомление об ошибке и ручную точку контроля.

Итог

Если по-человечески, то n8n для распознавания счетов и чеков — это не какая-то космическая история. Рабочая связка давно понятна: приняли файл, прогнали через OCR, вытащили поля в единый JSON, проверили обязательные значения, убрали дубли и записали строку в таблицу. Самое важное тут не сам OCR, а аккуратная нормализация и дисциплина в структуре данных.

Я бы начинал с минимального конвейера на одну строку в таблице, а уже потом докручивал позиции товаров, категории расходов, сводки и уведомления. Так ты быстрее увидишь результат, поймаешь реальные ошибки на своих документах и не утонешь в лишней сложности на старте.

Когда эта схема завелась, она уже начинает работать как нормальный цех: документы заходят, данные падают в таблицу, а ты занимаешься делом, а не копипастой дат и сумм из сканов.

Метки: , , , , , , , , ,