Добрый день.
У меня осталось 15 минут до конца обеденного перерыва (это важно), завтра выходной, а потому прошу мой пост приравнивать к пятничному.
В своем недавнем посте товарищ ParadoxFilm исследовал связи между участниками одной из групп «ВКонтакте», саму группу оставив анонимной. Поскольку в статье фигурировали реальные люди — участники группы, анонимизация по названию меня удивила. Процесс «деанонимизации» — под катом.



Итак, есть три человека юзера: id97723 — Валерий Окунев, id206186029 Глеб Коломиец, id105522823 Ингруп Стс. Все они участники одной группы почти на 16000 человек, группа университетская. Задача: отыскать группу.

Первым делом я открыл контакты юзеров — если уж истина где-то рядом, почему бы ей не быть там? Один товарищ упоминает КВН с выступающей командой ВШЭ, другой там учился (третий состоит в группе dotNet разработчиков, привет, коллега). Окей, ищем группы по названию «ВШЭ». Результатов десятки, но поиск контакта удобно сортирует их по числу участников. Группы с 16 000 юзеров нет. Шерлок Холмс знал бы самые часто используемые синонимы, но мое имя даже на Ш не начинается.

Так что я расчехлил свою привычную VS2015 с Dark Theme, и скачал VkNet библиотеку — она первая попалась в гугле. Обновил все необходимые NuGet пакеты, сориентировал проект на .net framework 4, накидал код
        private static readonly int[] UserIds = { 97723, 206186029, 105522823 }; 
        private static readonly VkApi Api = new VkApi();

        static void Main(string[] args)
        {
            var zeroUserGroups = GetUserGroups(UserIds[0]);
            Thread.Sleep(1000);
            Console.WriteLine($"Groups for id {UserIds[0]}: {zeroUserGroups.Count}");


            var firstUserGroups = GetUserGroups(UserIds[1]);
            Thread.Sleep(1000);
            Console.WriteLine($"Groups for id {UserIds[1]}: {firstUserGroups.Count}");


            var secondUserGroups = GetUserGroups(UserIds[2]);
            Thread.Sleep(1000);
            Console.WriteLine($"Groups for id {UserIds[2]}: {secondUserGroups.Count}");

            // Тут мы ищем группы, встречающиеся в наборах всех юзеров.
            // Эх, надо было сразу вместо групп идентификаторы выделять
            var groupsIntersection = zeroUserGroups
                .Where(group => firstUserGroups.Any(insGroup => insGroup.Id == group.Id))
                .Where(group => secondUserGroups.Any(insGroup => insGroup.Id == group.Id))
                .ToList();            
        }

        private static ReadOnlyCollection<Group> GetUserGroups(long userId)
        {
            GroupsGetParams getUserGroupParams = new GroupsGetParams() {UserId = userId};
            return Api.Groups.Get(getUserGroupParams);
        }


и словил баттхерт исключение. Неавторизованный доступ, все дела. Пришлось регистрироваться в контакте, создавать приложение, копипастить applicationId, mail моей странички и мой же пароль в код (не повторяйте это в продакшне).

В итоге в самом начале метода Main появился код
            ApiAuthParams authParams = new ApiAuthParams
            {
                ApplicationId = myAppId,
                Login = "my@mail.com",
                Password = "myPagePassword",
                Settings = Settings.All
            };
            Api.Authorize(authParams);


В итоге все заработало, я получил лист из двух групп: 25205856, 66036248. Вторая группа называется «The Вышка», в ней сейчас 15968 человек. Среди них, кстати, и автор первоначальной статьи.
Удачи тебе в IT, бро.
P.S. Процесс поиска занял 45 минут, «за 15 минут я еще и бутерброд доесть успею».
Поделиться с друзьями
-->

Комментарии (16)


  1. riot26
    23.06.2016 15:16
    +1

    А зачем в коде логин/пароль? Можно ведь было обойтись более безопасным auth token`ом с правами только на нужные штуки.


    1. Oxoron
      23.06.2016 15:20

      Несомненно, oauth безопаснее. Другое дело, что мою одноразовую страницу не жалко, а авторизация логин-пароль-applicationId делается быстрее.


  1. LoadRunner
    23.06.2016 15:20
    +5

    А вот и здравый смысл:
    1. Открываем все три профиля.
    2. Делаем те же выводы про ВШЭ.
    3. Открываем «Интересные страницы» третьего профиля и смотрим на список.
    4. The Вышка у меня оказалась в самом верху и только у неё около 16к подписчиков.
    5. За минуту проверяем в первых двух профилях её наличие в аналогичном разделе.


    1. Oxoron
      23.06.2016 15:26

      Шампанского этому господину!
      Не знал, что «Интересные страницы» в контакте приравнены к группам.


      1. LoadRunner
        23.06.2016 15:34

        Мне просто повезло :)
        Интересная страница — это что-то между личной страницей и группой.
        Давно заметил, что у тех, кто подписан на меня вконтакте (добавили в друзья) я попадаю в этот блок. Подозреваю, связано с общим числом друзей — когда оно переваливает за определённое число, личная страница трансформируется и где-то в недрах базы получает некий статус «интересности». Но это лишь моя теория.
        И при создании группы можно сразу определить — она будет создана именно как группа или просто Публичной страницей. Во втором случае она так же попадает в блок «Интересные страницы».
        Ну и у второго и третьего профиля даже блок групп не скрыт. А вот «интересные страницы» не скрываются вовсе (если это пункт «кого видно из моих друзей и подписок» в настройках приватности, то мало кто будет так заморачиваться для скрытия публичной группы). По третьему профилю вообще очень легко всё деанонимизируется.


      1. sshk
        23.06.2016 20:35

        А The Вышка — это не группа, а паблик. Поэтому ее и можно увидеть в интересных страницах.


  1. impwx
    23.06.2016 15:31
    +1

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


    1. Oxoron
      23.06.2016 15:41
      -2

      Вы абсолютно правы, статья не самая серьезная. Я честно постарался это выразить катом, первым абзацем и тэгами.


  1. ParadoxFilm
    23.06.2016 16:59

    Привет! Как было указано в комментах к моей статьи, ссылки на группу не было по причине того, что это запрещено правилами хабра. Конечно, узнать коей она является — труда не составит (ибо цель скрыть её никто не преследовал).
    По вашей статье: не понятно, зачем авторизация (методы получения списка групп пользователя доступны без этого). Также неясно, зачем использовать библиотеку (ведь есть API ВКонтакте).
    P.S. Лестно, что статья написана относительно моей. Спасибо, это было интересно!
    P.P.S. Группа, естественно, найдена верно.


    1. Oxoron
      23.06.2016 17:06

      Насчет авторизации — сам удивился. Возможно azhidkov (автор библиотеки) не учел этого момента. Кстати, библиотека как раз с API работает.


  1. lizarge
    23.06.2016 17:06
    +2

    Это хабрахабр или переписка студентов неудачников аналитиков тут? Если к первой статье можно было хоть что то разумное предьявить то тут уже нечего и сказать.
    Вау у вконтакте есть API а VS2015 с Dark Theme это конечно показатель глубокого профессионализма, если поставите Dark Green Theme то все девчата с соседнего ПТУ ваши конечно. Группы еще какие то в ВК, детский сад.


  1. kstep
    23.06.2016 17:49
    +3

    Что это за детский сад на главной? О чём это всё?


    1. drdoc
      23.06.2016 20:36

      А можно… Можно я тоже напишу как я скриптики на руби писал с вк апи??? Иль заминусуют меня за это. Хотя там и скриптики намного сложнее, чем «это». Но все же :)


  1. aquamakc
    23.06.2016 17:59

    int[] UserIds — тип Int32 передаётся в GetUserGroups(long userId) — тип Int64,
    Thread.Sleep(1000); — зачем?

    Да и вообще для хабра как-то слабовато.


    1. Oxoron
      23.06.2016 20:54
      -1

      1. В моем случае массив состоит из констант. Константы в пределах Int32, Int32 конвертится в Int64, потери времени не критичны.
      2. Thread.Sleep(1000); — у API есть ограничение по запросам в секунду. Точного значения не помнил, поэтому взял с запасом. Опять-таки, потеря 3 секунд — не проблема.