Как очистить выгрузку из CRM: пример на Python и pandas
Выгрузка из CRM может смешивать даты, суммы и статусы, а повторные контакты легко принять за дубли. Покажем, как прочитать CSV, привести поля к одному виду и пометить строки для проверки, не удаляя сомнительные данные автоматически.

В CSV из CRM одна дата может выглядеть как «08.03.2025», другая — как «2025-03-09», а у контакта с повторным email может быть другая сделка. На примере условной выгрузки покажем, как за несколько минут прочитать файл в Python 3.10+ с pandas 2.2.3, нормализовать поля и пометить подозрительные строки, не удаляя их без проверки.
Сначала выясните, что именно выгрузила CRM
В примере файл crm_export.csv содержит столбцы ID, Email, Телефон, Дата создания, Сумма и Статус. Разделитель — точка с запятой. Даты встречаются в форматах 08.03.2025 и 2025-03-09, сумма записана как 1 250,50 ₽, а значения статуса отличаются регистром и пробелами.
Перед обработкой проверьте первую строку файла и несколько значений вручную. У разных CRM отличаются названия столбцов, разделители, кодировка и правила выгрузки. Если файл использует запятые внутри значений, они должны быть корректно заключены в кавычки: иначе строка может распасться на лишние столбцы.
Для запуска нужен Python 3.10 или новее и pandas 2.2.3. Установите именно эту версию pandas командой python -m pip install pandas==2.2.3. Пример ниже рассчитан на указанные заголовки и разделитель; если в вашем файле они другие, замените их в коде.
Два способа прочитать выгрузку
Для небольшого разового файла хватит стандартного модуля csv. Он не требует установки библиотеки, но преобразование дат, сумм и отчёт по качеству данных придётся писать отдельно. В примере используем pandas: он удобен, когда нужно обработать таблицу целиком и проверить много строк.
| Подход | Что выигрываете | Чем платите | Когда выбирать |
|---|---|---|---|
Модуль csv | Нет внешней зависимости, легко читать записи по одной | Больше собственного кода для преобразования и проверок | Небольшой файл или потоковая обработка |
| pandas 2.2.3 | Удобные операции над столбцами и быстрые проверки | Дополнительная библиотека и расход памяти на всю таблицу | Регулярная очистка таблиц, сводки и аналитика |
Для крупных выгрузок pandas может потребовать больше оперативной памяти, чем доступно на рабочей машине. Тогда обрабатывайте файл частями или выбирайте потоковый сценарий на стандартном csv; конкретный порог зависит от размера строк и ресурсов компьютера.
Приводим поля к рабочему виду
Считываем все столбцы как текст. Так pandas не превратит пустую ячейку в специальное значение и не попытается угадать тип столбца до того, как мы проверим формат.
import pandas as pd
файл = "crm_export.csv"
df = pd.read_csv(
файл,
sep=";",
encoding="utf-8-sig",
dtype="string",
keep_default_na=False,
)
обязательные_столбцы = {
"ID", "Email", "Телефон", "Дата создания", "Сумма", "Статус"
}
отсутствуют = обязательные_столбцы - set(df.columns)
if отсутствуют:
raise ValueError(f"В файле нет столбцов: {sorted(отсутствуют)}")
# Нормализуем контакты, но не пытаемся угадать код страны.
df["Email"] = df["Email"].str.strip().str.lower()
df["Телефон"] = df["Телефон"].str.replace(r"\D+", "", regex=True)
# Оставляем исходную дату, чтобы можно было проверить преобразование.
исходная_дата = df["Дата создания"].str.strip()
df["Дата создания исходная"] = исходная_дата
df["Дата создания"] = pd.to_datetime(
исходная_дата,
format="mixed",
dayfirst=True,
errors="coerce",
)
df["Проверить дату"] = df["Дата создания"].isna() & исходная_дата.ne("")
# Пример рассчитан на сумму вида «1 250,50 ₽».
исходная_сумма = df["Сумма"].str.strip()
сумма_текст = исходная_сумма.str.replace(r"[^\d,.-]", "", regex=True)
сумма_текст = сумма_текст.str.replace(",", ".", regex=False)
df["Сумма"] = pd.to_numeric(сумма_текст, errors="coerce")
df["Проверить сумму"] = сумма_текст.ne("") & df["Сумма"].isna()
# Сводим известные варианты статусов, неизвестные оставляем для разбора.
нормализованный_статус = df["Статус"].str.strip().str.casefold()
словарь_статусов = {
"новая": "Новая",
"в работе": "В работе",
"закрыта": "Закрыта",
}
df["Статус"] = нормализованный_статус.map(словарь_статусов).fillna(
нормализованный_статус
)
df["Проверить статус"] = (
нормализованный_статус.ne("")
& ~нормализованный_статус.isin(словарь_статусов)
)
# ID удобнее email для поиска повторов, если он уникален в вашей CRM.
id_контакта = df["ID"].str.strip()
df["Повтор ID"] = id_контакта.ne("") & id_контакта.duplicated(keep="first")
df.to_csv("crm_review.csv", index=False, encoding="utf-8-sig")
print(f"Строк обработано: {len(df)}")
print(f"Даты для проверки: {int(df['Проверить дату'].sum())}")
print(f"Суммы для проверки: {int(df['Проверить сумму'].sum())}")
print(f"Неизвестные статусы: {int(df['Проверить статус'].sum())}")
print(f"Повторы ID: {int(df['Повтор ID'].sum())}")
Здесь utf-8-sig позволяет прочитать UTF-8-файл с BOM — служебной меткой в начале текста, которая иногда появляется после сохранения или экспорта таблицы. Если файл в другой кодировке, её нужно определить, а не перебирать варианты наугад.
format="mixed" в pandas 2.2.3 позволяет распознавать разные форматы дат в одном столбце. Но неоднозначная дата вроде 03/04/2025 всё равно требует правила: это 3 апреля или 4 марта? Параметр dayfirst=True задаёт предпочтение, но не заменяет проверку исходных данных.
Очистка не должна превращать сомнительное значение в «правильное» на вид. Лучше пометить строку и сохранить исходник, чем незаметно отправить неверную дату или сумму в отчёт.
Что проверить перед тем, как считать данные чистыми
- Даты. Пустые значения допустимы не всегда. В примере помечаются непустые ячейки, которые не удалось разобрать. Например, «31.02.2025» не станет корректной датой и попадёт в проверку.
- Суммы. Код поддерживает формат с пробелом-разделителем тысяч и десятичной запятой. Формат
1.250,50неоднозначен для этой обработки: не смешивайте варианты записи без отдельного правила преобразования. - Дубли. Совпадение email не означает, что это один и тот же клиент: общий адрес может быть у нескольких людей, а у одного клиента — несколько сделок. Сначала проверьте, что ID уникален и соответствует записи, которую вы анализируете.
- Статусы. Словарь в примере знает только три значения. Новое состояние CRM не удаляется, а попадает в проверку. Дополните словарь после сверки с актуальным справочником статусов.
- Телефоны. Удаление символов приводит номер к строке цифр, но не добавляет код страны и не проверяет, существует ли номер. Для международной базы нужна отдельная договорённость о формате.
Файл crm_review.csv — результат для контроля, а не автоматически одобренная база. Сверьте числа проверок с размером исходника, откройте подозрительные строки и убедитесь, что итоговые даты и суммы соответствуют правилам вашей CRM. Не загружайте клиентскую выгрузку в неизвестные онлайн-конвертеры: в ней могут быть персональные данные.
Когда выбирать другой способ
Если выгрузка занимает больше памяти, чем доступно, или поступает непрерывным потоком, pandas может быть не лучшим инструментом: он загружает таблицу для обработки. Для небольшого скрипта, который читает строку за строкой, подойдёт стандартный csv, но проверку форматов и накопление отчёта придётся реализовать отдельно. Если задача повторяется каждый день, зафиксируйте схему файла и допустимые значения в проверках, а не полагайтесь на ручной просмотр.
Что делать дальше
Запустите обработку на копии выгрузки и сравните исходное и итоговое количество строк. Затем разберите все помеченные даты, суммы, статусы и ID, прежде чем строить отчёт или импортировать файл обратно в CRM. Следующий полезный шаг — сохранить правила схемы и несколько контрольных строк рядом со скриптом: тогда изменение формата экспорта обнаружится до того, как испортит регулярный отчёт.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Документация pandas: read_csv, Документация pandas: to_datetime
Частые вопросы
Можно ли сразу удалить строки с повторным ID?
Что делать, если у меня другой разделитель или кодировка?
Почему дата оказалась пустой после обработки?
Можно ли безопасно обработать суммы с точкой как разделителем тысяч?
Что делать, если у меня другая версия pandas?
Нужно ли сохранять исходные значения после очистки?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.