Штрихкод и QR-код давно перестали быть чем-то исключительно складским или кассовым. Сегодня ими отмечают товары в интернет-магазинах, связывают упаковку с карточкой продукта, публикуют контакты, открывают страницы оплаты, передают настройки Wi‑Fi и добавляют офлайн-рекламе цифровое продолжение.
Веб-сайт, лендинг или сервис может генерировать такой код автоматически: достаточно получить данные от пользователя, выбрать формат и вернуть изображение в PNG, SVG или другом удобном виде.
Python особенно хорошо подходит для этой задачи. У него есть готовые библиотеки для QR-кодов, штрихкодов, работы с изображениями, файлами и веб-фреймворками. При этом разработчику не приходится вручную рисовать полосы или рассчитывать геометрию квадратов. Но простая генерация картинки - только половина дела.
Важно разобраться в форматах, проверить входные данные, выбрать правильный размер, обеспечить читаемость, безопасно встроить генератор в сайт и не превратить QR-код в красивый, но бесполезный квадратик.
Что такое штрихкоды и QR-коды и чем они отличаются
Штрихкод графическое представление данных с помощью полос, промежутков или других контрастных элементов. Большинство привычных одномерных кодов хранит сравнительно небольшой объём информации: номер товара, артикул, идентификатор документа или внутренний ключ.
Сканер считывает ширину и последовательность полос, после чего программное обеспечение преобразует их в строку символов.
QR-код относится к двумерным кодам. Он состоит из квадратных модулей и может хранить текст, ссылку, номер телефона, электронную почту, координаты, настройки сети и другие данные. Благодаря двум измерениям QR-код вмещает гораздо больше информации, чем типичный линейный штрихкод.
Кроме того, в нём предусмотрено исправление ошибок: часть повреждённых или закрытых модулей может быть восстановлена при сканировании.
| Параметр | Одномерный штрихкод | QR-код |
|---|---|---|
| Форма | Полосы или линии | Квадратная матрица |
| Типичные данные | Артикул, код товара, номер | Ссылка, текст, контакт, настройки |
| Объём данных | Небольшой | От нескольких символов до нескольких тысяч знаков |
| Ориентация | Обычно требуется правильное направление | Считывается под разными углами |
| Применение в интернете | Связь товара с базой или карточкой | Переход на страницу, приложение, оплату или форму |
Для интернет-проектов это различие принципиально. Если нужно обозначить товар внутренним номером и считывать его на складе, подойдёт Code 128 или EAN-13. Если требуется отправить пользователя с бумажного флаера на сайт, практичнее QR-код с коротким URL.
Не стоит запихивать в QR-код длинный текст, если ту же информацию можно разместить на веб-странице. Чем меньше данных в коде, тем компактнее и надёжнее изображение.
Есть и важное практическое уточнение: QR-код обычно содержит не саму бизнес-логику, а данные для её запуска. Например, код может вести на страницу вида /product/4821.
Сервер уже по этому адресу показывает актуальную цену, остаток, описание и форму заказа. Такой подход позволяет менять содержимое страницы без перепечатывания самого QR-кода. Если же в код зашит длинный неизменяемый текст, исправить ошибку после печати невозможно.
Подготовка Python-проекта и установка библиотек
Для генерации QR-кодов в Python чаще всего используют пакет qrcode. Он умеет создавать коды разных версий, настраивать уровень коррекции ошибок, размер модуля, поля и цветовую схему.
Изображение можно сохранить через Pillow - популярную библиотеку для работы с растровой графикой. Для одномерных штрихкодов удобно применять python-barcode, а для вывода в SVG - дополнительные возможности самого пакета или отдельные инструменты.
Лучше не устанавливать всё в глобальную среду операционной системы. Создайте отдельное виртуальное окружение проекта. Это избавит от конфликтов версий, особенно если сайт использует Flask, Django, FastAPI или другие зависимости.
python -m venv.venv
Активация окружения зависит от платформы. В Linux и macOS обычно используется команда ниже:
source.venv/bin/activate
В Windows PowerShell команда выглядит иначе:
.venv\Scripts\Activate.ps1
После активации установите нужные пакеты:
pip install qrcode[pil] pillow python-barcode
Дополнительная запись [pil] нужна для установки поддержки Pillow вместе с qrcode. Если проект работает только с SVG и не требует растровых изображений, набор зависимостей можно сократить.
Однако Pillow всё равно полезен: с его помощью удобно создавать превью, добавлять логотип, проверять размеры и конвертировать изображения в нужный формат.
Проверить окружение можно небольшим скриптом:
import qrcode
image = qrcode.make("https://example.com")
image.save("test_qr.png")
print("QR-код сохранён")
После запуска в каталоге появится файл test_qr.png. Откройте его на экране и попробуйте отсканировать камерой телефона.
Такой тест кажется примитивным, но он сразу показывает, установлены ли зависимости и корректно ли записывается изображение. В реальном проекте полезно также зафиксировать версии библиотек в requirements.txt:
pip freeze > requirements.txt
Для командной разработки это важно: генератор должен одинаково работать на локальном компьютере, тестовом сервере и в продакшене. Обновление библиотек без проверки иногда меняет поведение рендеринга, формат выходного файла или набор доступных параметров.
Поэтому перед обновлением зависимостей стоит сохранить несколько эталонных изображений и сравнить новые результаты с ними.
Создание простого QR-кода
Самый короткий способ создать QR-код - передать строку функции qrcode.make. Это удобно для одноразовых изображений, например в административном скрипте или небольшом прототипе:
import qrcode
data = "https://site.example/catalog"
qr_image = qrcode.make(data)
qr_image.save("catalog.png")
В переменной data может находиться любой текст, который поддерживает выбранная библиотека. На практике для интернет-сайта чаще всего используется URL.
Пользователь сканирует изображение камерой, телефон распознаёт адрес, а браузер предлагает перейти на страницу. При этом адрес должен начинаться с протокола, обычно https://. Если передать строку без протокола, разные приложения могут распознать её по-разному.
Когда нужно управлять параметрами, используется объект QRCode. Он позволяет задать версию, уровень коррекции ошибок, размер модуля, ширину свободной зоны и режим автоматического определения версии:
import qrcode
from qrcode.constants import ERROR_CORRECT_M
qr = qrcode.QRCode(
version=None,
error_correction=ERROR_CORRECT_M,
box_size=10,
border=4
)
qr.add_data("https://site.example/promo?source=qr")
qr.make(fit=True)
image = qr.make_image(
fill_color="black",
back_color="white"
)
image.save("promo.png")
Параметр version определяет размер матрицы QR-кода. Если указать None и включить fit=True, библиотека подберёт версию по объёму данных. Это хороший вариант для большинства задач.
Жёстко заданная версия нужна, когда необходимо обеспечить одинаковую геометрию кодов, например для печати серии этикеток в одном шаблоне.
Параметр box_size задаёт размер одного модуля в пикселях. Чем больше значение, тем крупнее изображение. border отвечает за свободную рамку вокруг матрицы.
Этот участок называется quiet zone, или зона покоя. Она обязательна: сканеру нужно отделить QR-код от фона и соседних элементов. Уменьшать border ради экономии места рискованно, особенно на упаковке с пёстрым дизайном.
Начальный уровень ERROR_CORRECT_M подходит для общего применения. В библиотеке обычно доступны четыре уровня коррекции:
- ERROR_CORRECT_L - восстановление примерно до 7 процентов повреждённых данных;
- ERROR_CORRECT_M - примерно до 15 процентов;
- ERROR_CORRECT_Q - примерно до 25 процентов;
- ERROR_CORRECT_H - примерно до 30 процентов.
Чем выше коррекция, тем больше служебных данных и тем плотнее матрица при одинаковом содержимом. Для кода с логотипом в центре разумно выбрать Q или H, но нельзя считать это разрешением закрыть значительную часть изображения.
Коррекция ошибок не делает QR-код неуязвимым: слишком большой логотип, низкий контраст или повреждение углов всё равно могут привести к сбою.
Генерация одномерных штрихкодов
Для обычных штрихкодов сначала нужно выбрать стандарт. Code 128 универсален и поддерживает цифры, латинские буквы и специальные символы.
EAN-13 применяется главным образом для товаров в розничной торговле и требует корректного тринадцатизначного номера, причём последняя цифра является контрольной.
Code 39 встречается в логистике, производстве и внутренних системах, но способен создавать более длинные изображения при той же информации.
Пример генерации Code 128 с помощью python-barcode:
import barcode
from barcode.writer import ImageWriter
value = "ORDER-4821"
code_class = barcode.get_barcode_class("code128")
code = code_class(value, writer=ImageWriter())
filename = code.save("order_code")
print(filename)
В результате библиотека создаст файл изображения с расширением PNG. Название и данные можно менять, но перед генерацией стоит установить правила валидации. Если бизнес-логика ожидает только цифры, не следует молча принимать буквы.
И наоборот: если используется Code 128, строка с дефисом может быть допустимой и не должна отбрасываться проверкой, рассчитанной на EAN-13.
Для EAN-13 пример выглядит так:
import barcode
from barcode.writer import ImageWriter
ean = barcode.get("ean13", "590123412345")
ean.save("product_ean")
В данном случае передаётся двенадцать цифр, а контрольный разряд рассчитывается библиотекой. Если передать тринадцать цифр, необходимо понимать, как конкретная реализация обрабатывает контрольное значение: она может проверить его, проигнорировать или выдать ошибку.
В интернет-магазине это особенно важно, потому что неверный EAN может привести к проблемам при импорте товаров, синхронизации с маркетплейсами и работе внешних каталогов.
Параметры внешнего вида можно передавать через writer_options:
from barcode import Code128
from barcode.writer import ImageWriter
options = {
"module_width": 0.35,
"module_height": 18,
"font_size": 10,
"text_distance": 4,
"quiet_zone": 6
}
code = Code128("WEB-2026-001", writer=ImageWriter())
code.save("web_code", options=options)
Не стоит делать полосы слишком тонкими. На экране такой код может выглядеть аккуратно, но после печати на дешёвой этикетке границы сольются.
В типографии на читаемость влияют разрешение принтера, растяжение бумаги, масштабирование макета и качество чернил. Поэтому штрихкод проверяют не только программно, но и реальным сканером или телефоном с подходящим приложением.
Размер, разрешение, цвет и читаемость
Генерация изображения с технической точки зрения не означает, что код будет хорошо считываться. Сканер анализирует контраст, форму модулей, расстояние до соседних элементов, резкость границ и общий масштаб.
Маленький QR-код с длинной ссылкой может превратиться в плотную мозаику, которую камера телефона распознаёт только при идеальном освещении.
Для цифрового размещения удобно начинать с размера от 250 до 400 пикселей по ширине, а затем проверять результат на реальном экране. Для печати важнее не число пикселей само по себе, а физический размер и разрешение. При разрешении 300 точек на дюйм изображение шириной 600 пикселей напечатается примерно на 5 сантиметров.
Если тот же файл растянуть без учёта качества, края модулей могут стать размытыми.
Базовые правила читаемости просты:
- используйте тёмный код на светлом фоне;
- оставляйте свободную рамку вокруг изображения;
- не размещайте код поверх фотографии без однотонной подложки;
- не растягивайте изображение отдельно по ширине или высоте;
- не применяйте чрезмерное скругление и декоративные фильтры;
- проверяйте код после сохранения и после вставки на страницу.
Цветной QR-код возможен, но цвет модулей должен оставаться заметно темнее фона. Красивый тёмно-синий код на белом фоне обычно работает, а жёлтый на белом - уже сомнительный вариант. Особенно опасны градиенты, металлические эффекты и полупрозрачность.
Камера воспринимает их иначе при разном освещении, поэтому код, который "идеально сканируется" на мониторе дизайнера, может не работать на витрине или упаковке.
Для настройки цвета в qrcode можно использовать RGB-значения:
import qrcode
qr = qrcode.QRCode(
version=None,
box_size=12,
border=4
)
qr.add_data("https://site.example/app")
qr.make(fit=True)
image = qr.make_image(
fill_color=(20, 40, 80),
back_color=(255, 255, 255)
)
image.save("app_qr.png")
Обратите внимание на три больших квадратных маркера по углам QR-кода. Их нельзя перекрывать текстом, логотипом или декоративной рамкой. Они помогают определить положение и ориентацию матрицы.
Если дизайнер хочет добавить подпись, разместите её под кодом, а не внутри рабочей области.
Работа с URL, параметрами и динамическими ссылками
В интернет-проектах QR-код чаще всего используется как переход на страницу. Здесь важно заранее продумать структуру адреса. В код можно зашить прямую ссылку на товар, короткий редирект, страницу кампании или специальный URL для мобильного пользователя.
Наиболее гибкий вариант - адрес собственного сервера, который затем перенаправляет посетителя на нужную страницу.
Например, вместо длинного адреса с десятками параметров можно использовать компактную ссылку:
https://site.example/r/summer
Сервер по этому маршруту определяет кампанию, записывает факт перехода и отправляет пользователя на целевую страницу. Такой подход даёт несколько преимуществ:
- можно изменить конечный адрес после печати материала;
- можно считать количество сканирований;
- можно различать источники трафика;
- можно отключить устаревшую акцию;
- можно показать разные страницы в зависимости от устройства или региона.
Если используются UTM-параметры, формируйте URL корректно. Значения нужно кодировать, особенно если в них есть пробелы, кириллица, амперсанды или специальные символы:
from urllib.parse import urlencode
params = {
"utm_source": "qr",
"utm_medium": "offline",
"utm_campaign": "summer_sale"
}
query = urlencode(params)
url = f"https://site.example/promo?{query}"
print(url)
Затем переменную url можно передать генератору QR-кода. Не вставляйте в него пароль, секретный токен администратора или персональные данные без необходимости. QR-код легко сфотографировать, а зашитая информация фактически становится публичной.
Даже если ссылка выглядит непонятно, её содержимое можно прочитать специализированным приложением.
Сокращение URL полезно не только для эстетики. Длинная ссылка увеличивает количество модулей и делает QR-код плотнее. При одинаковом размере физического изображения это снижает размер одного модуля, а значит, ухудшает считывание.
Если короткий адрес ведёт на серверный редирект, код получается проще и устойчивее.
Но редиректы нужно защищать от злоупотреблений. Если приложение принимает конечный URL от пользователя и перенаправляет куда угодно, оно может превратиться в открытый редиректор, который используют для фишинга.
Лучше хранить разрешённые назначения в базе данных, проверять домены и не принимать произвольные адреса из публичной формы без модерации.
Создание QR-кода в веб-приложении
Для сайта генератор должен не просто сохранять картинку на диск, а возвращать её браузеру или размещать в объектном хранилище. Рассмотрим простой вариант на Flask. Изображение создаётся в памяти через BytesIO, поэтому временный файл не нужен.
from io import BytesIO
import qrcode
from flask import Flask, request, send_file
app = Flask(name)
@app.get("/qr")
def make_qr():
text = request.args.get("text", "").strip()
if not text:
return {"error": "Параметр text обязателен"}, 400
qr = qrcode.QRCode(
version=None,
box_size=10,
border=4,
error_correction=qrcode.constants.ERROR_CORRECT_M
)
qr.add_data(text)
qr.make(fit=True)
image = qr.make_image(fill_color="black", back_color="white")
buffer = BytesIO()
image.save(buffer, format="PNG")
buffer.seek(0)
return send_file(
buffer,
mimetype="image/png",
download_name="qr.png"
)
if name == "main":
app.run(debug=True)
Теперь запрос к маршруту /qr с параметром text вернёт PNG-файл. В настоящем проекте debug=True нельзя оставлять включённым на публичном сервере. Также следует задать ограничение на длину входной строки.
Без него злоумышленник может отправлять огромные значения, заставляя приложение строить чрезмерно плотные изображения и тратить процессорное время.
Для отображения в HTML можно использовать обычный тег img:
<img src="/qr?text=https%3A%2F%2Fsite.example%2Fpromo"
alt="QR-код страницы акции"
width="300"
height="300">
Но открытая передача текста в URL имеет нюансы. В строке появятся экранированные символы, а браузер и сервер будут отдельно обрабатывать параметры. В административной панели лучше отправлять данные методом POST, проверять права доступа и возвращать готовое изображение по одноразовому идентификатору.
Для пользовательской страницы можно ограничить генерацию только URL домена сайта.
Если проект использует Django, общая схема не меняется: создаётся QRCode, результат сохраняется в BytesIO, а затем возвращается через HttpResponse с content type image/png.
В FastAPI можно вернуть StreamingResponse. Главное - не привязывать генерацию к локальной файловой системе, если приложение запускается в нескольких контейнерах. Файл, сохранённый в одном контейнере, может быть недоступен другому экземпляру.
При высокой нагрузке используйте кэширование. Один и тот же QR-код для одной и той же строки всегда будет одинаковым при одинаковых настройках.
Можно вычислить хеш входных данных и параметров, сохранить изображение в кэше или объектном хранилище и не пересоздавать его при каждом запросе. Это снижает нагрузку на CPU и ускоряет отдачу статических файлов.
Генерация SVG и использование в интерфейсе
PNG удобен почти везде, но для сайтов и печати иногда лучше SVG. Это векторный формат: изображение можно масштабировать без потери резкости. Модули остаются геометрически чёткими, что особенно полезно для больших плакатов, баннеров и адаптивных интерфейсов.
SVG также обычно занимает мало места, если QR-код состоит из простых прямоугольников. Однако его нельзя бездумно принимать от пользователя и вставлять в HTML.
SVG способен содержать дополнительные элементы и сценарии, если файл создаётся небезопасным способом. Генерируйте SVG проверенной библиотекой, очищайте пользовательские данные и отдавайте файл с корректным MIME-типом.
Для python-barcode можно использовать SVGWriter:
import barcode
from barcode.writer import SVGWriter
code_class = barcode.get_barcode_class("code128")
code = code_class("ORDER-4821", writer=SVGWriter())
code.save("order_svg")
Для QR-кодов выбор формата зависит от задачи. PNG проще показать в письме, сохранить в CMS и отправить через API. SVG лучше подходит для редактора макетов, печатных материалов и интерфейсов, где код должен хорошо выглядеть на экранах с разной плотностью пикселей.
Иногда удобно отдавать оба варианта: растровый для скачивания и векторный для дизайнера.
При вставке SVG в страницу сохраняйте альтернативный текст:
<img src="/static/qr/promo.svg"
alt="QR-код: переход на страницу акции"
width="280"
height="280">
Alt не заменяет сам код для пользователя, который не может его отсканировать, но улучшает доступность. Рядом полезно разместить обычную текстовую ссылку. Это хороший UX: посетитель может перейти на страницу кликом, а QR-код остаётся удобным вариантом для второго устройства.
Добавление логотипа и дизайн без потери надёжности
Логотип в центре QR-кода помогает связать изображение с брендом, но он же часто становится причиной ошибок сканирования.
Нельзя просто наложить картинку поверх матрицы и надеяться на высокий уровень коррекции. Нужно контролировать площадь перекрытия, контраст и наличие белой подложки между логотипом и модулями.
Пример добавления небольшого логотипа с Pillow:
from PIL import Image, ImageOps
qr = Image.open("promo.png").convert("RGBA")
logo = Image.open("logo.png").convert("RGBA")
max_size = qr.width // 5
logo.thumbnail((max_size, max_size))
padding = 12
logo_box = Image.new(
"RGBA",
(logo.width + padding * 2, logo.height + padding * 2),
"white"
)
logo_box.alpha_composite(logo, (padding, padding))
position = (
(qr.width - logo_box.width) // 2,
(qr.height - logo_box.height) // 2
)
qr.alpha_composite(logo_box, position)
qr.convert("RGB").save("promo_logo.png")
Размер логотипа здесь ограничен примерно пятой частью ширины. Это не универсальное правило, а безопасная стартовая точка. После наложения код обязательно проверяют несколькими камерами и при разном расстоянии.
Если логотип нужен только для визуального эффекта, его лучше сделать меньше, чем рисковать функциональностью.
Не изменяйте три угловых маркера, не превращайте квадратные модули в слишком округлые элементы и не добавляйте декоративную рамку вплотную к матрице. Хороший дизайн QR-кода строится вокруг читаемости, а не наоборот.
В рекламной кампании можно провести A/B-тест: сравнить обычный чёрно-белый код с брендированным и измерить не только клики, но и долю успешных сканирований.
Есть смысл тестировать код в реальных условиях:
- при ярком дневном освещении;
- в помещении с тусклым светом;
- на старом телефоне с не самой быстрой камерой;
- с экрана ноутбука и с экрана смартфона;
- после печати на обычном офисном принтере;
- на фоне упаковки, плаката или наклейки.
Если код будет размещён на улице, добавьте запас по размеру и контрасту. Дождь, блики, пыль, изгиб поверхности и выцветание заметно ухудшают распознавание.
Для изогнутой бутылки или небольшого стикера лучше использовать короткий URL, высокий контраст и достаточно крупные модули.
Проверка данных, безопасность и защита генератора
Открытая форма генерации кодов может использоваться для спама, фишинга и перегрузки сервера. Поэтому обработка входных данных должна быть такой же строгой, как в любом публичном API.
Не принимайте неограниченный текст, не разрешайте бесконечное число запросов и не доверяйте расширению файла, переданному клиентом.
Минимальный набор мер защиты включает:
- ограничение длины текста, например несколькими тысячами символов;
- проверку схемы URL и разрешённых доменов;
- ограничение частоты запросов с одного IP или аккаунта;
- защиту административных маршрутов авторизацией;
- кэширование одинаковых результатов;
- журналирование ошибок и подозрительной активности;
- отключение режима отладки в рабочей среде.
Если QR-код создаётся по ссылке пользователя, используйте urllib.parse для разбора адреса и проверяйте hostname. Простая проверка по подстроке недостаточна: строка может содержать доверенный домен в начале и настоящий вредоносный адрес после символа @ или в другом компоненте URL.
Для критичных сценариев лучше хранить идентификатор объекта, а не принимать полный внешний адрес.
Особое внимание уделите персональным данным. Код на бейдже сотрудника, транспортной накладной или клиентском документе может содержать имя, телефон, адрес и внутренний номер. Любой человек с камерой получит эти сведения.
Лучше зашивать короткий случайный идентификатор, а детали показывать после авторизации или по одноразовой ссылке.
При генерации изображения с пользовательским логотипом действуют дополнительные риски. Не позволяйте серверу загружать файлы любых форматов и бесконтрольно обрабатывать огромные изображения.
Проверяйте фактический тип файла, ограничивайте размер, уменьшайте изображение до разумных габаритов и по возможности преобразуйте его в безопасный растровый формат. Это защищает от проблем с памятью и неожиданными вложенными данными.
Для QR-кода, ведущего на страницу оплаты или входа, обязательно используйте HTTPS. Но сам HTTPS не гарантирует, что адрес не заменили на поддельный при печати или в рекламном макете.
Перед публикацией проверяйте итоговый файл, а для важных материалов применяйте процедуру согласования: сотрудник сканирует код и сверяет домен, страницу и параметры кампании.
Тестирование, аналитика и типичные ошибки
Тестирование нужно проводить на нескольких уровнях. Сначала проверяется содержимое: после декодирования строка должна в точности совпадать с ожидаемой. Затем проверяется изображение: размер, формат, наличие свободной зоны, цветовой контраст.
После этого выполняется физический тест камерой и, если код печатается массово, сканером, который будет использоваться на складе или кассе.
Для автоматической проверки можно применять библиотеку OpenCV и детектор QR-кодов, но такой тест не заменяет реальные устройства.
Программный декодер может быть терпимее или строже конкретной камеры. Полезно иметь набор тестов с коротким URL, длинной строкой, кириллицей, специальными символами, параметрами запроса и пустым значением.
import qrcode
test_values = [
"https://site.example",
"https://site.example/promo?utm_source=qr",
"Тестовая строка",
"ORDER-4821",
]
for index, value in enumerate(test_values, start=1):
qr = qrcode.QRCode(box_size=8, border=4)
qr.add_data(value)
qr.make(fit=True)
image = qr.make_image()
image.save(f"test_{index}.png")
Самые распространённые ошибки выглядят так:
- в QR-код записывают слишком длинный URL;
- убирают белую рамку, чтобы "сэкономить место";
- растягивают PNG непропорционально;
- используют низкий контраст;
- закрывают центр крупным логотипом;
- печатают изображение слишком маленьким;
- публикуют ссылку с ошибкой, которую уже невозможно исправить;
- не проверяют редирект и срок действия страницы;
- не добавляют обычную ссылку для пользователей без камеры;
- не ограничивают публичный API генерации.
Аналитика должна учитывать не только сам факт перехода, но и источник, кампанию, устройство, время и конверсию.
Для этого используют разные короткие маршруты или UTM-параметры. Если один и тот же код размещён на витрине, визитке и плакате, статистика будет смешиваться. Лучше генерировать отдельный адрес для каждого места размещения.
Нужно помнить, что статистика сканирований не всегда равна числу людей. Один пользователь может открыть ссылку несколько раз, автоматические системы могут загружать URL, а часть камер показывает превью без фактического перехода.
Поэтому анализируйте цепочку: обращение к редиректу, загрузка страницы, активность на странице и целевое действие. В интернет-маркетинге QR-код источник трафика, а не самостоятельный показатель успеха.
Организация генератора в реальном проекте
В небольшом скрипте можно собрать всё в одном файле, но в рабочем интернет-сервисе лучше разделить ответственность. Отдельный модуль принимает и проверяет данные, другой создаёт QR-код, третий отвечает за хранение и кэширование, а веб-слой занимается авторизацией и HTTP-ответом.
Такая структура упрощает тестирование и позволяет заменить PNG на SVG без переделки всей системы.
Удобно описать параметры генерации отдельным объектом:
from dataclasses import dataclass
@dataclass
class QRSettings:
box_size: int = 10
border: int = 4
error_level: int = 0
foreground: str = "black"
background: str = "white"
Затем функция-генератор получает строку и настройки, а не читает значения напрямую из HTTP-запроса. В таком случае один и тот же код легко использовать в веб-приложении, фоновой задаче, командной утилите и тестах.
Для хранения результата можно вычислять ключ из содержимого:
import hashlib
def qr_key(data: str, settings: str = "default") -> str:
raw = f"{settings}:{data}".encode("utf-8")
return hashlib.sha256(raw).hexdigest()
Полученный хеш подходит для имени файла или ключа в кэше. Не используйте сам URL как имя файла: в нём могут быть слэши, вопросительные знаки, кириллица и слишком большая длина. При этом хеш не должен подменять проверку доступа.
То, что файл трудно угадать, не означает, что его можно публиковать без ограничений.
Если генерация выполняется редко, достаточно синхронной функции. Если пользователи создают большие серии кодов, например тысячу этикеток для каталога, работу лучше отправлять в очередь. Фоновая задача создаёт изображения, собирает архив и уведомляет пользователя о готовности.
Это предотвращает тайм-аут веб-запроса и позволяет контролировать нагрузку.
Для серийной печати пригодится PDF или SVG-шаблон, но сам QR-код нужно размещать без дополнительного сглаживания. При экспорте макета дизайнерские программы иногда меняют масштаб изображения или добавляют прозрачные эффекты.
Финальный PDF обязательно проверяют после экспорта, а не только исходный PNG.
Практический пример- QR-код для интернет-магазина
Представим карточку товара с идентификатором 4821. Магазин хочет разместить код на упаковке и в печатной инструкции. В QR-код не нужно записывать название, цену и полное описание: эти данные могут измениться. Достаточно короткого адреса, связанного с товаром:
product_url = "https://shop.example/p/4821"
На сервере этот адрес показывает актуальную карточку, определяет язык интерфейса, проверяет наличие товара и записывает источник перехода. Для печати можно добавить отдельный параметр:
product_url = "https://shop.example/p/4821?utm_source=package"
Генератор:
import qrcode
from io import BytesIO
def create_product_qr(product_id: int) -> BytesIO:
url = f"https://shop.example/p/{product_id}"
qr = qrcode.QRCode(
version=None,
error_correction=qrcode.constants.ERROR_CORRECT_Q,
box_size=12,
border=4
)
qr.add_data(url)
qr.make(fit=True)
image = qr.make_image(
fill_color=(15, 15, 15),
back_color=(255, 255, 255)
)
result = BytesIO()
image.save(result, format="PNG")
result.seek(0)
return result
В этом примере выбран уровень Q, потому что упаковка может иметь небольшие потёртости и неровную поверхность. Но выбор уровня не отменяет требований к размеру.
Если код печатается на коробке шириной 30 сантиметров, его можно сделать крупным. Если тот же код помещают на маленькую наклейку, лучше сократить URL, убрать лишние параметры и провести отдельную проверку.
Сценарий можно расширить. Администратор загружает CSV-файл с товарами, приложение проверяет идентификаторы, создаёт QR-коды с едиными настройками и формирует архив.
Для каждого изображения сохраняется связь с товаром, датой создания и версией шаблона. Если спустя год потребуется повторить печать, система выдаст тот же адрес или предупредит, что карточка товара больше не существует.
Хорошая практика - показывать администратору предпросмотр и кнопку "Проверить". При нажатии сервис декодирует созданное изображение или предлагает открыть ссылку, а сотрудник подтверждает результат. Такая лишняя минута часто спасает тираж от ошибки в одной цифре.
Краткий выбор технологии и рекомендации
Для QR-кода со ссылкой используйте qrcode, автоматически подбирайте версию и начинайте с чёрного изображения на белом фоне. Для товарного EAN-13 применяйте специализированный генератор и обязательно проверяйте контрольную цифру. Для внутренних наклеек и заказов чаще подходит Code 128.
Если изображение должно масштабироваться без потери качества, рассмотрите SVG.
| Задача | Рекомендуемый вариант | На что обратить внимание |
|---|---|---|
| Переход с бумажной рекламы | QR-код с коротким URL | Редирект, аналитика, контраст |
| Идентификация товара | EAN-13 или Code 128 | Стандарт, контрольная цифра, размер |
| Складская маркировка | Code 128 или QR-код | Сканер, расстояние, устойчивость печати |
| Большой плакат | SVG или качественный PNG | Физический размер, векторная резкость |
| Код с логотипом | QR с уровнем Q или H | Небольшая зона логотипа и тестирование |
Главная мысль проста: код должен быть не украшением, а надёжным интерфейсом между физическим носителем и интернет-сервисом. Сначала проектируют маршрут пользователя и данные, затем выбирают формат, после этого настраивают изображение и только в конце занимаются дизайном.
Такой порядок экономит время и снижает риск получить красивый, но неработающий результат.
Python позволяет закрыть весь цикл - от одной строки кода до массовой генерации изображений в веб-приложении.
Библиотеки берут на себя техническую часть, а разработчику остаются архитектура, безопасность, валидация и тестирование.
Если использовать короткие динамические ссылки, сохранять свободную зону, соблюдать контраст и проверять финальные файлы на реальных устройствах, QR-коды и штрихкоды станут полноценным инструментом сайта: будут приводить посетителей, связывать товары с каталогом и помогать автоматизировать работу интернет-бизнеса.
Частые вопросы
Можно ли создать QR-код без установки сторонних сервисов? Да. Библиотека qrcode генерирует изображение локально, поэтому текст или ссылка не отправляются внешнему сервису.
Это удобно для конфиденциальных данных, но ответственность за защиту и проверку результата лежит на разработчике.
Почему QR-код не сканируется с экрана? Чаще всего причина в маленьком размере, низком контрасте, отсутствии свободной рамки, слишком длинных данных или декоративных элементах. Увеличьте изображение, верните белую зону, используйте короткий URL и проверьте код без логотипа.
Можно ли изменить ссылку после печати QR-кода? Можно, если код ведёт на собственный короткий адрес или редирект. Если в изображение зашит конечный адрес напрямую, изменить его уже нельзя: потребуется создать и напечатать новый код.