![](http://habrastorage.org/getpro/habr/post_images/a7b/5b4/ab1/a7b5b4ab1b2291c17aa51416c0e7c5aa.jpg)
Я являюсь администратором одной музыкальной группы ВКонтакте (далее – ВК). Музыканты часто ездят с гастролями по разным городам России и странам СНГ. Один из способов оповестить фанатов группы о предстоящем концерте в их городе – разослать приглашения на соответствующую встречу ВК.
В статье хочу показать одно из возможных решений этой задачи.
Надеюсь, что данная статья будет полезна другим администраторам групп, количество приглашений пользователей на события не в их городе уменьшится и больше людей разблокирует возможность приглашать их на встречи!
Прежде всего, вы должны являться администратором группы ВК и данная группа должна быть организатором встречи в ВК.
Решение «Все сделать вручную»
Существующий интерфейс позволяет сделать такую рассылку вручную через меню встречи:
«Пригласить друзей» – «Пригласить участников группы»:
Минусы этого решения очевидны:
- Долго, т.к. в некоторых городах количество участников больше нескольких тысяч
- Невозможно выполнить приглашение участников, проживающих в определенном городе
Решение «Автоматизировать процесс»
Здесь есть два подхода: написать приложение с помощью ВК API или standalone через post-get запросы.
После анализа я понял, что ВК API не подходит. В описании нет метода приглашения пользователя на встречу, да и не очень-то хочется связываться с регистрацией приложения и прочими внутренними правилами ВК.
Следовательно, придется анализировать post-get запросы, и написать «симулятор» пользователя.
Рассмотрим основные этапы работы:
- Авторизация пользователя
- Получение участников группы в определенном городе
- Рассылка приглашений
Авторизация
С логином все достаточно просто – POST запрос по адресу login.vk.com:
act=login&q=1&al_frame=1&expire=1&captcha_sid=&captcha_key=&from_host=vk.com&from_protocol=http&email=USERNAME&pass=PASSWORD
В ответ получаем параметр location с адресом, на который будет выполнен редирект:
http://vk.com/login.php?act=slogin&al_frame=1&hash=bd7aed27961c325b407332b5855fa1c1&s=1
После редиректа в куки записывается параметр remixsid – идентификатор сессии, который является подтверждением успешной авторизации
Поклонники из города N
Для получения списка участников группы из определенного города воспользуемся стандартным поиском vk.com/search, нам особенно важен этот набор фильтров:
Выполнить поиск по участникам группы можно со страницы группы, при этом запрос будет иметь вид:
al_search.php?al=1&c[group]=6206&c[section]=people
где group — id группы.
После добавления фильтрации по стране и городу запрос примет вид:
al_search.php?al=1&c[city]=1&c[country]=1&c[group]=6206&c[section]=people
где, соответственно, city — id города, country — id страны
Ответом на запрос является список пользователей.
Заголовок ответа несет в себе два важных значения:
"has_more":true,"offset":200
has_more — определяет, будут ли еще пользователи в выдаче
offset — «отступ» или сдвиг от первого пользователя
Блок с информацией об одном пользователе имеет вид:
<div class="people_row three_col_row clear_fix"> <div class="img search_bigph_wrap fl_l" onmouseover="Searcher.bigphOver(this, 1746355)"> <a href="/romasladky" onclick="return nav.go(this, event);"><img class="search_item_img" src="http://cs425828.vk.me/v425828355/11c7e/WlD9D-hBeJI.jpg" /></a> </div> <div class="info fl_l"> <div class="labeled name"><a href="/romasladky" onclick="return nav.go(this, event);">Рома Сладкин</a></div><div class="labeled ">Климатпрофф</div><div class="online">Online</div> </div>
В этом блоке интересны данные:
- id
- имя
- href на страницу
Парсить ответ достаточно удобно с помощью регулярных выражений.
Для получения id использую такое выражение:
"<div[^>]*onmouseover=\"Searcher.bigphOver\\(this, (\\d+)\\)\">"
Для получения имени и href:
"<div class=\"labeled name\"><a href=\"/([^\"]+)\" onclick=\"return nav\\.go\\(this, event\\);\">([^<]+)<";
В данном подходе есть одно синтетическое ограничение — контакт не выдает более 1000 результатов поиска. Это критично, т.к., например, в Москве у группы 3000+ участников. Что бы обойти это ограничение придется добавить дополнительную фильтрацию на пользователей, а затем объединить результаты работы всех фильтров.
Из доступных надо выбрать только те фильтры, у которых значения фиксированы и их не так много.
Для этой задачи подойдут:
Пол — [sex], значения: 0-2
Порядок сортировки – [sortId], значения 0-1
Семейное положение – [statusId], значения 0-7.
На ruby этот перебор выглядит так:
offset=0 for sort_id in 0..1 do for status_id in 0..7 do for sex_id in 0..2 do offset=0 begin get_str = "/al_search.php?al=1" get_str += "&c[city]=#{city_id}" if city_id.to_i>0 get_str += "&c[country]=#{country_id}" if country_id.to_i>0 get_str += "&c[group]=#{group_id}" get_str += "&c[name]=1&c[section]=people" get_str += "&c[sex]=#{sex_id}" if sex_id>0 get_str += "&c[sort]=#{sort_id}" if sort_id>0 get_str += "&c[status]=#{status_id}" if status_id>0 get_str += "&offset=#{offset}" if offset>0 ...
Таким образом будет получен список всех пользователей в городе.
Если будем делать отправку приглашений вручную, то заметим, что оно отправляется методом POST:
act=a_invite&al=1&gid=65898108&hash=99247d766b77d7a584&mid=22935
где gid – id встречи, mid – id пользователя, hash – некий хэш, несущий информацию о приглашающем. Вот этот-то хэш теперь надо получить для всех пользователей из нашего списка.
Получение hash
Для получения хэша придется парсить список «друзей», которых я могу пригласить на встречу. Друзья указаны в кавычках, т.к. здесь под этим понятием выступают все участники группы-организатора.
GET-запрос получения этого списка выглядит так:
vk.com/friends?act=get_section_friends&al=1&gid=65898108&offset=0§ion=members&sugg_rev=0
, где gid – id встречи
Ответом будет является json-строка с набором блоков вида:
['1298','http://cs315422.vk.me/u01298/d_e13351b2.jpg','/id1298','2','0','Сергей Суворов','0','1','61','','0','2d9d4211c2297c3a06']
где 1-й параметр – id пользователя, а последний – нужный нам хэш.
Обработка этих данных выполнена с помощью регулярного выражения:
@"\['(\d*)','[^']*','\/([\w\.]+)','[^']*','[^']*','([^']+)','[^']*','(\d+)','[^']*','[^']*','[^']*','(\w+)'\]"
Формат данного ответа меняется достаточно часто, поэтому в программе был сделан трюк: дополнительно происходит вычисление количества ссылок на аватарки (2-параметр) и проверка совпадения количества аватарок и пользователей после обработки.
На С# эта проверка выглядит так:
string patternNorm = @"'http:\/\/cs\d+\.vk\.me"; string patternDeactiveOrDeleted = @"'\/images\/\w+\.gif'"; MatchCollection mcNorm = Regex.Matches(responseString, patternNorm); MatchCollection mcDeactiveOrDeleted = Regex.Matches(responseString, patternDeactiveOrDeleted); int httpCount = mcNorm.Count + mcDeactiveOrDeleted.Count; if (listVkUser.Count != httpCount) { throw new Exception("http total count != user count"); }
После обработки списка «друзей» и слияния его со списком пользователей из города все готово к рассылке приглашений.
В процессе рассылки было выяснено, что через каждые 40 приглашений необходимо вводить капчу, ссылка на капчу выдается в виде:
captcha.php?sid={1}&s=1
, где sid – уникальный id данной капчи.
При каждом запросе по данному url будет выдаваться новая картинка с капчей.
Здесь – единственное место, где в процессе требуется участие пользователя и ручной ввод.
Программа VkInviter
Для автоматизации перечисленных действий написана программа VkInviter.
Главное окно программы представлено на скриншоте:
Помимо описанного алгоритма, программа позволяет делать выборку по нескольким городам, что актуально, когда приглашения рассылаются не только по городу, но и по ближайшим областям.
Исходный код выложен на github, также выложен скрипт на ruby, который может быть полезен для понимания общей логики.
Заключение
В заключении хочу сказать, пару слов об эффективности.
Заметил, что приблизительно 60% всех пользователей запретили приглашать себя на встречи.
Из принявших приглашение на встречу приходит где-то 10%.
Не знаю, как долго этот функционал останется в ВК и почему возможность пригласить всех была выпилена несколько лет назад.
Исходным кодом может пользоваться любой желающий по своему усмотрению.
ссылка на оригинал статьи http://habrahabr.ru/post/213773/
Добавить комментарий