cece
This commit is contained in:
329
main.py
Normal file
329
main.py
Normal 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)
|
||||
Reference in New Issue
Block a user