2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00
2026-10-01 00:28:16 +10:00

Parser Lab

Учебный сайт для сбора данных: преподаватель импортирует CSV, JSON или JSONL, выбирает оформление и публикует две версии страниц — обычный HTML с пагинацией и HTML с динамической дозагрузкой. Приложение работает на FastAPI, Jinja2, HTML, CSS и небольших JavaScript-модулях без UI-фреймворков. Один аккаунт преподавателя; студентам вход не нужен.

Быстрый запуск через Docker

Нужны Docker Engine с Compose либо Docker Desktop. Запускайте команды из папки проекта.

  1. Скопируйте .env.example в .env и соберите образ:

    docker compose build
    
  2. Укажите логин и обычный пароль (не менее 10 символов) в .env:

    LAB_ADMIN_USER=teacher
    LAB_ADMIN_PASSWORD='ваш-пароль-для-входа'
    

    Одинарные кавычки сохраняют символы $, пробелы и #. Если пароль содержит кавычки или обратные слеши, используйте uv run --locked python -m parser_lab.cli init-env для создания корректного .env вместо ручного копирования шаблона.

  3. Создайте случайный секрет:

    docker compose run --rm --no-deps app uv run --no-sync python -c "import secrets; print(secrets.token_urlsafe(48))"
    

    Поместите значение в LAB_SECRET. Не используйте пароль как секрет.

  4. Для локальной проверки оставьте LAB_ORIGINS=http://localhost:8080 и LAB_SECURE_COOKIE=false. Запустите:

    docker compose up -d
    docker compose ps
    

Откройте кабинет. Проверка сервиса: healthz.

Если меняете порт, например на 8087, измените одновременно LAB_PORT=8087 и LAB_ORIGINS=http://localhost:8087. Имя хоста тоже имеет значение: localhost и 127.0.0.1 — разные origin. Через запятую можно указать несколько разрешённых адресов.

Размещение в интернете

Разместите приложение в корне отдельного домена, например https://lab.example.org. Установите:

LAB_ORIGINS=https://lab.example.org
LAB_SECURE_COOKIE=true

Передайте домен на reverse proxy с HTTPS. Пример nginx, если приложение доступно прокси на порту 8080:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    client_max_body_size 26m;
}

TLS-сертификат и DNS настраиваются на вашем сервере. Ограничьте прямой доступ к порту приложения средствами сервера или привяжите порт в Compose к 127.0.0.1, если прокси находится на той же машине. Подкаталоги вида /my-lab/ и несколько реплик приложения не поддерживаются первой версией.

Как опубликовать данные

  1. Войдите в кабинет и нажмите «Загрузить данные».
  2. Загрузите файл. При необходимости выберите кодировку и разделитель CSV либо массив записей внутри JSON.
  3. Нажмите «Проверить файл»: появятся количество записей, предупреждения и первые 20 строк. Сохраните импорт.
  4. Выберите представление и включите его. Отметьте поля, задайте подписи, порядок, поиск и категориальный фильтр. Для карточек назначьте заголовок; для сообщений — текст, при желании автора и дату.
  5. Проверьте живой предпросмотр, сохраните черновик и откройте полный предпросмотр.
  6. Опубликуйте версию. В разделе публикаций появятся ссылки для студентов.

Один набор может иметь все четыре представления. Изменения черновика не затрагивают опубликованные данные. Повторная публикация создаёт новые ссылки с номером версии; прежние продолжают работать. Снятие версии с публикации делает её недоступной. Уже скачанные студентом данные, разумеется, не исчезают.

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

Форматы файлов

Формат Поддержка
CSV Первая строка — уникальные непустые заголовки; UTF-8 или Windows-1251; запятая, точка с запятой или табуляция
JSON Массив объектов, одиночный объект или выбранный вложенный массив объектов
JSONL По одному объекту JSON в каждой непустой строке; UTF-8

Лимиты по умолчанию: 25 МиБ, 50 000 записей, глубина JSON 20. Размер файла и количество записей можно изменить через LAB_MAX_BYTES и LAB_MAX_RECORDS. Большие наборы требуют больше памяти: текущая версия хранит JSON-снимки в SQLite и загружает снимок для выборки. Проверяйте скорость на своих данных до занятия.

Дубликаты и исходный порядок сохраняются. Значения CSV остаются строками, чтобы не потерять ведущие нули и исходное представление чисел. В JSON различаются отсутствие поля, null, пустая строка, false и 0. Ошибки формата блокируют импорт; повреждённые строки не пропускаются молча. Пустой набор не публикуется.

Вложенные поля показаны путями: /profile/age означает поле age в объекте profile. Символ / в самом имени поля кодируется как ~1, а ~ — как ~0. Массивы сохраняются; специальные анкеты могут отображать их как пары вопросов и ответов.

Заполненные анкеты

Для таблицы с колонками participant, q1, q2 выберите «Колонки с ответами» и замените подписи q1/q2 текстами вопросов.

Для examples/data/questionnaires.json достаточно выбрать файл, нажать «Проверить файл» и «Сохранить и настроить». Приложение распознаёт участников и пары question/answer, выбирает /participants и создаёт готовое представление «Анкеты». Предпросмотр сразу показывает двух участников и их ответы. Распознавание зависит от структуры данных, а не имени файла.

Если структура неоднозначна, выберите уровень записей вручную. Для ранее загруженного целиком документа в редакторе доступна кнопка «Настроить анкеты автоматически»: она исправляет черновик без повторной загрузки исходного файла. Опубликованные версии сохраняются.

Сайт отображает готовые данные; он не собирает ответы и не интерпретирует психологические шкалы. Дополнительные примеры синтетические. Хоккейный CSV перенесён из предыдущего проекта.

Парсинг

Адреса имеют вид:

/html/study-abc/v/1/table
/interactive/study-abc/v/1/table

Для HTML данные находятся в исходном ответе сервера. Пагинация — ?page=2, следующая ссылка — a[rel=next]. Стабильные селекторы:

Селектор Значение
.record[data-record-id] Запись со стабильным в пределах версии id
.field[data-field] Значение выбранного поля
data-value-state missing, null или value
data-value-type Исходный тип: string, number, boolean, object, array, null или missing
data-role Роль значения: title, text, author или date
data-label Подпись поля или текст вопроса
.detail-link Ссылка на отдельную запись

Фильтры HTML: q — регистронезависимый поиск в назначенном поле, category — JSON-представление скалярного значения. Формы на странице формируют правильные параметры автоматически. Поиск не выполняет морфологический анализ. При неправильном номере страницы возвращается 400, при отсутствии страницы или версии — 404.

В динамическом варианте первые записи также находятся в HTML-ответе. Кнопка «Загрузить ещё», поиск и фильтры обновляют данные обычными HTTP-запросами через JavaScript. Для практики браузерного парсинга используйте Playwright. Оба варианта используют один шаблон, стили и favicon.

Примеры решений находятся в examples/parsers/ и не доступны как файлы через публичный сайт:

uv sync --locked
uv run --locked playwright install chromium
uv run --locked python examples/parsers/scrape_html.py "http://localhost:8080/html/SLUG/v/1/table" --output html.jsonl
uv run --locked python examples/parsers/scrape_interactive.py "http://localhost:8080/interactive/SLUG/v/1/table" --output interactive.jsonl

Вместо загруженного Chromium можно использовать установленный Chrome: добавьте --channel chrome второму парсеру.

Обновление и резервная копия

Данные находятся в named volume lab-data, смонтированном в /data. docker compose down сохраняет том. Не используйте down -v, если данные нужны.

Обновление:

docker compose down
docker compose build
docker compose up -d

Перед обновлением остановите контейнер и скопируйте весь каталог данных:

docker compose stop app
docker compose cp app:/data ./backup-data
docker compose start app

Храните копию вместе с защищённой копией .env. Для восстановления подготовьте отдельный Compose-проект с новым томом, создайте его контейнер (docker compose create), скопируйте содержимое backup-data в /data, восстановите владельца UID 10001 при необходимости и запустите контейнер. Проверяйте восстановление отдельно от рабочего сайта.

Импортированные файлы и старые снимки не удаляются автоматически. Следите за размером тома. Безвозвратное удаление истории не входит в интерфейс первой версии.

Локальная разработка

Нужен uv версии 0.8.14 или новее. Python 3.12 и окружение .venv управляются через uv. Запускайте команды из корня проекта:

uv sync --locked
uv run --locked python -m parser_lab.cli init-env
uv run --locked --env-file .env python -m parser_lab

init-env один раз создаёт .env и запрашивает параметры преподавателя. При последующих запусках достаточно последней команды. Активация окружения не требуется.

Зависимости приложения и группа dev описаны в pyproject.toml, точные версии зафиксированы в uv.lock. Для изменения зависимостей используйте uv add ИМЯ или uv add --dev ИМЯ; сохраняйте оба файла в Git. Устаревшие requirements*.lock больше не используются. Docker собирает production-окружение командой uv sync --locked --no-dev и запускает готовое окружение через uv run --no-sync.

Параметры окружения имеют приоритет над локальной .env. Пароль LAB_ADMIN_PASSWORD и секрет LAB_SECRET обязательны, приложение откажется запускаться без них. После изменения пароля или секрета перезапустите приложение (для Docker: docker compose up -d --force-recreate); старые сессии станут недействительны.

Тесты:

uv run --locked pytest -q
# Дополнительные браузерные тесты: LAB_BROWSER_TESTS=1, при необходимости PLAYWRIGHT_CHANNEL=chrome.

Старые документы проектирования в docs/ сохранены как история. Актуальная архитектура — FastAPI + Jinja2 + HTML/CSS/JavaScript; зависимости Rio полностью удалены. Существующие SQLite-данные и опубликованные ссылки совместимы с новой версией. Фактические результаты проверки и ограничения среды — в docs/verification.md.

Справка: uv в Docker, запуск команд.

Пароль хранится в .env обычным текстом. Внутренний Argon2-хеш для проверки входа приложение создаёт в памяти при запуске. Если .env остался от предыдущей версии, замените строку LAB_ADMIN_HASH=... на LAB_ADMIN_PASSWORD='ваш-пароль'; прежний хеш больше не используется. .env исключён из Git и Docker-образа.

S
Description
Конструктор сайта для парсинга из csv, json, jsonl
Readme
369 KiB
Languages
Python 73.6%
HTML 13.4%
JavaScript 12.4%
Dockerfile 0.6%