This commit is contained in:
2025-10-01 10:30:11 +05:00
commit 0fec1a5a36
11 changed files with 1823 additions and 0 deletions

329
main.py Normal file
View File

@@ -0,0 +1,329 @@
import docx
import csv
import re
def extract_quoted_text(text):
"""Извлекает текст в кавычках «»"""
if not text:
return ""
match = re.search(r'«([^»]+)»', text)
return match.group(1).strip() if match else text.strip()
def extract_address(text):
"""Извлекает адрес, содержащий г. или Г."""
if not text:
return ""
# Ищем текст с "г." или "Г."
if re.search(r'[гГ]\.', text):
return text.strip()
return ""
def extract_email(text):
"""Извлекает email из текста и убирает пробелы после @"""
if not text:
return ""
# Убираем пробелы после @
text = re.sub(r'@\s+', '@', text)
# Ищем паттерн email
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
match = re.search(email_pattern, text)
return match.group(0) if match else ""
def extract_phone(text):
"""Извлекает телефон из текста"""
if not text:
return ""
# Убираем лишние пробелы
return text.strip()
def parse_contact_data(cells):
"""Парсит данные контакта из ячеек таблицы"""
# Объединяем весь текст из всех ячеек для анализа
all_text = ' '.join(cells)
# ВАЖНО: Парсим только строки с email!
has_email = '@' in all_text
if not has_email:
return None
contact = {
'Имя': '',
'Фамилия': '',
'Отчество': '',
'Организация': '',
'Телефон': '',
'E-mail': ''
}
# Ищем email
for cell in cells:
email = extract_email(cell)
if email:
contact['E-mail'] = email
break
# Ищем организацию/имя в кавычках «»
organization_found = False
for cell in cells:
quoted_match = re.search(r'«([^»]+)»', cell)
if quoted_match:
contact['Организация'] = quoted_match.group(1).strip()
organization_found = True
break
# Если не нашли в кавычках, ищем название ЗАГЛАВНЫМИ буквами
if not organization_found:
for cell in cells:
# Ищем текст заглавными буквами (название организации обычно так)
# Исключаем строки с email и телефонами
if cell and not '@' in cell and not re.search(r'8\s*\(\d+\)', cell):
# Проверяем, есть ли заглавные слова
upper_words = re.findall(r'[А-ЯЁA-Z][А-ЯЁA-Z\s\-\.]+', cell)
if upper_words:
# Берем самое длинное совпадение
longest = max(upper_words, key=len).strip()
if len(longest) > 10: # Минимум 10 символов для названия
contact['Организация'] = longest
organization_found = True
break
# Ищем адрес (содержит г. или Г.) и добавляем к организации
for cell in cells:
address_match = re.search(r'\d{6},\s*[гГ]\.\s*[^,]+(?:,\s*[^,]+)*', cell)
if address_match:
address = address_match.group(0)
if contact['Организация'] and address not in contact['Организация']:
contact['Организация'] += ', ' + address
elif not contact['Организация']:
contact['Организация'] = address
break
# Ищем телефон (только основной, если есть)
for cell in cells:
# Ищем паттерн телефона
phone_match = re.search(r'8\s*\(\d+\)\s*[\d\-]+', cell)
if phone_match:
contact['Телефон'] = phone_match.group(0).strip()
break
return contact
def parse_phone_book():
"""Парсит телефонную книгу из Word документа и сохраняет в CSV"""
# Открываем документ
doc = docx.Document('./04_Телефонный справочник_МАКСИМ.docx')
# Список для хранения контактов
contacts = []
# Обрабатываем каждую таблицу в документе
for table in doc.tables:
# Пропускаем первую строку (заголовок), если она есть
rows = table.rows
for i, row in enumerate(rows):
cells = [cell.text.strip() for cell in row.cells]
# Пропускаем пустые строки или заголовки
if not cells or not any(cells):
continue
# Проверяем, что это не заголовок таблицы
if i == 0 and ('имя' in cells[0].lower() or 'фамилия' in ' '.join(cells).lower()):
continue
# Парсим данные контакта
contact = parse_contact_data(cells)
# Добавляем только если есть email и данные
if contact and any(contact.values()):
contacts.append(contact)
# Записываем в CSV файл
with open('contacts.csv', 'w', encoding='utf-8', newline='') as csvfile:
fieldnames = ['Имя', 'Фамилия', 'Отчество', 'Организация', 'Телефон', 'E-mail']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=';')
# Записываем заголовок
writer.writeheader()
# Записываем все контакты
writer.writerows(contacts)
print(f"Успешно обработано {len(contacts)} контактов")
print(f"Данные сохранены в файл contacts.csv")
return contacts
def export_for_gmail():
"""Экспортирует контакты в формате для Gmail"""
# Читаем существующий CSV файл
contacts = []
with open('contacts.csv', 'r', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
contacts = list(reader)
# Создаем CSV в формате Gmail
with open('contacts_gmail.csv', 'w', encoding='utf-8', newline='') as csvfile:
# Gmail использует специальные заголовки
fieldnames = ['Name', 'Given Name', 'Additional Name', 'Family Name',
'Organization 1 - Name', 'Phone 1 - Value', 'E-mail 1 - Value']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for contact in contacts:
# Очищаем название организации от многострочного текста
org = contact['Организация']
if org:
org = org.split('\n')[0].strip()
org = re.sub(r',\s*\d{6},.*$', '', org)
org = org.rstrip(',').strip()
# Формируем полное имя
full_name = f"{contact['Фамилия']} {contact['Имя']} {contact['Отчество']}".strip()
gmail_contact = {
'Name': org if org else full_name,
'Given Name': contact['Имя'],
'Additional Name': contact['Отчество'],
'Family Name': contact['Фамилия'],
'Organization 1 - Name': org,
'Phone 1 - Value': contact['Телефон'],
'E-mail 1 - Value': contact['E-mail']
}
writer.writerow(gmail_contact)
print(f"\n✅ Файл для Gmail создан: contacts_gmail.csv ({len(contacts)} контактов)")
print("📧 Импортируйте его в Gmail: Контакты -> Импорт -> Выберите файл")
return contacts
def export_for_mailru():
"""Экспортирует контакты в формате для Mail.ru"""
# Читаем существующий CSV файл
contacts = []
with open('contacts.csv', 'r', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
contacts = list(reader)
# Создаем CSV в формате Mail.ru (простой формат)
with open('contacts_mailru.csv', 'w', encoding='utf-8', newline='') as csvfile:
# Mail.ru использует простые заголовки
fieldnames = ['First Name', 'Last Name', 'E-mail Address', 'Home Phone', 'Company']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for contact in contacts:
# Очищаем название организации от многострочного текста
org = contact['Организация']
if org:
org = org.split('\n')[0].strip()
org = re.sub(r',\s*\d{6},.*$', '', org)
org = org.rstrip(',').strip()
mailru_contact = {
'First Name': contact['Имя'] if contact['Имя'] else org,
'Last Name': contact['Фамилия'],
'E-mail Address': contact['E-mail'],
'Home Phone': contact['Телефон'],
'Company': org
}
writer.writerow(mailru_contact)
print(f"\n✅ Файл для Mail.ru создан: contacts_mailru.csv ({len(contacts)} контактов)")
print("📧 Импортируйте его в Mail.ru: Настройки -> Контакты -> Импорт")
return contacts
def export_to_vcard():
"""Экспортирует контакты в формат VCard (.vcf)"""
# Читаем существующий CSV файл
contacts = []
with open('contacts.csv', 'r', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
contacts = list(reader)
with open('contacts.vcf', 'w', encoding='utf-8') as vcf_file:
for contact in contacts:
# Очищаем название организации от многострочного текста
org = contact['Организация']
if org:
org = org.split('\n')[0].strip()
org = re.sub(r',\s*\d{6},.*$', '', org)
org = org.rstrip(',').strip()
# Формируем VCard для каждого контакта
vcf_file.write("BEGIN:VCARD\n")
vcf_file.write("VERSION:3.0\n")
# Имя
if contact['Фамилия'] or contact['Имя']:
vcf_file.write(f"FN:{contact['Фамилия']} {contact['Имя']} {contact['Отчество']}\n".strip() + "\n")
vcf_file.write(f"N:{contact['Фамилия']};{contact['Имя']};{contact['Отчество']};;\n")
else:
# Если нет имени, используем организацию
vcf_file.write(f"FN:{org}\n")
# Организация
if org:
vcf_file.write(f"ORG:{org}\n")
# Email
if contact['E-mail']:
vcf_file.write(f"EMAIL;TYPE=INTERNET:{contact['E-mail']}\n")
# Телефон
if contact['Телефон']:
vcf_file.write(f"TEL;TYPE=WORK,VOICE:{contact['Телефон']}\n")
vcf_file.write("END:VCARD\n")
print(f"\n✅ Файл VCard создан: contacts.vcf ({len(contacts)} контактов)")
print("📱 Импортируйте его в почтовый клиент или телефон")
return contacts
if __name__ == "__main__":
print("=" * 60)
print("ПАРСЕР ТЕЛЕФОННОЙ КНИГИ")
print("=" * 60)
# Сначала парсим Word документ
print("\n📖 Парсинг телефонной книги из Word...")
contacts = parse_phone_book()
# Затем создаем файлы для импорта
print("\n" + "=" * 60)
print("СОЗДАНИЕ ФАЙЛОВ ДЛЯ ИМПОРТА")
print("=" * 60)
export_for_mailru()
export_for_gmail()
export_to_vcard()
# Выводим статистику
print("\n" + "=" * 60)
print("ПРИМЕРЫ КОНТАКТОВ:")
print("=" * 60)
for i, contact in enumerate(contacts[:5], 1):
org = contact['Организация'].split('\n')[0][:50]
print(f"{i}. {org}... - {contact['E-mail']}")
print("\n" + "=" * 60)
print("✅ ГОТОВО! Используйте файлы для импорта:")
print(" 📧 contacts_mailru.csv - для Mail.ru")
print(" 📧 contacts_gmail.csv - для Gmail, Outlook")
print(" 📱 contacts.vcf - для Apple Mail, телефонов")
print("=" * 60)