Извлечение данных и OCR
Извлечение таблиц из PDF, OCR сканов, структурирование данных из документов с использованием Python-кода в песочнице
Извлечение данных и OCR
Этот skill содержит паттерны Python-кода для извлечения данных из документов в песочнице. Загруженные файлы доступны в /tmp/.
Доступные библиотеки
Библиотеки НЕ предустановлены в песочнице. Перед использованием установи через pip:
pdfplumber— извлечение таблиц и текста из PDFpytesseract— OCR (оптическое распознавание текста)pdf2image— конвертация PDF в изображенияPillow— обработка изображенийopenpyxl— создание Excel-файловpandas— обработка табличных данных
ВАЖНО: Каждый скрипт ОБЯЗАН начинаться с установки нужных пакетов:
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas'], capture_output=True)
БЛОК 1: Извлечение таблиц из PDF
Паттерн: Извлечение всех таблиц из PDF
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas'], capture_output=True)
import pdfplumber
import pandas as pd
import base64
from io import BytesIO
pdf_bytes = base64.b64decode(pdf_content)
tables = []
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
for i, page in enumerate(pdf.pages):
page_tables = page.extract_tables()
for j, table in enumerate(page_tables):
if table:
df = pd.DataFrame(table[1:], columns=table[0])
df["_page"] = i + 1
df["_table"] = j + 1
tables.append(df)
if tables:
result = pd.concat(tables, ignore_index=True)
result.to_excel(cw.output_path("extracted_tables.xlsx"), index=False)
print(f"Извлечено таблиц: {len(tables)}")
else:
print("Таблицы не найдены")
Паттерн: Извлечение таблицы с конкретной страницы
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas'], capture_output=True)
import pdfplumber
import pandas as pd
import base64
from io import BytesIO
pdf_bytes = base64.b64decode(pdf_content)
target_page = 1 # номер страницы (начиная с 1)
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
page = pdf.pages[target_page - 1]
tables = page.extract_tables()
if tables:
# Берём первую таблицу со страницы
table = tables[0]
df = pd.DataFrame(table[1:], columns=table[0])
df.to_excel(cw.output_path("table_page_{}.xlsx").format(target_page), index=False)
print(f"Таблица извлечена: {len(df)} строк")
else:
print("Таблицы на странице не найдены")
Паттерн: Извлечение с настройками таблицы
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas'], capture_output=True)
import pdfplumber
import pandas as pd
import base64
from io import BytesIO
pdf_bytes = base64.b64decode(pdf_content)
# Настройки для сложных таблиц
table_settings = {
"vertical_strategy": "lines", # или "text", "explicit"
"horizontal_strategy": "lines", # или "text", "explicit"
"snap_tolerance": 3,
"join_tolerance": 3,
"edge_min_length": 3,
}
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
all_data = []
for page in pdf.pages:
tables = page.extract_tables(table_settings)
for table in tables:
if table and len(table) > 1:
df = pd.DataFrame(table[1:], columns=table[0])
all_data.append(df)
if all_data:
result = pd.concat(all_data, ignore_index=True)
result.to_excel(cw.output_path("extracted.xlsx"), index=False)
print(f"Извлечено строк: {len(result)}")
Паттерн: Извлечение таблицы в несколько листов Excel
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas', 'openpyxl'], capture_output=True)
import pdfplumber
import pandas as pd
import base64
from io import BytesIO
pdf_bytes = base64.b64decode(pdf_content)
with pd.ExcelWriter(cw.output_path("tables_by_page.xlsx"), engine="openpyxl") as writer:
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
for i, page in enumerate(pdf.pages):
tables = page.extract_tables()
for j, table in enumerate(tables):
if table and len(table) > 1:
df = pd.DataFrame(table[1:], columns=table[0])
sheet_name = f"Page{i+1}_Table{j+1}"[:31] # Excel ограничение
df.to_excel(writer, sheet_name=sheet_name, index=False)
print(f"Добавлен лист: {sheet_name}")
print("Все таблицы сохранены")
БЛОК 2: OCR сканированных документов
Паттерн: OCR одностраничного скана (изображение)
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'Pillow'], capture_output=True)
import pytesseract
from PIL import Image
import base64
from io import BytesIO
image_bytes = base64.b64decode(image_content)
image = Image.open(BytesIO(image_bytes))
# OCR с русским языком
text = pytesseract.image_to_string(image, lang="rus")
with open(cw.output_path("ocr_result.txt"), "w", encoding="utf-8") as f:
f.write(text)
print(f"Распознано символов: {len(text)}")
print("Превью:", text[:500])
Паттерн: OCR многостраничного PDF (скан)
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'pdf2image'], capture_output=True)
import pytesseract
from pdf2image import convert_from_bytes
import base64
pdf_bytes = base64.b64decode(pdf_content)
# Конвертируем PDF в изображения
images = convert_from_bytes(pdf_bytes, dpi=300)
all_text = []
for i, image in enumerate(images):
text = pytesseract.image_to_string(image, lang="rus")
all_text.append(f"=== Страница {i+1} ===\n{text}")
print(f"Страница {i+1}: распознано {len(text)} символов")
full_text = "\n\n".join(all_text)
with open(cw.output_path("ocr_full.txt"), "w", encoding="utf-8") as f:
f.write(full_text)
print(f"Всего страниц: {len(images)}")
Паттерн: OCR с предобработкой изображения
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'Pillow'], capture_output=True)
import pytesseract
from PIL import Image, ImageEnhance, ImageFilter
import base64
from io import BytesIO
image_bytes = base64.b64decode(image_content)
image = Image.open(BytesIO(image_bytes))
# Предобработка для улучшения качества OCR
# 1. Конвертация в градации серого
image = image.convert("L")
# 2. Увеличение контраста
enhancer = ImageEnhance.Contrast(image)
image = enhancer.enhance(2.0)
# 3. Бинаризация (опционально)
threshold = 150
image = image.point(lambda x: 255 if x > threshold else 0)
# 4. Удаление шума
image = image.filter(ImageFilter.MedianFilter(size=3))
# OCR
text = pytesseract.image_to_string(image, lang="rus", config="--psm 6")
with open(cw.output_path("ocr_enhanced.txt"), "w", encoding="utf-8") as f:
f.write(text)
print("OCR с предобработкой завершён")
Паттерн: OCR с определением структуры (блоки текста)
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'Pillow'], capture_output=True)
import pytesseract
from PIL import Image
import base64
from io import BytesIO
import json
image_bytes = base64.b64decode(image_content)
image = Image.open(BytesIO(image_bytes))
# Получаем данные с координатами
data = pytesseract.image_to_data(image, lang="rus", output_type=pytesseract.Output.DICT)
# Группируем по блокам
blocks = {}
for i in range(len(data["text"])):
if data["text"][i].strip():
block_num = data["block_num"][i]
if block_num not in blocks:
blocks[block_num] = {
"text": [],
"left": data["left"][i],
"top": data["top"][i],
}
blocks[block_num]["text"].append(data["text"][i])
# Формируем результат
result = []
for block_num, block_data in blocks.items():
result.append({
"block": block_num,
"text": " ".join(block_data["text"]),
"position": {"left": block_data["left"], "top": block_data["top"]}
})
with open(cw.output_path("ocr_structured.json"), "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print(f"Распознано блоков: {len(result)}")
Паттерн: OCR с извлечением таблицы из скана
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'Pillow', 'pandas'], capture_output=True)
import pytesseract
from PIL import Image
import pandas as pd
import base64
from io import BytesIO
image_bytes = base64.b64decode(image_content)
image = Image.open(BytesIO(image_bytes))
# Используем TSV-вывод для структурированных данных
tsv_data = pytesseract.image_to_data(image, lang="rus", output_type=pytesseract.Output.DATAFRAME)
# Фильтруем пустые значения
tsv_data = tsv_data[tsv_data["text"].notna()]
tsv_data = tsv_data[tsv_data["text"].str.strip() != ""]
# Группируем по строкам (line_num) и блокам
lines = tsv_data.groupby(["block_num", "line_num"])["text"].apply(" ".join).reset_index()
# Сохраняем
lines.to_excel(cw.output_path("ocr_lines.xlsx"), index=False)
print(f"Извлечено строк: {len(lines)}")
БЛОК 3: Извлечение текста из PDF
Паттерн: Извлечение всего текста
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber'], capture_output=True)
import pdfplumber
import base64
from io import BytesIO
pdf_bytes = base64.b64decode(pdf_content)
all_text = []
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
for i, page in enumerate(pdf.pages):
text = page.extract_text()
if text:
all_text.append(f"=== Страница {i+1} ===\n{text}")
full_text = "\n\n".join(all_text)
with open(cw.output_path("extracted_text.txt"), "w", encoding="utf-8") as f:
f.write(full_text)
print(f"Извлечено страниц: {len(all_text)}")
Паттерн: Извлечение текста с сохранением форматирования
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber'], capture_output=True)
import pdfplumber
import base64
from io import BytesIO
pdf_bytes = base64.b64decode(pdf_content)
with pdfplumber.open(BytesIO(pdf_bytes)) as pdf:
for i, page in enumerate(pdf.pages):
# Извлекаем слова с координатами
words = page.extract_words(
keep_blank_chars=True,
x_tolerance=3,
y_tolerance=3
)
# Группируем по строкам (по y-координате)
lines = {}
for word in words:
y = round(word["top"], 0)
if y not in lines:
lines[y] = []
lines[y].append(word)
# Сортируем строки
for y in sorted(lines.keys()):
line_words = sorted(lines[y], key=lambda w: w["x0"])
line_text = " ".join(w["text"] for w in line_words)
print(line_text)
БЛОК 4: Структурирование данных
Паттерн: Парсинг реквизитов организации
import re
import json
# text - извлечённый текст документа
text = extracted_text
patterns = {
"inn": r"ИНН[:\s]*(\d{10,12})",
"kpp": r"КПП[:\s]*(\d{9})",
"ogrn": r"ОГРН[:\s]*(\d{13,15})",
"name": r"(?:Наименование|Организация)[:\s]*([^\n]+)",
"address": r"(?:Адрес|Юридический адрес)[:\s]*([^\n]+)",
"phone": r"(?:Тел\.?|Телефон)[:\s]*([\d\s\-\+\(\)]+)",
"email": r"[\w\.-]+@[\w\.-]+\.\w+",
"bank_account": r"р/с[:\s]*(\d{20})",
"bik": r"БИК[:\s]*(\d{9})",
}
result = {}
for field, pattern in patterns.items():
match = re.search(pattern, text, re.IGNORECASE)
if match:
result[field] = match.group(1).strip() if match.lastindex else match.group(0).strip()
with open(cw.output_path("requisites.json"), "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print("Извлечённые реквизиты:")
for k, v in result.items():
print(f" {k}: {v}")
Паттерн: Извлечение сумм и дат
import re
import json
import sys
from document_dates import find_dates, find_contract_date, find_payment_term
text = extracted_text
amount_patterns = [
r"(\d[\d\s]*[\d,\.]+)\s*(?:руб|рублей|₽|RUB)",
r"(?:сумма|стоимость|цена)[:\s]*(\d[\d\s]*[\d,\.]+)",
r"(?:итого|всего)[:\s]*(\d[\d\s]*[\d,\.]+)",
]
amounts = []
for pattern in amount_patterns:
for match in re.finditer(pattern, text, re.IGNORECASE):
amount_str = match.group(1).replace(" ", "").replace(",", ".")
try:
amounts.append(float(amount_str))
except ValueError:
pass
all_dates = find_dates(text)
contract_date = find_contract_date(text)
payment_term = find_payment_term(text)
result = {
"amounts": sorted(set(amounts), reverse=True),
"dates": [d["iso"] for d in all_dates],
"dates_detailed": all_dates,
"contract_date": contract_date,
"payment_term": payment_term,
}
with open(cw.output_path("extracted_values.json"), "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print(f"Найдено сумм: {len(result['amounts'])}")
print(f"Найдено дат: {len(result['dates'])}")
print(f"Дата заключения: {contract_date['iso'] if contract_date else 'не найдена'}")
Паттерн: Дата заключения договора и срок оплаты
Скрипт document_dates.py в /mnt/skills/data_extraction_ru/scripts/ парсит даты во всех форматах русских договоров: "22" мая 2026, «22» мая 2026, 22 мая 2026 г., 22.05.2026, ISO 2026-05-22. Каждой дате присваивается тип (birthdate, passport, power_of_attorney, generic) по ближайшему ключевому слову — это отделяет дату заключения от дат рождения/паспорта/доверенности.
import sys
from document_dates import find_contract_date, find_payment_term, payment_deadline, RU_WEEKDAYS
contract_date = find_contract_date(text)
term = find_payment_term(text)
base_iso = contract_date["iso"]
deadline = payment_deadline(base_iso, term)
print(f"Дата заключения: {base_iso}")
print(f"Срок оплаты: {term['days']} {term['kind']} дней")
print(f"Крайний срок: {deadline} ({RU_WEEKDAYS[deadline.weekday()]})")
Для электронных договоров датой заключения обычно считается дата подписания ЭЦП последней стороной (она может отличаться от даты в шапке): тогда base_iso бери из даты ЭЦП, а не из find_contract_date. find_payment_term различает «рабочих» и «календарных» дней; payment_deadline считает рабочие дни через add_business_days.
Не форматируй даты через strftime с локалью. date.strftime("%d.%m.%Y", "ru") падает с TypeError: strftime() takes at most 1 argument (2 given) — у date/datetime метод принимает только строку формата. Русский день недели бери из RU_WEEKDAYS[d.weekday()], а не из strftime("%A").
Паттерн: Структурирование накладной/счёта
import subprocess
subprocess.run(['pip', 'install', 'pandas'], capture_output=True)
import re
import pandas as pd
import json
text = extracted_text
# Извлекаем номер и дату документа
doc_number = re.search(r"№\s*(\S+)", text)
doc_date = re.search(r"от\s*(\d{2}\.\d{2}\.\d{4})", text)
# Ищем табличные данные (товарные позиции)
# Типичный формат: № | Наименование | Ед.изм. | Кол-во | Цена | Сумма
line_pattern = r"(\d+)\s+(.+?)\s+(шт|кг|м|л|уп|компл)[.\s]*\s+(\d+[\d,\.]*)\s+(\d+[\d,\.]*)\s+(\d+[\d,\.]*)"
items = []
for match in re.finditer(line_pattern, text, re.IGNORECASE):
items.append({
"num": match.group(1),
"name": match.group(2).strip(),
"unit": match.group(3),
"quantity": float(match.group(4).replace(",", ".")),
"price": float(match.group(5).replace(",", ".").replace(" ", "")),
"amount": float(match.group(6).replace(",", ".").replace(" ", "")),
})
result = {
"document_number": doc_number.group(1) if doc_number else None,
"document_date": doc_date.group(1) if doc_date else None,
"items": items,
"total_amount": sum(item["amount"] for item in items),
}
# Сохраняем в JSON
with open(cw.output_path("invoice_data.json"), "w", encoding="utf-8") as f:
json.dump(result, f, ensure_ascii=False, indent=2)
# И в Excel
if items:
df = pd.DataFrame(items)
df.to_excel(cw.output_path("invoice_items.xlsx"), index=False)
print(f"Извлечено позиций: {len(items)}")
print(f"Общая сумма: {result['total_amount']}")
БЛОК 5: Работа с входными файлами
Паттерн: Обработка загруженных файлов
import base64
from io import BytesIO
for file_input in files:
name = file_input["name"]
content = base64.b64decode(file_input["content_base64"])
# Определяем тип файла
if name.lower().endswith(".pdf"):
file_type = "pdf"
elif name.lower().endswith((".png", ".jpg", ".jpeg", ".tiff", ".bmp")):
file_type = "image"
elif name.lower().endswith((".xlsx", ".xls")):
file_type = "excel"
else:
file_type = "unknown"
print(f"Файл: {name}, тип: {file_type}, размер: {len(content)} байт")
Паттерн: Batch-обработка нескольких PDF
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas'], capture_output=True)
import pdfplumber
import pandas as pd
import base64
from io import BytesIO
all_tables = []
for file_input in files:
if not file_input["name"].lower().endswith(".pdf"):
continue
content = base64.b64decode(file_input["content_base64"])
with pdfplumber.open(BytesIO(content)) as pdf:
for page in pdf.pages:
tables = page.extract_tables()
for table in tables:
if table and len(table) > 1:
df = pd.DataFrame(table[1:], columns=table[0])
df["_source_file"] = file_input["name"]
all_tables.append(df)
if all_tables:
result = pd.concat(all_tables, ignore_index=True)
result.to_excel(cw.output_path("all_tables.xlsx"), index=False)
print(f"Обработано файлов, извлечено таблиц: {len(all_tables)}")
Паттерн: OCR нескольких изображений
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'Pillow'], capture_output=True)
import pytesseract
from PIL import Image
import base64
from io import BytesIO
results = []
for file_input in files:
name = file_input["name"]
if not name.lower().endswith((".png", ".jpg", ".jpeg", ".tiff", ".bmp")):
continue
content = base64.b64decode(file_input["content_base64"])
image = Image.open(BytesIO(content))
text = pytesseract.image_to_string(image, lang="rus")
results.append({
"file": name,
"text": text,
"chars": len(text)
})
print(f"{name}: распознано {len(text)} символов")
# Сохраняем все результаты
with open(cw.output_path("ocr_results.txt"), "w", encoding="utf-8") as f:
for r in results:
f.write(f"=== {r['file']} ===\n{r['text']}\n\n")
print(f"Обработано файлов: {len(results)}")
БЛОК 6: Экспорт в Excel с форматированием
Паттерн: Экспорт структурированных данных
import subprocess
subprocess.run(['pip', 'install', 'pandas', 'openpyxl'], capture_output=True)
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
from openpyxl.utils.dataframe import dataframe_to_rows
from openpyxl.utils import get_column_letter
# data - извлечённые данные
df = pd.DataFrame(extracted_data)
wb = Workbook()
ws = wb.active
ws.title = "Извлечённые данные"
# Стили
header_font = Font(bold=True, size=11, color="FFFFFF")
header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid")
thin_border = Border(
left=Side(style="thin"),
right=Side(style="thin"),
top=Side(style="thin"),
bottom=Side(style="thin")
)
# Записываем данные
for r_idx, row in enumerate(dataframe_to_rows(df, index=False, header=True), 1):
for c_idx, value in enumerate(row, 1):
cell = ws.cell(row=r_idx, column=c_idx, value=value)
cell.border = thin_border
if r_idx == 1: # заголовок
cell.font = header_font
cell.fill = header_fill
cell.alignment = Alignment(horizontal="center")
# Автоширина колонок
for col_idx, column in enumerate(df.columns, 1):
max_length = max(len(str(column)), df[column].astype(str).map(len).max())
ws.column_dimensions[get_column_letter(col_idx)].width = min(max_length + 2, 50)
wb.save(cw.output_path("formatted_data.xlsx"))
print("Данные экспортированы с форматированием")
Паттерн: Экспорт с несколькими листами
import subprocess
subprocess.run(['pip', 'install', 'pandas', 'openpyxl'], capture_output=True)
import pandas as pd
# Словарь с данными для разных листов
sheets_data = {
"Реквизиты": pd.DataFrame([requisites]),
"Позиции": pd.DataFrame(items),
"Суммы": pd.DataFrame({"Сумма": amounts}),
}
with pd.ExcelWriter(cw.output_path("structured_export.xlsx"), engine="openpyxl") as writer:
for sheet_name, df in sheets_data.items():
if not df.empty:
df.to_excel(writer, sheet_name=sheet_name, index=False)
print(f"Добавлен лист: {sheet_name}")
print("Экспорт завершён")
БЛОК 7: Комбинированные сценарии
Задача: PDF скан → OCR → Таблица в Excel
import subprocess
subprocess.run(['pip', 'install', 'pytesseract', 'pdf2image', 'Pillow', 'pandas'], capture_output=True)
import pytesseract
from pdf2image import convert_from_bytes
from PIL import Image
import pandas as pd
import re
import base64
pdf_bytes = base64.b64decode(pdf_content)
# 1. Конвертируем PDF в изображения
images = convert_from_bytes(pdf_bytes, dpi=300)
print(f"Страниц: {len(images)}")
# 2. OCR каждой страницы
all_text = []
for i, image in enumerate(images):
text = pytesseract.image_to_string(image, lang="rus")
all_text.append(text)
print(f"Страница {i+1}: OCR завершён")
full_text = "\n".join(all_text)
# 3. Извлекаем табличные данные
# Адаптируйте паттерн под ваш документ
line_pattern = r"(\d+)\s+(.+?)\s+(\d+[\d,\.]*)\s+(\d+[\d,\.]*)"
rows = []
for match in re.finditer(line_pattern, full_text):
rows.append({
"№": match.group(1),
"Наименование": match.group(2).strip(),
"Количество": match.group(3),
"Сумма": match.group(4),
})
# 4. Сохраняем в Excel
if rows:
df = pd.DataFrame(rows)
df.to_excel(cw.output_path("scanned_table.xlsx"), index=False)
print(f"Извлечено строк: {len(rows)}")
else:
# Сохраняем хотя бы текст
with open(cw.output_path("ocr_text.txt"), "w", encoding="utf-8") as f:
f.write(full_text)
print("Таблица не найдена, сохранён текст OCR")
Задача: Извлечь реквизиты из нескольких PDF
import subprocess
subprocess.run(['pip', 'install', 'pdfplumber', 'pandas'], capture_output=True)
import pdfplumber
import pandas as pd
import re
import base64
from io import BytesIO
all_requisites = []
for file_input in files:
if not file_input["name"].lower().endswith(".pdf"):
continue
content = base64.b64decode(file_input["content_base64"])
with pdfplumber.open(BytesIO(content)) as pdf:
text = "\n".join(page.extract_text() or "" for page in pdf.pages)
# Извлекаем реквизиты
inn_match = re.search(r"ИНН[:\s]*(\d{10,12})", text)
name_match = re.search(r"(?:ООО|ОАО|ЗАО|ПАО|АО|ИП)\s*[«\"]?([^»\"]+)[»\"]?", text)
all_requisites.append({
"Файл": file_input["name"],
"ИНН": inn_match.group(1) if inn_match else "",
"Наименование": name_match.group(0) if name_match else "",
})
df = pd.DataFrame(all_requisites)
df.to_excel(cw.output_path("requisites_all.xlsx"), index=False)
print(f"Обработано файлов: {len(all_requisites)}")
БЛОК 8: Типичные команды пользователя
| Команда | Действие |
|---|---|
| "Извлеки таблицы из PDF" | БЛОК 1: Извлечение всех таблиц |
| "Распознай скан" | БЛОК 2: OCR скана |
| "Вытащи текст из PDF" | БЛОК 3: Извлечение текста |
| "Найди реквизиты в документе" | БЛОК 4: Парсинг реквизитов |
| "Переведи скан в Excel" | БЛОК 7: PDF скан → OCR → Excel |
| "Извлеки суммы и даты" | БЛОК 4: Извлечение сумм и дат |
| "Обработай несколько файлов" | БЛОК 5: Batch-обработка |
Skill-файл содержит паттерны кода для извлечения данных из документов. Выполняй код через sandbox_bash.
Попробуйте этот навык
Зарегистрируйтесь и используйте навык «Извлечение данных и OCR» бесплатно.