Привет, Habr!
Как-то в процессе работы возник вопрос как на корпоративном домене в Яндексе выгрузить все контакты организации из адресной книги Яндекс.почты в файл .csv или .xls, чтобы было красиво и потом удобно работать с этими данными в MS Excel.
Оказывается, что стандартными средствами Яндекс.почты можно выгрузить только в Vcard формат, что мне совсем не подходит. Нужно потом его как-то конвертировать сторонними средствами. Такие попадались на просторах интернета, что совсем неудобно.
На помощь пришел Python.
C помощью библиотеки BeautifulSoup очень удобно и быстро парсить html и вынимать всю нужную нам информацию.
Для парсинга нам понадобится Python 3, библиотека BeautifulSoup и браузер с инспектором кода.
Для начала импортируем необходимые для работы библиотеки.
from bs4 import BeautifulSoup as BS
import re
import csv
В результате анализа кода страницы выявлено, что данные которые нам нужны спрятаны в тегах span с классами:
mail-AbookEntry-Contact - содержит имя контакта
mail-AbookEntry-Emails - содержит список Email-ов
mail-AbookEntry-Phones - телефоны
Сохраняем нашу веб страницу на диск в папку со скриптом, я назвал ее просто “contacts.html”. Если в адресной книге много контактов, то перед сохранением не забываем нажать “Показать все контакты” в конце страницы.
Открываем сохраненную страницу и получаем весь код внутри тегов span, сохраняя их в три списка:
with open('contacts.html', 'r', encoding='utf-8') as f:
html_str = f.read()
res = BS(html_str, features="lxml")
#список с именами
l_contacts = res.findAll('span', class_='mail-AbookEntry-Contact')
#список с Emailами
l_emails = res.findAll('span', class_='mail-AbookEntry-Emails')
#список с телефонами
l_phones = res.findAll('span', class_='mail-AbookEntry-Phones')
#Объединяем в один большой список с которым и будем дальше работать
l_res = list(zip(l_contacts, l_emails, l_phones))
Каждый элемент списка l_res это список с кусочками кода с нашей страницы, соответствующий строке с контактом.
Пробегаем циклом по нашему списку l_res:
for i in l_res:
l_row_contact=[] #список, в который будут записываться данные о контакте (имя, емейлы, телефон) для записи в файл .csv
Так как i элемент это тоже список, содержащий группы, показанные выше на рисунке, то проходим по всем элементам этого списка.
for j in i:
Может быть такое, что у контакта несколько Email-ов. В коде они хранятся в списке ul с классом _nb-popup-menu, а каждый email обернут в теги li и a.
#Если существует список дополнительных емейлов у контакта, то извлекаем емейлы и сохраняем в список l_a
if j.find('ul', class_='_nb-popup-menu') is not None:
Для начала находим и получаем содержимое тегов li:
l_li = j.findAll('li', class_='_nb-popup-line')
l_a=[]
Пробегаем по каждому полученному li и извлекаем текст Email, обернутый в тег a с классом _nb-popup-link
for k in l_li:
if k.find('a', class_='_nb-popup-link') is not None:
l_a.append(k.find('a', class_='_nb-popup-link').text)
Добавляем к результирующему списку с данными о контакте строку с разделителями \r\n, чтобы в ячейке был перенос, если несколько email-ов.
l_row_contact.append('\r\n'.join(l_a))
#если доп списка нет, то просто извлекаем все данные по контакту
elif j.find('span', class_='mail-ui-Overflower') is not None:
l_row_contact.append(j.find('span', class_='mail-ui-Overflower').text)
В результате одного прохода мы получаем список со строками следующего формата:
[ ‘Имя контакта’, ‘Email_1\r\nEmail_2…Email_k’, ‘Телефон’ ]
#записываем строку с данными контакта в файл csv
with open('contacts.csv','a') as f:
file_writer = csv.writer(f, delimiter = ";", lineterminator="\r")
file_writer.writerow(['Имя', 'Emails', 'Телефон'])
file_writer.writerow(l_row_contact)
Я использую разделитель ‘;’ только, чтобы при открытии было красиво в Excel.
И так проходим по всему списку, дописывая в файл CSV строки с данными о контактах.
Если использовать разделитель ‘,’ и убрать дополнительные Email-ы в получившемся файле, то можно импортировать всё в Outlook.
Код проекта вы можете посмотреть и скачать на GitHub.
Комментарии (5)
Akina
11.03.2022 18:26+2Не понимаю... код писать, библиотеки какие-то цеплять... да VCARD парсится по щелчку пальцев! скажем, пять минут Экселя - и готов нормальный CSV. Можно макрос записать, а потом воспроизводить.
vladimir-klp Автор
11.03.2022 20:07Да, можно и так. Как бывает на одну задачу есть несколько способов ее решения. В моем случае больше даже преследовалась цель изучения библиотек Python????
bungu
13.03.2022 22:34Ну так не интересно. Я бы оценил если бы автор сделал скрипт который сам авторизируется в Яндексе, а потом сам скачает все это.
Anderson
А разве у почты для домена Яндекса нет api для работы с учетными записями?
https://yandex.ru/dev/pdd/doc/reference/email-list.html
vladimir-klp Автор
Спасибо за подсказку, надо будет попробовать поиграться с api яндекс. А вообще смысл был на Python написать скрипт, который спарсит контакты с любого аккаунта Яндекс. Позднее на основе этого скрипта было написан другой, который с помощью драйвеоа chromium автоматом чекал ящики определенного домена и удалял из адресной книги (после смены домена в организации надо было как-то убрать у всех сотрудников из личной адресной книги записи со старым доменом, опять же яндекс дает это делать только ручками. Python собранный в exe решил эту задачу на ура у всех 50+ сотрудников) .