Нормализация базы контактов: что работает, а что нет
XLSX → VCF Конвертер«Программа сама всё сделает» — эту фразу повторяют в каждом описании конвертера. DataBaseNormalizer за несколько секунд делает 80% работы, а оставшиеся 20% — кривые ФИО, номера с потерянными цифрами, иностранные имена — всё равно потребуют проверки. Ниже — что автоматизировать безопасно, а где рассчитывать на неё опасно.
Откуда берётся хаос в базе
Типичная выгрузка из CRM или таблицы отдела продаж выглядит примерно так:
8(903)123-4567 мария продажа спб masha@test.ru
+7 999 888 77 66 | Иванов Иван Сергеевич | ivanov.IS@corp.com
79164445566 Ася Берг Москва
В одной ячейке — телефон, имя, email, заметки. Форматы номеров разные. Разделители разные. ФИО в разном порядке. Excel с этим справляется плохо: начинаешь чистить один столбец — ломается другой, числа превращаются в экспоненциальный вид 7,99E+10, а задача на 15 000 строк занимает неделю.
DataBaseNormalizer делает это за минуты. Но не волшебно — а через чёткую логику, которую нужно понимать.
Этап 1. Очистка и нормализация телефонов
Это единственный этап, который работает надёжно и без оговорок.
RegEx очищает строку от мусора:
import re
phone = re.sub(r"[^0-9+]", "", raw_string)
Скобки, дефисы, пробелы, буквы — всё вылетает. Остаётся голый номер.
Замена российского формата на E.164:
if phone.startswith("8") and len(phone) == 11:
phone = "+7" + phone[1:]
elif phone.startswith("7") and len(phone) == 11:
phone = "+" + phone
Логика проста: 8XXXXXXXXXX и 7XXXXXXXXXX из 11 цифр — российские номера, приводим к +7XXXXXXXXXX.
Валидация через phonenumbers (порт Google libphonenumber):
import phonenumbers
try:
parsed = phonenumbers.parse(phone, None)
if phonenumbers.is_valid_number(parsed):
clean = phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164)
else:
clean = None # уходит в лог ошибок
except:
clean = None
Номера с потерянными цифрами программа не «починит» — она честно отсеет их в Error Log. Это правильное поведение. Лучше исключить 200 кривых записей, чем зашить их в VCF и получить WhatsApp-рассылку в никуда.
В интерфейсе: столбец TEL → «Форматировать номера» → подсветка изменённых ячеек.
Этап 2. Разбор ФИО — где реальные ограничения
Здесь важно расставить точки над i, потому что формулировка «программа автоматически разделяет ФИО» вводит в заблуждение.
DataBaseNormalizer использует pymystem3 — Python-обёртку над морфологическим анализатором Яндекс Mystem. Библиотека делает лемматизацию и морфологический разбор токенов. Она умеет определять граммемы (имя, фамилия, отчество) и извлекать признак пола по морфемам и словарям — но это не то же самое, что «разделить ФИО по столбцам без ошибок».
Что работает хорошо:
- Стандартные русские ФИО: «Иван Петров Сергеевич» → имя/фамилия/отчество + пол M
- Определение пола по имени для большинства русскоязычных записей
Где алгоритм ошибается:
- Редкие и нестандартные имена
- Иностранные имена (латиница, азиатские имена)
- Сокращения: «И. Петров», «Иванов И.С.»
- Названия компаний вместо ФИО
- Порядок Фамилия–Имя vs Имя–Фамилия без контекста
Практический вывод: pymystem3 — полезный инструмент для русскоязычных баз, но его результаты нужно верифицировать, особенно на нестандартных записях. Для крупных международных баз без внешних справочников или API универсального решения не существует.
Примечание о производительности. На Windows pymystem3 при обработке каждой строки в цикле pandas.apply работает медленно из-за межпроцессного взаимодействия с бинарником Mystem. DataBaseNormalizer оптимизирует это пакетной обработкой — но ~3–4 секунды на строку при сложных именах остаются нормой.
В интерфейсе: столбец FN → «Форматировать имена» → проверьте результат вручную.
Этап 3. Автоматическое обогащение базы
Email определяется надёжно: регулярное выражение по наличию @ работает стабильно.
Сайт — по доменным маскам (.ru, .com, .net в ячейке).
Город — вероятностно. Скрипт сравнивает текст с геосправочником (DEF-коды операторов или текстовые упоминания). Это эвристика, не истина. Москва и Санкт-Петербург по кодам +7 495 / +7 812 определятся надёжно. Мобильный номер +7 916 ... — уже нет: этот DEF-диапазон покрывает несколько регионов.
Пол — как описано выше, работает для стандартных русскоязычных записей. Для компаний, сокращений и иностранных имён — ненадёжно.
Обогащение — вспомогательный слой, не источник истины. Используйте его для сегментации рассылок, но не полагайтесь на него для критических решений.
Этап 4. Дедупликация — обязательный шаг
После нормализации все 8999..., +7 999 ... и 79991234567 превращаются в один формат E.164. Только теперь видно, сколько раз один человек попал в базу под разными масками.
df = df.drop_duplicates(subset=['phone'])
Мини-кейс. При обработке базы из 40 000 строк после нормализации телефонов drop_duplicates убрал 4 500 дублей. Те же люди, записанные как 8999... в одном источнике и +7999... в другом. Без нормализации эти дубли незаметны — и каждый получил бы сообщение дважды, что поднимает вероятность жалоб.
Дедупликацию нужно делать до сборки VCF, не после.
Этап 5. Сборка VCF
Структура карточки vCard 3.0:
BEGIN:VCARD
VERSION:3.0
FN:Мария Иванова
TEL;TYPE=CELL:+79031234567
EMAIL;TYPE=INTERNET:masha@test.ru
ADR;TYPE=HOME:;;Санкт-Петербург;;;;
GENDER:F
NOTE:источник=CRM_2024;сегмент=Женщины_СПБ
END:VCARD
Несколько важных деталей:
- Версия 3.0 или 4.0 — обязательно. Версия 2.1 ломает кириллицу из-за конфликта кодировок. DataBaseNormalizer всегда выгружает UTF-8.
- Поле NOTE можно использовать для хранения метаданных (город, источник, сегмент). Продвинутые рассылочные инструменты умеют читать это поле и подставлять переменные в текст сообщения — без подключения внешней CRM.
- Максимальный объём одного VCF-файла — на практике до 50 000 контактов. На бюджетных Android-устройствах с ОЗУ < 6–8 GB лучше дробить на пакеты по 3 000–5 000.
Запись пакетом:
with open('contacts.vcf', 'a', encoding='utf-8') as f:
f.write(vcard_text)
Метод append записывает карточки последовательно в один файл. Никаких разделителей между карточками добавлять не нужно — стандарт vCard сам разбивает блоки по BEGIN/END:VCARD.
Что автоматизация не сделает
| Задача | Автоматизация | Комментарий |
|---|---|---|
| Очистка номеров от символов | ✅ Надёжно | RegEx, 100% |
| Замена 8 → +7 (РФ) | ✅ Надёжно | Простая логика |
| Валидация длины/формата | ✅ Надёжно | phonenumbers |
| Восстановление потерянных цифр | ❌ Невозможно | Данных нет |
| Разбор ФИО (рус.) | ⚠️ Частично | pymystem3, требует проверки |
| Разбор международных имён | ❌ Ненадёжно | Нет универсального решения |
| Определение пола | ⚠️ Вероятностно | Ошибается на нестандартных именах |
| Определение города | ⚠️ Вероятностно | Зависит от данных в записи |
| Сегменты/группы в WhatsApp | ❌ Не создаёт | VCF только в телефонную книгу |
VCF загружает контакты в адресную книгу смартфона. WhatsApp увидит их как доступные для переписки номера, но ярлыки и группы внутри мессенджера расставляются вручную или через CRM-интеграцию.
Скорость: цифра «5 секунд»
На практике обработка 10 000–20 000 строк занимает несколько секунд на номера — против 2–5 рабочих дней ручной работы в Excel. Форматирование имён дольше: ~3–4 секунды на строку.
Цифра «5 секунд» — это кейс для этапа нормализации телефонов, а не гарантированный результат на всю базу. Суть не в секундах, а в том, что задача, требующая человеко-дней, становится фоновым процессом.
Преимущества DataBaseNormalizer
- Единый формат — номера E164, готовые к использованию
- Автораспознавание ФИО — имя, фамилия, отчество с ручной верификацией
- Совместимость — формат Android и iPhone, vCard 3.0 UTF-8
- Персонализация — рассылки с обращением по имени
- Универсальность — Excel, CSV, VCF на входе и выходе
- Проверка контактов — WhatsApp и Telegram из программы
- Локально и бесплатно — данные не уходят на серверы
🎯 Следующий шаг
Возьмите небольшой кусок своей реальной базы — 100–200 строк с типичным хаосом — и прогоните через DataBaseNormalizer: TEL → форматирование номеров → FN → форматирование имён → сохранение VCF. Это покажет реальный уровень «грязи» в данных и точки, где потребуется ручная доработка, до того как вы запустите это на всю базу.
Вывод
Практическое правило:
Автоматизация убирает хаос в телефонах и дублях — но не исправляет данные, которых нет. Мусор на входе плюс скрипт = красиво упакованный мусор на выходе.