OCR и компьютерное зрение: когда текста на странице недостаточно
Что делать, когда нужные данные — это изображение, скан или текст, встроенный в canvas/WebGL, а не обычный HTML.

Не все данные в вебе — это текст в HTML. Иногда нужная информация — это отсканированный документ, число на скриншоте, текст, отрисованный в canvas, или изображение чека. В этих случаях обычный парсинг DOM не работает вообще.
Когда обычный парсинг бессилен
- Сканы и PDF-документы без текстового слоя — счета, накладные, старые архивные документы.
- Canvas/WebGL-рендеринг — некоторые сайты (в том числе защищённые от скрапинга) рисуют текст через canvas вместо обычного HTML именно чтобы усложнить парсинг.
- Изображения с текстом — скриншоты таблиц, инфографика с ценами, водяные знаки поверх контента.
Классический OCR: Tesseract
import pytesseract
from PIL import Image
image = Image.open("invoice_scan.png")
text = pytesseract.image_to_string(image, lang="rus+eng")
print(text)Tesseract хорошо справляется с чистым, ровным текстом на однородном фоне, но заметно теряет точность на сложных макетах — таблицах, многоколоночных документах, тексте под углом или с низким контрастом.
Vision-модели: понимание контекста, не только символов
from openai import OpenAI
import base64
client = OpenAI()
with open("invoice_scan.png", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="gpt-4.1",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Извлеки: номер счёта, дату, сумму, ИНН поставщика. Верни JSON."},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_b64}"}},
],
}
],
)
print(response.choices[0].message.content)Мультимодальная модель понимает не только отдельные символы, но и структуру документа — где находится таблица, что относится к заголовку, а что к строке данных. Это даёт заметно лучшую точность на сложных макетах, но стоит дороже за запрос, чем локальный OCR.
Совет
Для больших объёмов однотипных документов (например, тысячи однотипных накладных от одного поставщика) экономически выгоднее один раз настроить точный шаблон извлечения (даже через классический OCR + регулярные выражения), чем каждый раз платить за vision-модель.
Извлечение текста из PDF без OCR
Если PDF содержит текстовый слой (не является сканом), OCR не нужен вообще:
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
for page in pdf.pages:
tables = page.extract_tables()
for table in tables:
print(table)Это быстрее и точнее OCR — стоит всегда сначала проверить, есть ли у PDF текстовый слой, прежде чем применять распознавание изображений.
Сравнение подходов
| Подход | Точность на сложных макетах | Стоимость | Скорость |
|---|---|---|---|
| pdfplumber (текстовый слой) | Высокая (если слой есть) | Минимальная | Высокая |
| Tesseract OCR | Средняя | Минимальная | Высокая |
| Vision-модель (GPT-4V, Claude) | Высокая | Заметная (за запрос) | Средняя |
Заключение
OCR и компьютерное зрение — не замена обычному парсингу, а дополнение для случаев, когда данные физически не представлены как текст в разметке. Правильная стратегия — сначала проверить, нет ли более дешёвого пути (текстовый слой PDF, скрытый API), и только затем переходить к OCR или vision-моделям, выбирая между ними по балансу точности и стоимости для конкретного объёма документов.
Частые вопросы
Чем OCR отличается от vision-моделей (мультимодальных LLM)?+
Классический OCR (Tesseract) распознаёт символы по их форме и не понимает контекст — хорошо работает на чистом, ровном тексте, но ошибается на сложных макетах. Мультимодальные LLM (GPT-4 Vision, Claude) понимают изображение целостно, включая структуру и контекст, что даёт лучшую точность на сложных документах, но дороже по стоимости запроса.
Можно ли извлекать данные из PDF без OCR?+
Если PDF содержит текстовый слой (не скан, а сгенерированный документ), можно извлечь текст напрямую библиотеками вроде pdfplumber или PyMuPDF — это быстрее и точнее OCR. OCR нужен только для отсканированных/растровых PDF без текстового слоя.
Как проверить точность OCR-извлечения на масштабе?+
Выборочная сверка случайной подвыборки результатов с оригиналом — стандартная практика. Для критичных данных (суммы в финансовых документах) стоит также использовать contrastive-проверку: если два разных метода извлечения дают разный результат, помечать запись для ручной проверки.
Похожие материалы

Parsera vs Scrapy: API или Python-фреймворк?
Честное сравнение управляемого API для скрапинга и популярного open-source фреймворка Scrapy — по скорости внедрения, гибкости и совокупной стоимости.

Structured extraction: как заставить LLM возвращать чистый JSON из HTML
Practical guide: function calling, JSON Schema и валидация — три техники, которые убирают галлюцинации и битый JSON из ответов LLM.

Playwright для веб-скрапинга: обход JS-рендеринга и антибот-защиты
Как использовать Playwright для парсинга SPA-сайтов, какие сигналы выдают headless-браузер и как их скрыть.