Предыстория и анонс

Мы в далеком 2022 году писали статью про анализ групп Вконтакте, она обрела популярность, разлетелась по многим статьям популярных сайтов. Сейчас когда Вконтакте возвращает себе былую мощь и аудиторию, статья снова становится актуальной.

Мы обновили парсер ВК групп, восстановили его работоспособность, а так же добавили новый функционал. Помимо анализа группы по активности ее пользователей за заданный интервал времени, который был реализован еще в прошлый раз, мы добавили сохранение в excel файл результата парсинга подписчиков группы Вконтакте, который содержит поля:

  1. id — идентификатор пользователя (по желанию можно добавить имя/фамилию, но мы это не делаем);
  2. activity — активен профиль пользователя или нет (активен/удален/заблокирован);
  3. last_seen — дата последнего посещения пользователя (можно с точностью до секунды);
  4. city — город, который указан у пользователя;
  5. bdate — год рождения, который указан у пользователя;
  6. sex — пол пользователя (муж/жен, третьего у нас не дано ;-D )
  7. platform — идентификатор платформы с которой сидит пользователь (мобильная версия, десктоп и тд. Расшифровки нигде на нашел, если поможете буду благодарен)
  8. is_closed — указывает закрытая страница у пользователя или нет.

Новая функция: save_excel Сохранение в excel

Для данный функции надо установить и добавить импорт библиотеки pandas, а так же установить вспомогательные библиотеки openpyxl и XlsxWriter

Вот так выглядит новая функция:

def save_excel(data: list, filename: str):
    """сохранение результата в excel файл"""
    df = pandas.DataFrame(data)
    writer = pandas.ExcelWriter(f'{filename}.xlsx')
    df.to_excel(writer, sheet_name='data', index=False)
    writer.sheets['data'].set_column(0, 1, width=10)
    writer.sheets['data'].set_column(1, 2, width=12)
    writer.sheets['data'].set_column(2, 3, width=14)
    writer.sheets['data'].set_column(3, 4, width=23)
    writer.sheets['data'].set_column(4, 5, width=10)
    writer.sheets['data'].set_column(5, 6, width=8)
    writer.sheets['data'].set_column(6, 7, width=12)
    writer.close()
    print(f'Все сохранено в {filename}.xlsx\n')

На входе получаем data, который является списком с данными, которые мы собрали благодаря парсеру ВК, и название файла filename, типа string, который получаем из списка указанных групп для анализа.

writer.sheets[‘data’].set_column(0, 1, width=10) и последующие похожие строки строки, для того чтобы указывать ширину каждого столбца в конечном файле excel.

Модифицируем функцию get_users Добавляем поля для парсинга из Вконтакте.

Добавим в params ‘fields’: ‘last_seen, city, bdate, sex’.

last_seen — последнее посещение пользователя, предоставляется в формате timestamp и platform — с какого устройства последний раз заходил пользователь, city — город пользователя, bdate — дата рождения, sex — пол пользователя (1 или 2)

С полным списком всех полей можете ознакомится тут: Официальная документация Вконтакте. Так же прошу вашей помощи, найти расшифровку идентификаторов поля platform, я так понимаю каждая цифра это web, android и ios, но это не точно)))

В начале функции создаем списки:

  1. data_list — в нем будем аккумулировать собранные данные о собранных пользователях;
  2. active_list — для активных пользователей (которые не удалены или забанены);
  3. active_list_by_time — для активных пользователей за отведенное время;
  4. un_active_list — для всех не активных пользователей группы Вконтакте;
  5. banned_list — для забаненных и удаленных пользователей группы Вконтакте.

Используя метод API VK groups.getMembers получим json с данными о пользователях и распарсим его, распределяя пользователей по нашим спискам.

Многие поля из json нечитабельны, преобразуем каждый из них в визуально понятный. Например параметр sex мы получаем 1 и 2, а мы сразу укажем что 1 это жен, а 2 — муж. Параметр last_seen в формате timestamp, переведем его в дд.мм.гггг. используя стандартную библиотеку python datetime: datetime.datetime.utcfromtimestamp(user.get(‘last_seen’).get(‘time’)).strftime(‘%d.%m.%Y’). Единственное, что я не знаю, это значения 1, 2, 4, 7 из platform, пишите мне или в комментарии если вы знаете, что за что отвечает.

def get_users(group_id: str, from_data: str) -> list:
    """Получаем данные о всех пользователях в группе и сортируем их по спискам"""
   data_list = []  # лист для сохранения данных о пользователях
    active_list = []  # активные пользователи
    active_list_by_time = []  # активные пользователи за отведенное время
    un_active_list = []  # неактивные пользователи
    banned_list = []  # удаленные и забаненные пользователи
    total_users = ''
    for offset in range(0, get_offset(group_id) + 1):
        params = {'access_token': token,
                  'v': 5.131,
                  'group_id': group_id,
                  'offset': offset * 1000,
                  'fields': 'last_seen, city, bdate, sex'}
        users = requests.get('https://api.vk.com/method/groups.getMembers', params=params).json()
        for user in users['response']['items']:
            total_users = users['response']['count']
            user_id = user.get('id')
            if user.get('deactivated'):
                activity = user.get('deactivated')
                banned_list.append(user_id)
            else:
                activity = 'active'
                active_list.append(user_id)
            try:
                last_seen = datetime.datetime.utcfromtimestamp(user.get('last_seen').get('time')).strftime('%d.%m.%Y')
            except AttributeError:
                last_seen = None
            if user.get('city'):
                city = user['city'].get('title')
            else:
                city = None
            bdate = user.get('bdate')
            if user.get('sex') == 2:
                sex = 'муж'
            else:
                sex = 'жен'
            try:
                platform = user.get('last_seen').get('platform')
            except AttributeError:
                platform = None
            if user.get('is_closed'):
                is_closed = 'закрытй профиль'
            else:
                is_closed = 'открытый профиль'
            data_list.append({
                'id': user_id,
                'activity': activity,
                'last_seen': last_seen,
                'city': city,
                'bdate': bdate,
                'sex': sex,
                'platform': platform,
                'is_closed': is_closed,
            })
            # проверка последнего посещения, не ранее указанной даты from_data преобразованной в timestamp
            start_point_data = datetime.datetime.strptime(from_data, '%d.%m.%Y').timestamp()
            try:
                if user['last_seen']['time'] >= start_point_data:
                    active_list_by_time.append(user['id'])
                else:
                    un_active_list.append(user['id'])
            except:  # если дата посещения скрыта (раньше можно было скрыть, сейчас такой функции нет)
                un_active_list.append(user['id'])
    print(f"Количество подписчиков всего:   {total_users}")
    print(f"Активных подписчиков:           {len(active_list)} ({round(len(active_list) / total_users * 100, 2)}%)")
    print(f"Уделенных/забаненных:           {len(banned_list)} ({round(len(banned_list) / total_users * 100, 2)}%)")
    print(f'Активные за отведенное время:   {len(active_list_by_time)} ({round(len(active_list_by_time) / total_users * 100, 2)}%)')
    print(f'Неактивные за отведенное время: {len(un_active_list)} ({round(len(un_active_list) / total_users * 100, 2)}%)\n')
    return data_list

В конце функции выведем на печать наши статистические данные о группе, я их переработал в отличии от прошлой версии парсера ВК, которые представлены в старой статье и сделал более информативными и удобными, плюс там были неточности в подсчетах. Все суммы и проценты результатов сходятся с реалиями и соответствуют действительности.

    print(f"Количество подписчиков всего:   {total_users}")
    print(f"Активных подписчиков:           {len(active_list)} ({round(len(active_list) / total_users * 100, 2)}%)")
    print(f"Уделенных/забаненных:           {len(banned_list)} ({round(len(banned_list) / total_users * 100, 2)}%)")
    print(f'Активные за отведенное время:   {len(active_list_by_time)} ({round(len(active_list_by_time) / total_users * 100, 2)}%)')
    print(f'Неактивные за отведенное время: {len(un_active_list)} ({round(len(un_active_list) / total_users * 100, 2)}%)\n')

Изменения в основной функции parser

И последний штрих, подредактируем основную функцию нашего парсера Вконтакте

def parser(group_list):
    from_data = input('Введите дату, с которой хотите отслеживать активность\nв формате: дд.мм.гггг: ')
    print(f'Анализируем с {from_data}\n')
    for group in group_list:
        print(f'Группа: {group}')
        try:
            users = get_users(group_id=group, from_data=from_data)
            save_excel(users, filename=f"users_of_{group}")
        except Exception as ex:
            print(f'{group} - не предвиденная ошибка: {ex}\n')
            continue

Добавив в нее функцию сохранения. Проходя по каждой заданной группы из списка, результат будет сохраняться в excel по 1 группе отдельно. И так время тестирования, запустим наш обновленный парсер vk.com

Запуск парсера Вконтакте и сравнение с прошлой версией

Запускаем наш парсер. Я его запускаю на момент написания статьи 05.09.2024, буду анализировать свою группу за последние два месяца, то есть с 05.07.2024 (интервал в 2 месяца выбран потому что, в прошлой статье было так же)

запуск улучшенного парсера ВК и вывод результата по группе happython в 2024 году

А вот такой вывод был в старой статье:

результат старого парсера ВК и вывод результата по группе happython в 2022 году

Приятно видеть, что количество подписчиков выросло вдвое, но и удаленных/забаненных подписчиков не мало, целых 228 человек. Процент активности ~80% результат приемлемый, радует.

Смотрим excel с результатами парсинга группы ВКонтакте

Самая вишенка на торте, это наши собранные данные по подписчикам, которые мы можем анализировать и делать выводы, кто с какого города, с какой площадки сидел, какого пола, возраста и сколько их всего

Итоги парсинга пользователей в группе Вконтакте

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

Дополнительно, если дописать пару моментов, можно сделать чистку группы ВК от удаленных/забаненные пользователей, через специальные методы VK API, но это уже совсем другая история.

Вступайте в нашу группу ВКонтакте: HappyPython

Телеграм канал: Happy Python | Парсинг Фриланс Обучение🐍

Партнерский телеграм канал: Backend development 💻

Ссылка на код GitHub

Ссылка на нашу самую популярную статью: Парсер Wildberries (а так же запустили бота в телеграм для парсинга Вайлдберриз, канал парсера Тимур и его блог )