Skip to content

AlexBSoft/chtodata

Repository files navigation

Что?Data (ChtoData)

Открытый бесплатный сервис обработки данных для рунета — альтернатива DaData.

Публичный экземпляр доступен бесплатно: chtodata.ru. При желании сервис можно развернуть у себя (см. раздел «Быстрый старт»).

Сейчас доступен один модуль — очистка и разбор телефонных номеров. На вход подаётся произвольная строка (хоть «грязный» текст с номером, хоть номер в любом региональном формате), на выходе — структурированный объект в формате, совместимом с DaData.

Российские номера дополнительно обогащаются данными из официального реестра Минцифры (оператор, регион, город), который сервис скачивает и актуализирует автоматически.

  • Разбор номеров через phonenumbers (порт google/libphonenumber).
  • База операторов/регионов из opendata.digital.gov.ru в SQLite (≈ 446 тыс. диапазонов).
  • Извлечение номера из «грязного» текста и добавочного номера (доб., *, #, ext и т.п.).
  • Международные номера тоже разбираются (страна/город/таймзона из встроенных баз phonenumbers).
  • FastAPI, встроенный планировщик обновлений, Docker.

Быстрый старт

Локально (Python 3.12+)

python -m venv .venv
# Windows:
.venv\Scripts\activate
# Linux/macOS:
source .venv/bin/activate

pip install -r requirements.txt

# Собрать базу из локальных CSV (data/mincifry-phones/) ...
python scripts/build_db.py
# ... или скачать свежие данные и собрать:
python scripts/build_db.py --download

# Запустить сервер
uvicorn app.main:app --host 0.0.0.0 --port 8000

Откройте http://localhost:8000/ — страница документации, http://localhost:8000/swagger — Swagger UI.

При первом запуске, если базы ещё нет, сервис сам соберёт её из локальных CSV (data/mincifry-phones/), а при их отсутствии — скачает с opendata.digital.gov.ru.

Docker

docker compose up --build

База registry.db сохраняется в томе ./data между перезапусками. При первом старте с пустым томом данные скачиваются автоматически.


API

POST /api/v1/clean/phone

Тело запроса — JSON-массив строк. Ответ — JSON-массив объектов в том же порядке. Авторизация не требуется.

curl -X POST http://localhost:8000/api/v1/clean/phone \
     -H "Content-Type: application/json" \
     -d '["раб 846)231.60.14 *139"]'

Ответ:

[
  {
    "source": "раб 846)231.60.14 *139",
    "type": "Стационарный",
    "phone": "+7 846 231-60-14 доб. 139",
    "country_code": "7",
    "city_code": "846",
    "number": "2316014",
    "extension": "139",
    "provider": "ООО \"СИПАУТНЭТ\"",
    "country": "Россия",
    "country_iso": "ru",
    "region": "Самарская область",
    "city": "Самара",
    "timezone": "UTC+4",
    "qc_conflict": 0,
    "qc": 0
  }
]

Поля ответа

Поле Описание
source Исходная строка, как пришла на вход
type Тип: «Мобильный», «Стационарный», «Бесплатный» и т.п.
phone Нормализованный номер (+7 846 231-60-14 доб. 139)
country_code Код страны (7)
city_code Код города / DEF-код (846)
number Локальный номер без кода города
extension Добавочный номер
provider Оператор связи (из реестра Минцифры)
country Страна (Россия, Казахстан, Соединенные Штаты, …)
country_iso Двухбуквенный код страны ISO 3166-1 (ru, us, kz)
region Регион / субъект РФ (для зарубежных номеров пусто)
city Город / населённый пункт
timezone Часовой пояс (UTC+4)
qc_conflict Код конфликта (всегда 0 в текущей версии)
qc Код качества: 0 — распознан, 1 — не распознан

Служебные эндпоинты

Метод и путь Назначение
GET /api/health Состояние сервиса и число записей в базе
POST /api/admin/refresh Ручное обновление базы (требует токен; по умолчанию отключено)
GET /swagger Интерактивная OpenAPI-документация
GET / и /docs Страница документации на русском

Конфигурация (переменные окружения)

Все параметры — с префиксом CHTODATA_.

Переменная По умолчанию Назначение
CHTODATA_HOST 0.0.0.0 Хост сервера
CHTODATA_PORT 8000 Порт сервера
CHTODATA_DATA_DIR ./data Каталог данных (база)
CHTODATA_CSV_DIR ./data/mincifry-phones Локальные CSV реестра
CHTODATA_UPDATE_ENABLED true Включить автообновление базы
CHTODATA_UPDATE_INTERVAL_DAYS 7 Период автообновления, дни
CHTODATA_DOWNLOAD_TIMEOUT 180 Таймаут скачивания одного CSV, сек
CHTODATA_DOWNLOAD_RETRIES 3 Число попыток скачать CSV при сбоях
CHTODATA_MIN_ROWS 100000 Порог «вменяемости» базы: ниже — обновление отклоняется
CHTODATA_LOG_LEVEL INFO Уровень логов (DEBUG/INFO/WARNING/ERROR)
CHTODATA_SITE_URL https://chtodata.ru Канонический адрес сайта для SEO/OpenGraph
CHTODATA_ADMIN_TOKEN (пусто) Токен для POST /api/admin/refresh; пусто = эндпоинт отключён

Ручное обновление при заданном токене:

curl -X POST "http://localhost:8000/api/admin/refresh?download=true" \
     -H "X-Admin-Token: ВАШ_ТОКЕН"

Как это работает

  1. Разбор. Добавочный номер вычленяется из конца строки, затем номер парсится через phonenumbers. Если строка — «грязный» текст, номер ищется внутри неё.
  2. Обогащение (РФ). Российский номер из 10 цифр делится на код (3 цифры) и локальный номер (7 цифр) — так устроен реестр Минцифры. По коду и попаданию в диапазон находится оператор, регион и город; при пересечении диапазонов побеждает самый узкий. Часовой пояс берётся по региону.
  3. Международные. Страна, город и часовой пояс определяются встроенными базами phonenumbers.

База Минцифры хранится в SQLite (data/registry.db) и обновляется по расписанию: 4 CSV скачиваются с opendata.digital.gov.ru, собирается новая база и атомарно подменяет рабочую.

  • Автообновление базы раз в неделю (настраивается CHTODATA_UPDATE_INTERVAL_DAYS). Если VPS долго был выключен или часто перезагружается, при старте проверяется свежесть базы и устаревшая обновляется в фоне — таймер не «теряется».
  • Скачивание с повторными попытками (CHTODATA_DOWNLOAD_RETRIES) переживает кратковременные сетевые сбои.
  • Защита от «битого» обновления. Новая база собирается во временный файл и заменяет рабочую, только если прошла проверку: строк не меньше CHTODATA_MIN_ROWS и не вдвое меньше текущей. Иначе обновление отклоняется, сервис продолжает работать на последней успешной базе.
  • Сбои не роняют сервис. Любая ошибка обновления логируется, но API продолжает отвечать. Если данных нет вовсе (первый старт без сети) — номера разбираются через phonenumbers, без оператора/региона, а реестр подтянется при следующей попытке.
  • Перезапуск при сбоях и после ребутаrestart: unless-stopped в compose.
  • Ротация логов настроена в docker-compose.yml (max-size: 10m, max-file: 5), чтобы логи не заполнили диск.
  • Мониторинг. GET /api/health возвращает число записей, дату обновления базы (updated_at) и её возраст в днях (age_days) — удобно для внешних проверок.

Минимальный деплой:

git clone <repo> chtodata && cd chtodata
docker compose up -d --build

Дальше можно не вмешиваться: база скачается на старте и будет обновляться сама. Проверить состояние в любой момент: curl http://<vps>:8000/api/health.

Структура проекта

Код организован по модулям: ядро (app/core, app/main.py) ничего не знает о конкретных обработчиках, а каждый инструмент — самодостаточный пакет в app/modules/.

app/
  main.py              точка входа: подключает ядро и все модули из app.modules.MODULES
  config.py            общие настройки (env CHTODATA_*)
  module.py            контракт модуля (Module: роутер, хуки, health, документация)
  core/
    health.py          GET /api/health (агрегирует health всех модулей)
    web.py             страница документации (собирается из метаданных модулей)
  modules/
    __init__.py        MODULES = [phone_module]  ← сюда добавляются новые модули
    phone/             модуль «телефоны»
      __init__.py      объект Module (метаданные + хуки)
      source.py        источник данных и пути (реестр Минцифры)
      models.py        PhoneResult (формат ответа)
      parser.py        строка -> PhoneResult
      registry.py      сборка и поиск по SQLite-базе
      geo.py           регион/город/таймзона/тип номера
      updater.py       скачивание CSV, пересборка базы, планировщик, health
      router.py        эндпоинты модуля
  templates/           docs.html (оболочка) + modules/<name>.html (документация модуля)
  static/              стили, favicon, og-image
scripts/build_db.py    CLI сборки/обновления базы
data/mincifry-phones/  исходные CSV реестра

Как добавить новый модуль

  1. Создайте пакет app/modules/<name>/ с объектом module типа Module (название, описание, свой APIRouter, при необходимости хуки on_startup/on_shutdown, health, шаблон документации).
  2. Добавьте его в список MODULES в app/modules/init.py.

Ядро само подключит роутер, вызовет хуки жизненного цикла, добавит модуль в /api/health и на страницу документации. Править main.py не нужно.

Ограничения

  • Значения region, city, timezone — приближённые: формат ответа совпадает с DaData, но значения берутся из реестра Минцифры и могут немного отличаться (у DaData собственные геобазы). Для номеров, выделенных на несколько регионов, эти поля могут быть пустыми.
  • qc в текущей версии принимает значения 0 (распознан) и 1 (не распознан), qc_conflict всегда 0.

Лицензия

MIT. Проект открытый — PR и issue приветствуются.

About

Сервис обработки данных для рунета: разбор телефонов через API. Альтернатива DaData.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors