Pull to refresh

VkInviter – приглашатель-помощник администраторам групп ВКонтакте

Ruby *C# *
Sandbox
Всем доброго дня!

Я являюсь администратором одной музыкальной группы ВКонтакте (далее – ВК). Музыканты часто ездят с гастролями по разным городам России и странам СНГ. Один из способов оповестить фанатов группы о предстоящем концерте в их городе – разослать приглашения на соответствующую встречу ВК.
В статье хочу показать одно из возможных решений этой задачи.

Надеюсь, что данная статья будет полезна другим администраторам групп, количество приглашений пользователей на события не в их городе уменьшится и больше людей разблокирует возможность приглашать их на встречи!


Прежде всего, вы должны являться администратором группы ВК и данная группа должна быть организатором встречи в ВК.

Решение «Все сделать вручную»

Существующий интерфейс позволяет сделать такую рассылку вручную через меню встречи:
«Пригласить друзей» – «Пригласить участников группы»:


Минусы этого решения очевидны:
  • Долго, т.к. в некоторых городах количество участников больше нескольких тысяч
  • Невозможно выполнить приглашение участников, проживающих в определенном городе


Решение «Автоматизировать процесс»

Здесь есть два подхода: написать приложение с помощью ВК 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 с адресом, на который будет выполнен редирект:
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&section=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.
Главное окно программы представлено на скриншоте:
image
Помимо описанного алгоритма, программа позволяет делать выборку по нескольким городам, что актуально, когда приглашения рассылаются не только по городу, но и по ближайшим областям.

Исходный код выложен на github, также выложен скрипт на ruby, который может быть полезен для понимания общей логики.

Заключение

В заключении хочу сказать, пару слов об эффективности.
Заметил, что приблизительно 60% всех пользователей запретили приглашать себя на встречи.
Из принявших приглашение на встречу приходит где-то 10%.
Не знаю, как долго этот функционал останется в ВК и почему возможность пригласить всех была выпилена несколько лет назад.

Исходным кодом может пользоваться любой желающий по своему усмотрению.
Tags:
Hubs:
Total votes 37: ↑8 and ↓29 -21
Views 94K
Comments Comments 9