Как извлечь номера телефонов из текста — парсинг и нормализация
Когда нужен парсинг номеров
Представьте: вы получили результаты web-скрапинга — 20 страниц с контактами компаний. Всё вперемешку: адреса, email, телефоны, описания. Номера записаны как попало: где-то +7 (999) 123-45-67, где-то 8-999-1234567, где-то просто 9991234567.
Ваша задача — извлечь все телефоны и привести к единому формату. Руками? На это уйдёт день. А если страниц не 20, а 200?
Парсинг телефонных номеров нужен, когда:
- Импортируете данные из неструктурированных источников — результаты парсинга сайтов, текстовые дампы, PDF-документы
- Обрабатываете экспорты из CRM — часто там номера смешаны с именами и комментариями
- Объединяете базы из разных систем — у каждой свой формат записи
- Чистите «грязные» CSV — когда телефоны окружены лишними символами
Хороший парсер должен:
- Распознавать все варианты записи (с пробелами, скобками, дефисами, плюсом)
- Отличать телефоны от случайных последовательностей цифр (номера домов, счетов)
- Приводить к единому формату (например, 79991234567)
- Игнорировать невалидные номера
Российские номера — какими они бывают
Прежде чем парсить, нужно понять, что искать. Российские мобильные номера имеют чёткую структуру:
- Код страны: +7 или 7 (иногда пишут 8 вместо 7 для внутренних звонков)
- Код оператора (DEF): 3 цифры (900—999)
- Абонентский номер: 7 цифр
Итого: 11 цифр (с семёркой) или 10 цифр (если код страны опущен).
Вот как один и тот же номер может выглядеть в разных источниках:
+7 (999) 123-45-67
+7 999 123 45 67
+7-999-123-45-67
7 (999) 123-45-67
7-999-123-45-67
7 999 123 45 67
79991234567
8 (999) 123-45-67
8-999-123-45-67
89991234567
(999) 123-45-67
999-123-45-67
9991234567
Все эти варианты описывают один номер. Задача парсера — распознать все форматы и привести к стандартному виду: 79991234567.
Проблемные случаи
Не каждая последовательность из 10—11 цифр — телефон:
12345678901— слишком последовательно, скорее всего идентификатор11111111111— номер-заглушка71234567890— код оператора 123 не существует70001234567— код 000 не используется
Качественный парсер проверяет не только длину, но и валидность кода оператора. В России мобильные коды начинаются с 9 (900—999).
Regex-паттерны — классический подход
Подходит для: простых случаев, когда текст относительно чистый
Время: 10—15 минут на написание
Сложность: средняя (нужно знать регулярные выражения)
Регулярные выражения (regex) — классический способ поиска паттернов в тексте. Вот базовый пример для Python:
import re
text = """
Контакты:
Иван: +7 (999) 123-45-67
Мария: 8-900-765-43-21
Офис: 79161234567
"""
# Паттерн для поиска номеров
pattern = r'\+?[78][-\s]?\(?(\d{3})\)?[-\s]?(\d{3})[-\s]?(\d{2})[-\s]?(\d{2})'
matches = re.findall(pattern, text)
for match in matches:
# match — кортеж из групп (999, 123, 45, 67)
phone = '7' + ''.join(match)
print(phone) # 79991234567
Паттерн \+?[78][-\s]?\(?(\d{3})\)?... означает:
\+?— опциональный плюс[78]— либо 7, либо 8[-\s]?— опциональный дефис или пробел\(?\d{3}\)?— три цифры, возможно в скобках- И так далее для остальных групп
Ограничения:
- Regex быстро усложняется, если форматов много
- Не проверяет валидность кода оператора (может вытащить несуществующий номер)
- Легко ошибиться в паттерне — найдутся не все варианты или, наоборот, лишнее
Для быстрого прототипа — подходит, но для production лучше использовать специализированные библиотеки.
Библиотека phonenumbers от Google
Подходит для: надёжного парсинга с валидацией
Время: 5 минут на интеграцию
Сложность: низкая (если знаете Python)
Библиотека phonenumbers от Google — де-факто стандарт для работы с телефонными номерами. Она знает форматы всех стран, проверяет валидность, нормализует запись.
Установка:
pip install phonenumbers
Пример использования:
import phonenumbers
from phonenumbers import phonenumberutil
text = """
Контакты компании:
Отдел продаж: +7 (999) 123-45-67
Бухгалтерия: 8 900 765 43 21
Склад: 9161234567
"""
# Ищем все возможные номера
for match in phonenumberutil.PhoneNumberMatcher(text, "RU"):
phone = match.number
# Проверяем валидность
if phonenumbers.is_valid_number(phone):
# Форматируем в E.164 (международный формат)
formatted = phonenumbers.format_number(
phone,
phonenumbers.PhoneNumberFormat.E164
)
print(formatted) # +79991234567
Результат:
+79991234567
+79007654321
+79161234567
Преимущества:
- Распознаёт все форматы автоматически
- Проверяет валидность по базе кодов операторов
- Поддерживает все страны мира
- Активно поддерживается Google
Ограничения:
- Только для Python (есть порты на JS, Java, но они менее популярны)
- Требует установки зависимости
- Для очень больших текстов может быть медленнее regex
Если вы пишете на Python — это оптимальный выбор.
Basalt — парсинг без кода
Подходит для: тех, кто не программирует
Время: 30 секунд
Сложность: нулевая
Basalt автоматически извлекает телефоны из любого текста — CSV, Excel, TXT. Вам не нужно писать код или разбираться в regex.
Два сценария использования:
Парсинг из CSV/TXT
- Откройте функцию «Уникальные» (она извлекает и дедуплицирует за один проход)
- Загрузите файл с «грязными» данными
- Basalt автоматически найдёт все телефоны, приведёт к формату 7XXXXXXXXXX
- Получите чистый список уникальных номеров
Парсинг из Excel
- Откройте функцию «Парсинг Excel»
- Загрузите XLSX-файл
- Basalt просканирует все листы, все ячейки
- Извлечёт телефоны и ссылки (если есть)
- Сохранит результаты в два CSV:
filename_phones.csvиfilename_links.csv
Как работает внутри:
Basalt использует многоступенчатый алгоритм:
- Regex-поиск — находит все последовательности, похожие на телефоны
- Очистка — убирает скобки, дефисы, пробелы, плюсы
- Нормализация — заменяет 8 на 7 в начале, дополняет 10-значные номера семёркой
- Валидация — проверяет длину (11 цифр), код страны (7), код оператора (9XX)
- Дедупликация — удаляет повторы
На выходе вы получаете только валидные российские мобильные номера в едином формате: 79991234567.
Пример результата:
Обработано: 50 000 строк
Извлечено: 12 340 номеров
Уникальных: 11 890
Дублей удалено: 450
Basalt работает локально — файлы не загружаются на сервер. Вся обработка происходит на вашем компьютере.
Нормализация к единому формату
Извлечь номера — полдела. Важно привести их к единому формату, чтобы избежать дублей.
Стандартный формат: 7XXXXXXXXXX (11 цифр, начинается с семёрки)
Алгоритм нормализации:
def normalize_phone(raw_phone):
# Шаг 1: убрать всё, кроме цифр
digits = ''.join(filter(str.isdigit, raw_phone))
# Шаг 2: если 11 цифр и начинается с 8 — заменить на 7
if len(digits) == 11 and digits[0] == '8':
digits = '7' + digits[1:]
# Шаг 3: если 10 цифр и начинается с 9 — добавить 7 в начало
if len(digits) == 10 and digits[0] == '9':
digits = '7' + digits
# Шаг 4: проверка валидности
if len(digits) != 11:
return None # невалидный номер
if digits[0] != '7':
return None # не российский
if digits[1] != '9':
return None # не мобильный
return digits
# Примеры
print(normalize_phone("+7 (999) 123-45-67")) # 79991234567
print(normalize_phone("8 (999) 123-45-67")) # 79991234567
print(normalize_phone("9991234567")) # 79991234567
print(normalize_phone("71234567890")) # None (код 123 невалидный)
Эта функция:
- Игнорирует форматирование (скобки, дефисы)
- Приводит все номера к виду 7XXXXXXXXXX
- Отсеивает невалидные номера
После нормализации вы можете безопасно дедуплицировать базу — одинаковые номера в разных форматах будут распознаны как дубли.
Практические советы
1. Проверяйте результат выборочно
После парсинга откройте результат и просмотрите первые 50—100 номеров. Убедитесь, что:
- Все номера валидны (начинаются с 79)
- Нет «мусора» (случайных последовательностей цифр)
- Нет очевидных дублей
Если видите ошибки — уточните паттерн парсинга или используйте более строгую валидацию.
2. Сохраняйте «сырые» данные
Не удаляйте исходный файл сразу после парсинга. Иногда выясняется, что настройки были неправильные, и приходится перезапускать процесс.
Basalt автоматически создаёт новый файл, не трогая оригинал. Но если вы пишете свой скрипт — не забудьте сделать то же самое.
3. Учитывайте контекст
Если парсите контакты компаний, в тексте могут встречаться:
- Номера факсов (часто городские, не мобильные)
- Короткие номера (3—4 цифры для внутренней связи)
- Номера счетов, ИНН, ОГРН
Настройте валидацию так, чтобы извлекались только мобильные российские номера. Это уменьшит количество «ложных срабатываний».
4. Парсите построчно для больших файлов
Если файл огромный (несколько гигабайт), не загружайте его целиком в память. Читайте и обрабатывайте построчно:
import re
pattern = re.compile(r'\d{10,11}')
with open('huge_file.txt', 'r') as infile:
with open('phones.csv', 'w') as outfile:
for line in infile:
matches = pattern.findall(line)
for match in matches:
normalized = normalize_phone(match)
if normalized:
outfile.write(normalized + '\n')
Этот подход работает даже на файлах в несколько гигабайт — потребление памяти остаётся минимальным.
5. Используйте дедупликацию сразу
Парсинг часто выдаёт дубликаты — один номер может встретиться в тексте несколько раз. Удаляйте дубли сразу, используя set в Python или функцию «Уникальные» в Basalt.
Это экономит место и упрощает дальнейшую работу.
Типичные ошибки при парсинге
Слишком жадный regex
Паттерн \d{10,11} найдёт любые 10—11 цифр подряд, включая номера счетов, даты (20241231235959) и другие несвязанные данные.
Решение: добавляйте проверку формата и валидацию кода оператора.
Пробелы внутри номера
Номер может быть записан как 7 999 123 45 67 (с пробелами). Если regex не учитывает пробелы, он найдёт несколько коротких последовательностей вместо одного номера.
Решение: используйте [-\s]* в паттерне, чтобы допустить любое количество дефисов и пробелов.
Скобки в формате
Формат +7 (999) 123-45-67 содержит скобки. Если regex не учитывает их, номер не распознается.
Решение: добавьте \(? и \)? для опциональных скобок.
Дедупликация без нормализации
Если удалять дубли до нормализации, номера 79991234567 и 89991234567 останутся оба, хотя это один телефон.
Решение: сначала нормализуйте (приведите к 7XXXXXXXXXX), потом дедуплицируйте.
От хаоса к порядку
Парсинг телефонных номеров — это превращение неструктурированных данных в аккуратный список контактов. Правильный парсинг экономит часы ручной работы и исключает ошибки.
Что запомнить:
- Российские мобильные: 11 цифр, формат 79XXXXXXXXX
- Один номер может быть записан 10+ способами
- Regex подходит для простых случаев, библиотека phonenumbers — для надёжности
- Basalt — для тех, кто не хочет писать код
- Всегда нормализуйте формат перед дедупликацией
Выбирайте инструмент под задачу:
- Разовый парсинг небольшого текста — regex
- Production-система на Python — phonenumbers
- Регулярная работа без программирования — Basalt
Главное — не парсите вручную. Компьютер сделает это быстрее, точнее и без ошибок. А вы сэкономите время на более важные задачи.