Python — получить телефоны друзей в VK

Многие, изучающие Python интересуются его использованием в связке с API Вконтакте. В VK имеется телефонная книга, она в более-менее нормальном формате отображает мобильные номера ваших друзей. А учитывая то, что далеко не каждый человек охотно оставляет там свой валидный (полный) номер телефона, будет весьма интересно и полезно написать скрипт, который будет отбирать исключительно валидные мобильные номера и выводить их в отдельную таблицу. Наша телефонная книга будет создавать CSV-файл, который впоследствии можно будет открывать, к примеру, в Excel.

Чтобы воспользоваться API Вконтакте на Python можно воспользоваться неплохой библиотекой vk. Оригинальное название, не так ли? Итак, нужно импортировать нужные нам модули:


import vk
from time import sleep
from re import sub, findall
from getpass import getpass
from csv import writer, QUOTE_ALL

Дале создаем класс User с методами, которые нам необходимы:


class User(object):
    """VK User"""
    def __init__(self, login, password):
        self.login = login
        self.password = password
        self.id = ''
    def auth(self):
        session = vk.AuthSession(app_id='5340228', user_login=self.login, user_password=self.password)
        api = vk.API(session)
        return api
    def friends(self, api):
        user_friends = api.friends.get(user_id=self.id, order='hints')
        return user_friends
    def friends_count(self, api):
        user_friends = User.friends(self, api)
        friends_count = len(user_friends)
        return friends_count
    def info(self, api):
        user = api.users.get(user_id=self.id)
        return user[0]

Тут возникла проблема, и гугл как-то не выдавал нужное решение, как взять id текущего пользователя. Но, выход был найдет – нужно передать как аргумент пустую строку.

Затем следует написать функцию валидатор, приводящая к общему виду номера телефонов. В нашем примере мы будем выбирать лишь номера, начинающиеся с «0». Вы сможете легко скорректировать скрипт под нужный вам формат.


def norm_mob(str):
    if len(str) != '':
        norm_mob = sub(r'(\s+)?[+]?[-]?', '', str)
        right_mob = findall(r'[\d]', norm_mob)
        if (len(right_mob) == len(norm_mob)) and (len(norm_mob) >= 10):
            rev_norm_mob = norm_mob[::-1]
            norm_mob = rev_norm_mob[0:10]
            if norm_mob[::-1][0] == '0':
                return norm_mob[::-1]
    else:
        return False

Затем пройдем по друзьям, отобрав тех, которые оставили свои контактные данные, и если оставили, то мы их валидируем и записываем в массив. У сервера ВК есть одна особенность – он не любит большое количество запросов, соответственно нужно сделать так, чтобы наш скрипт «спал» определенное время между ними. Были перепробованы различные значение, и определены оптимальные.


def find_correct_phone_numbers(api, friends, friends_count):
    users_phones = []
    for i in range(0, friends_count):
        cur_user_id = int(friends[i])
        cur_user = api.users.get(user_id=cur_user_id, fields='contacts')
        try:
            cur_mob = cur_user[0]['mobile_phone']
        except KeyError:
            sleep(0.3)
            continue
        mob = norm_mob(cur_mob)
        if mob:
            users_phones.append({
                'user_name': '{} {}'.format(cur_user[0]['first_name'], cur_user[0]['last_name']),
                'user_phone': '8{}'.format(mob)
                })
        sleep(0.4)
    return users_phones

Теперь сохраним полученный результат.


def saveCSV(data, path):
    with open(path, 'w') as csvfile:
        my_writer = writer(csvfile, delimiter='    ', quotechar='"', quoting=QUOTE_ALL)
        my_writer.writerow(('Имя пользователя', 'Номер моб. телефона'))
        for item in data:
            try:
                my_writer.writerow((item['user_name'], item['user_phone']))
            except Exception:
                my_writer.writerow(('(Ошибка в кодировке)', item['user_phone']))

Далее нужно добавить функцию, подсчитывающую затраченное время.


class Timer(object):
    def __enter__(self):
        self._startTime = time()
    def __exit__(self, type, value, traceback):
        howLong = time() - self._startTime
        print("Операция заняла: {:.2f} минут".format(howLong/60))

И в конце нужно реализовать вызов созданных функций.


def main():
    while True:
        login = input('E-mail: ')
        password = getpass('Password: ')
        try:
            vk_user = User(login, password)
            api = vk_user.auth()
            print('Авторизация выполнена успешно!')
            break
        except Exception:
            print('Вы ввели неверные данные, пожалуйста, повторите попытку.')
    friends = vk_user.friends(api)
    friends_count = vk_user.friends_count(api)
    print('Найдено {} друзей.'.format(friends_count))
    print('Идет выборка мобильных номеров...')
    with Timer() as p:
        users_phones = find_correct_phone_numbers(api, friends, friends_count)
    print('Выборка окончена. Сохранение...')
    saveCSV(users_phones, 'vk_mob.csv')
    print('Данные успешно сохранены.')
if __name__ == '__main__':
    main()

В результате мы получаем csv-файл, который в виде удобной таблицы можно открывать в Excel.

One thought on “Python — получить телефоны друзей в VK

  1. Привет.
    Столкнулся с множеством проблем с библиотекой vk для python и к сожалению автор видимо слишком занят чтобы поддерживать ее, вообщем сделал fork проекта, у уже внесено множество улучшений и исправлений, большая часть проекта покрыта тестами, добавлены полезные продакшн фичи, например, авто-разрешение конфликтов при входе с неизвестного места (когда деплоимся на aws или где-то не на домашнем лэптопе)
    Надеюсь кто-то так же найдет это полезным. Извиняюсь за внимание.
    Ссылка на проект: https://github.com/prawn-cake/vk-requests

Добавить комментарий

Войти с помощью: 

Ваш e-mail не будет опубликован. Обязательные поля помечены *