Открытый бесплатный сервис обработки данных для рунета — альтернатива DaData.
Публичный экземпляр доступен бесплатно: chtodata.ru. При желании сервис можно развернуть у себя (см. раздел «Быстрый старт»).
Сейчас доступен один модуль — очистка и разбор телефонных номеров. На вход подаётся произвольная строка (хоть «грязный» текст с номером, хоть номер в любом региональном формате), на выходе — структурированный объект в формате, совместимом с DaData.
Российские номера дополнительно обогащаются данными из официального реестра Минцифры (оператор, регион, город), который сервис скачивает и актуализирует автоматически.
- Разбор номеров через
phonenumbers(порт google/libphonenumber). - База операторов/регионов из opendata.digital.gov.ru в SQLite (≈ 446 тыс. диапазонов).
- Извлечение номера из «грязного» текста и добавочного номера (
доб.,*,#,extи т.п.). - Международные номера тоже разбираются (страна/город/таймзона из встроенных баз phonenumbers).
- FastAPI, встроенный планировщик обновлений, Docker.
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 compose up --buildБаза registry.db сохраняется в томе ./data между перезапусками. При первом старте
с пустым томом данные скачиваются автоматически.
Тело запроса — 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: ВАШ_ТОКЕН"- Разбор. Добавочный номер вычленяется из конца строки, затем номер парсится
через
phonenumbers. Если строка — «грязный» текст, номер ищется внутри неё. - Обогащение (РФ). Российский номер из 10 цифр делится на код (3 цифры) и локальный номер (7 цифр) — так устроен реестр Минцифры. По коду и попаданию в диапазон находится оператор, регион и город; при пересечении диапазонов побеждает самый узкий. Часовой пояс берётся по региону.
- Международные. Страна, город и часовой пояс определяются встроенными базами
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 реестра
- Создайте пакет
app/modules/<name>/с объектомmoduleтипаModule(название, описание, свойAPIRouter, при необходимости хукиon_startup/on_shutdown,health, шаблон документации). - Добавьте его в список
MODULESв app/modules/init.py.
Ядро само подключит роутер, вызовет хуки жизненного цикла, добавит модуль в
/api/health и на страницу документации. Править main.py не нужно.
- Значения
region,city,timezone— приближённые: формат ответа совпадает с DaData, но значения берутся из реестра Минцифры и могут немного отличаться (у DaData собственные геобазы). Для номеров, выделенных на несколько регионов, эти поля могут быть пустыми. qcв текущей версии принимает значения0(распознан) и1(не распознан),qc_conflictвсегда0.
MIT. Проект открытый — PR и issue приветствуются.