Удаляем «собачек» из списка друзей в ВК с помощью Python

У многих есть аккаунт в социальной сети ВК. И, если вы используете данную социальную сеть не только для общения с друзьями, то список этих друзей может быть довольно внушительным. К примеру, у моего аккаунта ВК 4635 активных друзей. Вот только не все аккаунты пользователей у вас в друзьях долго живут. Со временем кто-то из них станет «собачкой». То есть, либо просто удалит свой аккаунт, либо будет заблокирован соцсетью за какую-либо «провинность». Таких вот, неактивных, пользователей из списка друзей лучше вычищать. Но делать это вручную, особенно если список друзей напоминает египетский список, довольно долго и муторно. Можно, конечно, воспользоваться уже готовыми решениями, а можно написать собственный скрипт на Python, чем я и предлагаю заняться.


Что потребуется?

Для работы данного скрипта требуется установка двух библиотек. Это vk-api и colorama. Причем установка второй вовсе не обязательно. Она служит скорее для украшения вывода в терминал и практической пользы несет не особо много. Тем не менее, для их установки пишем в терминале команду:

pip install vk-api colorama


Импорт необходимых библиотек

Для начала импортируем в скрипт библиотеки, которые понадобятся в процессе его работы. Конечно же, это библиотека vk-api из которого импортируем модуль VkApi, а также colorama, откуда импортируются модули Fore, init. Также понадобится импортировать из модуля vk_api.exceptions ApiError для обработки исключений, которые могут возникнуть в процессе работы с библиотекой vk-api.

Из стандартны библиотек импортируем модуль Path библиотеки pathlib; ThreadPoolExecutor из библиотеки concurrent.futures; модуль sleep из библиотеки для работы со временем time.

Также понадобиться создать дополнительный файл set.py, в котором объявить две переменные: token_vk, user_vk_id. Первая переменная будет содержать токен приложения для работы с ВК, вторая – id пользователя, со списком друзей которого мы будем работать. Обратите внимание, что работать вы сможете только со своим списком друзей, так как в процессе работы будет происходить удаление деактивированных пользователей. Выглядеть содержимое данного файла будет примерно так:

Python:
token_vk = "vk1.a.kv8Q6fhsEO4VEO3v7z87R6INxYlrU9aTyeAoPrY0ObAFEOUlzHb7AgYHd21Ykt5vqcRNkoq75jIYuWtStAHLLwD78E4RPZ_L_c0EfqiVmJcYsl- "
user_vk_id = "111111111"

Значения, которые присвоены данным переменным служат только для примера. Вам нужно будет получить собственный токен, а также узнать . Импортируем все необходимое в наш скрипт:

Python:
from time import sleep
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

from colorama import Fore, init
from vk_api import VkApi
from vk_api.exceptions import ApiError

from set import token_vk, user_vk_id


Инициализация colorama, объявление глобальных переменных и активация сессии ВК

Для корректной работы библиотеки colorama ее необходимо инициализировать с помощью команды init. Также, необходимо создать сессию ВК, в которую передать ранее полученный токен. И здесь же объявить две глобальные переменные, которые будут служить счетчиками удаленных и не удаленных пользователей в процессе работы скрипта.

Python:
init()
session = VkApi(token=token_vk).get_api()

del_ch = 0
not_del = 0


Получение списка друзей ВК

Создадим функцию get_friends() -> (list, bool). На вход данной функции ничего не передается. А вот возвращает функция, в случае благополучного исхода, список id друзей пользователя, или False в случае возникновения исключения или, если список друзей будет пуст.

Объявим переменную friends_list, которой присвоим в качестве значения пустой список. В него будут помещены id друзей пользователя. В переменную friends получим список друзей пользователя с помощью метода VK API friends.get. В данный метод передадим токен, id пользователя, список друзей которого нужно получить, смещение offset, с которого нужно получать друзей – в данном случае 0, так как нужно получить полный список и количество друзей count, которое в данном случае также равно 0. Также передадим сюда версию используемого API в переменной v.

Проверим, получили ли мы список друзей. Если да, пробегаемся по нему в цикле, забираем каждый id и добавляем в список friends_list. Проверяем, не является ли данный список пустым. Если нет, возвращаем его из функции. В случае же, если список пуст или мы не получили список друзей, возвращаем False.

Также, для обработки исключения, которое может возникнуть в процессе работы с VK API, заключим данный код в блок try – except и в случае возникновения исключения возвращаем из функции False.

Python:
def get_friends() -> (list, bool):
    """
    Получаем список друзей пользователя и забираем их id.
    """
    friends_list = []
    try:
        friends = session.friends.get(access_token=token_vk, user_id=user_vk_id, offset=0, count=0, v=5.131)
        if friends['items']:
            for item in friends['items']:
                friends_list.append(item)
            if friends_list:
                return friends_list
            return False
        return False
    except ApiError:
        return False


Проверка списка друзей

Для проверки списка друзей пользователя создадим функцию get_user(user_id: str, nm: str) -> None. На входе передаем в нее id друга, а также строку, которая содержит порядковый номер из списка проверяемого пользователя и служит больше в информационных целях. На выходе данная функция ничего не возвращает.

Теперь необходимо получить базовую информацию о пользователе с помощью метода VK API users.get. В случае, если пользователь заблокирован или удален, возвращается параметр deactivated. Вот с его помощью мы и будем определять, является ли пользователь «собачкой» или нет. Создаем переменную users, в которую будет передан список со словарями, содержащими данные о пользователе. Передаем токен, id друга, данные по которому нужно получить, а также версию используемого API.

Python:
users = session.users.get(access_token=token_vk, user_ids=user_id, v=5.131)

Проверяем, получен ли ключ deactivated. Если да, выводим сообщение для пользователя на экран и передаем id деактивированного друга в функцию unfollower для удаления его из списка друзей. Данную функцию мы напишем немного позднее. После чего возвращаемся из функции.

Python:
            if users[0]['deactivated']:
                print(f'{Fore.RESET}{nm}: {user_id}: {Fore.RED}Деактивирован')
                unfollower(user_id)
                return

В случае же, когда данного ключа не существует, возникнет исключение KeyError. В данном случае, это означает, что аккаунт друга активен. Сохраняем id активного друга в файл. Это понадобиться нам в дальнейшем, чтобы проверять id, которые уже были использованы, так как скрипт может быть прерван, а проверять одни и те же данные не имеет смысле. Также выводим сообщение в терминал, что пользователь активен и возвращаемся из функции.

Python:
            with open("user_check.txt", "a", encoding="utf-8") as file:
                file.write(f"{user_id}\n")
            print(f'{Fore.RESET}{nm} | {users[0]["first_name"]} {users[0]["last_name"]} https://vk.com/id{user_id}: '
                  f'{Fore.GREEN}Активен')
            return

Заключим весь код в блок try – except, чтобы обработать ошибки, которые могут возникнуть в процессе работы с VK API.

Python:
def get_user(user_id: str, nm: str) -> None:
    try:
        """
        Получаем основные данные о пользователе.
        """
        users = session.users.get(access_token=token_vk, user_ids=user_id, v=5.131)
        try:
            """
            Проверяем, есть ли ключ деактивации. Если да, то добавляем
            "битый" id в список. Если нет, обрабатываем исключение и
            добавляем не "битый" id в список проверенных.
            """
            if users[0]['deactivated']:
                print(f'{Fore.RESET}{nm}: {user_id}: {Fore.RED}Деактивирован')
                unfollower(user_id)
                return
        except KeyError:
            """
            Сохраняем не "битые" id для последующей проверки.
            :param us_id: id пользователя
            """
            with open("user_check.txt", "a", encoding="utf-8") as file:
                file.write(f"{user_id}\n")
            print(f'{Fore.RESET}{nm} | {users[0]["first_name"]} {users[0]["last_name"]} https://vk.com/id{user_id}: '
                  f'{Fore.GREEN}Активен')
            return
    except ApiError:
        return


Удаление деактивированного друга из списка друзей

Для удаления друга, аккаунт которого был заблокирован или удален, создадим функцию unfollower(user_id: str) -> None. На вход данная функция получает id друга, которого надо удалить из списка друзей.

В переменную deleted получим словарь, который в случае успешного удаления пользователя из списка друзей будет содержать ключ success. Удалять пользователя из списка будем с помощью метода VK API friends.delete, куда передадим токен, id пользователя, которого нужно удалить из списка друзей и версию используемого API.

Python:
deleted = session.friends.delete(access_token=token_vk, user_id=user_id, v=5.131)

Проверяем, если ли ключ success в полученных в процессе работы с API данных. Если да, проверяем его содержимое. И если оно равно 1, удаление пользователя из списка друзей произошло успешно. Выводим сообщение в терминал об успешном удалении, увеличиваем счетчик удаленных пользователей и сохраняем id удаленного пользователя в файл user_bad.txt, который понадобиться в дальнейшем, для проверки, удален ли пользователь из списка друзей ранее или нет.

Если же возникнет ошибка при работе с API или ключа success не окажется с возвращенных данных, обработаем эти исключения и запишем данные о необработанном id в файл error_deleted.txt. Функцию для записи создадим немного позднее, а также выведем сообщение в терминал, что пользователь с текущим id не удален. После этого возвращаемся из функции.

Python:
def unfollower(user_id: str) -> None:
    global del_ch
    try:
        """
        Удаляем пользователя из списка друзей.
        Если произошли ошибки, записываем id пользователя в файл.
        """
        deleted = session.friends.delete(access_token=token_vk, user_id=user_id, v=5.131)
        if deleted["success"] == 1:
            print(f'{user_id}: удален')
            del_ch += 1
            """
            Сохраняем "битые" id в отдельный файл, для последующей проверки.
            :param us_id: id пользователя
            """
            with open("user_bad.txt", "a", encoding="utf-8") as file:
                file.write(f"{user_id}\n")
    except (ApiError, KeyError):
        print(f'{user_id}: не удален')
        error_save(user_id)
        return


Сохранение ошибок при работе с id

Создадим простую функцию error_save(user_id: str) -> None, которая на входе принимает id пользователя, при работе с которым возникла ошибка. Данная функция ничего не возвращает. Далее, открываем файл на добавление данных, записываем id пользователя, при работе с которым возникла ошибка и увеличиваем счетчик не удаленных пользователей.

Python:
def error_save(user_id: str) -> None:
    global not_del
    with open("error_deleted.txt", "a", encoding="utf-8") as dl:
        dl.write(f'{user_id}\n')
        not_del += 1


Запуск проверки

Создадим функцию main. Для того, чтобы выполнять проверять, был ли проверен текущий id ранее, создадим переменную users_check, которая будет содержать множество из id загруженных из файлов. Проверяем в цикле, существуют ли файлы с проверенными активными и деактивированными id. Если да, загружаем из них id в множество users_check.

Python:
global del_ch, not_del
    users_check = set()

    for f_name in ["user_check.txt", "user_bad.txt"]:
        if Path(f_name).exists():
            with open(f_name, "r", encoding="utf-8") as fl:
                for us in fl.readlines():
                    users_check.add(us.strip())

Получаем список друзей пользователя. В случае, если список не пуст, запускаем ThreadPoolExecutor, для выполнения функции get_user в потоках. Хотя, существенного прироста в скорости при работе с VK API особо не наблюдается. Пробегаемся по полученному списку id в цикле. Забираем id, а также с помощью функции enumerate его порядковый номер. Проверяем, есть ли текущий id в множестве с уже проверенными. Если да, выводим сообщение в терминал и продолжаем цикл дальше. Если нет, запускаем поток для функции get_user, куда передаем id и строку из порядкового номера текущего id и общего количества. Делаем паузу на 0,4 секунды. Если же список друзей получен не был, выводим соответствующее сообщение в терминал.

Python:
def main() -> None:
    global del_ch, not_del
    users_check = set()

    """
    Проверяем существование файла с проверенными id.
    Если есть, добавляем каждый id в множество.
    """

    for f_name in ["user_check.txt", "user_bad.txt"]:
        if Path(f_name).exists():
            with open(f_name, "r", encoding="utf-8") as fl:
                for us in fl.readlines():
                    users_check.add(us.strip())

    if frd := get_friends():
        with ThreadPoolExecutor(max_workers=50) as executor:
            for num, us_id in enumerate(frd):
                if str(us_id) in users_check:
                    print(f"{Fore.RESET}{num+1}/{len(frd)} | {us_id}: {Fore.YELLOW}проверен ранее")
                    continue
                executor.submit(get_user, user_id=us_id, nm=f'{num+1}/{len(frd)}')
                sleep(0.4)
    else:
        print(Fore.RED + f"\nУ пользователя нет друзей.")


if __name__ == "__main__":
    main()

Таким образом, при работе данной функции у меня было найдено 4 деактивированных учетных записи друзей, которые были благополучно удалены. Создано два файла, содержащие активные id друзей, а также деактивированные id.

screenshot2.png

Также, данные пользователи отобразились в самом ВК, в виде пользователей, которых необходимо удалить как подписчиков.

screenshot1.png

Таким образом, с помощью небольшого и несложного скрипта мы смогли облегчить проверку списка друзей на деактивированных пользователей – «собачек». А заодно немного попробовали работать с методами VK API. Подробнее об использованных методах можно почитать на официальной странице руководства по данным методам: .

Python:
"""
Скрипт для удаления "собачек" из списка друзей ВК.
Требует для установки библиотек: vk-api и colorama:
pip install vk-api colorama
"""

from time import sleep
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

from colorama import Fore, init
from vk_api import VkApi
from vk_api.exceptions import ApiError

from set import token_vk, user_vk_id

init()
session = VkApi(token=token_vk).get_api()

del_ch = 0
not_del = 0


def get_friends() -> (list, bool):
    """
    Получаем список друзей пользователя и забираем их id.
    """
    friends_list = []
    try:
        friends = session.friends.get(access_token=token_vk, user_id=user_vk_id, offset=0, count=0, v=5.131)
        if friends['items']:
            for item in friends['items']:
                friends_list.append(item)
            if friends_list:
                return friends_list
            return False
        return False
    except ApiError:
        return False


def get_user(user_id: str, nm: str) -> None:
    try:
        """
        Получаем основные данные о пользователе.
        """
        users = session.users.get(access_token=token_vk, user_ids=user_id, v=5.131)
        try:
            """
            Проверяем, есть ли ключ деактивации. Если да, то добавляем
            "битый" id в список. Если нет, обрабатываем исключение и
            добавляем не "битый" id в список проверенных.
            """
            if users[0]['deactivated']:
                print(f'{Fore.RESET}{nm}: {user_id}: {Fore.RED}Деактивирован')
                unfollower(user_id)
                return
        except KeyError:
            """
            Сохраняем не "битые" id для последующей проверки.
            :param us_id: id пользователя
            """
            with open("user_check.txt", "a", encoding="utf-8") as file:
                file.write(f"{user_id}\n")
            print(f'{Fore.RESET}{nm} | {users[0]["first_name"]} {users[0]["last_name"]} https://vk.com/id{user_id}: '
                  f'{Fore.GREEN}Активен')
            return
    except ApiError:
        return


def unfollower(user_id: str) -> None:
    global del_ch
    try:
        """
        Удаляем пользователя из списка друзей.
        Если произошли ошибки, записываем id пользователя в файл.
        """
        deleted = session.friends.delete(access_token=token_vk, user_id=user_id, v=5.131)
        if deleted["success"] == 1:
            print(f'{user_id}: удален')
            del_ch += 1
            """
            Сохраняем "битые" id в отдельный файл, для последующей проверки.
            :param us_id: id пользователя
            """
            with open("user_bad.txt", "a", encoding="utf-8") as file:
                file.write(f"{user_id}\n")
    except (ApiError, KeyError):
        print(f'{user_id}: не удален')
        error_save(user_id)
        return


def error_save(user_id: str) -> None:
    global not_del
    with open("error_deleted.txt", "a", encoding="utf-8") as dl:
        dl.write(f'{user_id}\n')
        not_del += 1


def main() -> None:
    global del_ch, not_del
    users_check = set()

    """
    Проверяем существование файла с проверенными id.
    Если есть, добавляем каждый id в множество.
    """

    for f_name in ["user_check.txt", "user_bad.txt"]:
        if Path(f_name).exists():
            with open(f_name, "r", encoding="utf-8") as fl:
                for us in fl.readlines():
                    users_check.add(us.strip())

    if frd := get_friends():
        with ThreadPoolExecutor(max_workers=50) as executor:
            for num, us_id in enumerate(frd):
                if str(us_id) in users_check:
                    print(f"{Fore.RESET}{num+1}/{len(frd)} | {us_id}: {Fore.YELLOW}проверен ранее")
                    continue
                executor.submit(get_user, user_id=us_id, nm=f'{num+1}/{len(frd)}')
                sleep(0.4)
    else:
        print(Fore.RED + f"\nУ пользователя нет друзей.")


if __name__ == "__main__":
    main()

Файлы с кодом прилагаю к статье во вложении.

А на этом, пожалуй – все. Спасибо за внимание. Надеюсь, данная информация будет вам полезна
 

Вложения

  • bad_friends.zip
    2,4 КБ · Просмотры: 93
  • Нравится
Реакции: InternetMC
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!