Собираем лайки

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

Допустим если взять функцию follFr, которая собирает друзей и подписчиков. То здесь всё замкнуто внутри этой функции. И если допустим друзей больше 5000 (пяти тысяч), а подписчиков больше 1000 (тысячи), то тогда используется цикл for, который делает своё дело отлично, но при работе немного подклинивает программу, пока не пройдёт весь цикл. Это ни каким образом не влияет на результат, но при работе программа выглядит скажем так не очень цивилизованно, потому что на ней, не возможно к примеру нажать какую-то кнопку, которая в свою очередь выполнила бы какое-то действие и это нажатие можно было бы сделать, не останавливая основную работу программы.
В предыдущих статьях: вк информация, об этом уже немного говорилось. Но именно в этой статье, сбор лайков в программе написан таким способом, что вот именно в тот момент, когда программа будет собирать лайки, можно будет допустим нажать кнопку, для того что бы паралельно основному процессу выполнилось какое-то действие.
Почему это было сделано именно с лайками? Потому что из всей информации, которая собирается с аккаунта с сайта ВКонтакте, на сбор лайков уходит не мало времени, по причине того, что лайки собираются с каждого объекта. То есть допустим если в аккаунте тысяч от пятидесяти до ста новостей или фотографий, то будет браться каждая новость или фото и с них уже будут собираться лайки. И на каждое такое действие будет делаться запрос. И так пятьдесят-сто тысяч раз.

Кстати насчёт комментариев ситуация такая же, тоже берётся каждый объект, допустим новость или фото и на каждый делаются запросы для сбора комментов.
Единственное отличие есть только у фотографий, если собирать комментарии не больше 10000 (десяти тысяч), то тогда их можно собрать со всех фотографий сразу используя метод photos.getAllComments. Но если же комментариев больше десяти тысяч и нам их нужно все собрать, то тогда уже используется метод photos.getComments и делая запрос к каждой фотографии, программа собирает комментарии. Всё это можно увидеть открыв исходники в функции photos.

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

Немного математики, допустим нам надо собрать лайки с десяти тысяч новостей. Такое количество новостей очень часто встречается в сайте ВКонтакте, даже в среднестатистических аккаунтах, которым далеко по своим объёмам до аккаунта Павла Дурова. И на каждой новости где-то примерно до пятидесяти лайков.
Так вот если брать программу написанную на Visual Studio, то при таких условиях программа будет делать от восьми до двенадцати запросов в секунду. В среднем берём десять запросов. Конечно такие условия будут выполнимы, если access token (токенов) будет от пяти, а лучше всего восьми штук.
И считаем, десять новостей в секунду, а новостей десять тысяч. На всё про всё, примерно выходит 1000 (тысяча) секунд или 16,66 минут.

От теории, перейдём к практике.
Добавлены новые элементы на первую форму в программе написанной на Visual Studio и новые компоненты на первую форму в программе написанной на Devel Studio. На будущее компонент будем называть элементом, так как это одно и то же. Смотрим фотографию с программы написанной на Visual Studio:

лайки вк
С фотографии видно что в программу добавлена кнопка STOP, с именем button6. Имя одинаковое и в Visual Studio и в Devel Studio.
Эта кнопка будет останавливать работу программы только тогда, когда программа собирает лайки. Если же программа не собирает лайки, то тогда на эту кнопку просто не будет возможности нажать, так как программа будет находится в клине. Ну а если даже и удастся каким-то способом нажать в тот момент когда программа выполняет другие функции кроме сбора лайков, то просто ничего не произойдёт, потому что в этих функциях насчёт этой кнопки ничего не прописано.
То есть ещё раз, эта кнопка работает только тогда когда собираются лайки. При её нажатии сбор лайкнувших пользователей остановится. Для того что бы его продолжить, надо будет нажать на кнопку START. Программа спросит да или нет, нажимаем да и остановленный процесс продолжится с того места, где он был остановлен.

Так же в программы добавлен второй элемент: таймер, который переименовываем в timerLikes. Это уже второй таймер по счёту, первый таймер идёт с именем timerPause.

И дальше немного рассмотрим сам код, который в программах будет использоваться для сбора лайков. Добавлено три глобальных переменных в Visual Studio:
public static Dictionary tLikes;
public static Dictionary tLikesInt;
public static bool stop = false;
И соответственно на Devel Studio:
$genvar = array(
"tLikes" => array(),
"stop" => 0
);
На PHP массив tLikes, так же будет содержать и значения массива tLikesInt с языка C Sharp.
Эти глобальные массивы создаются для того, что бы задавать им значения и в последствии передавать их на timerLikes. Для этого написана функция funcLikes, именно она задаёт значения этим массивам, а после запускает timerLikes, который уже в свою очередь использует значения этих массивов для работы. То есть получается что то наподобие цепочки, для того что бы задавать данные таймеру.
Ну и не трудно догадаться, что при нажатии на кнопку STOP, глобальной переменной stop будет задано значение true или значение 1 (один) в PHP.

Сам код который непосредственно собирает лайкнувших пользователей написан в таймере timerLikes. Суть этого таймера заключается в том, что он перебирает заданный массив с идентификаторами объектов и используя эти данные, делает один запрос на сайт ВКонтакте. Полученные данные сохраняются во временные файлы temp/log/reslikes.txt. Если массив не закончен, таймер запускает сам себя и со следующего запуска он уже берёт следующий элемент массива, опять делает запрос на сайт ВКонтакте и так далее пока массив не будет закончен.
С фотографии видно что файлу reslikes.txt, задаётся максимальное количество строк, которое по умолчанию равно 4500000 (четыре с половиной миллиона). Если количество строк будет больше, тогда программа создаст новый файл reslikes1.txt и следующие данные будет собирать уже в этот файл. Потом reslikes2.txt и так далее.
После того когда массив с идентификаторами объектов будет закончен, таймер запускает функцию с названием saveLikes, которая перемещает файлы reslikes.txt во временную папку аккаунта нашей базы с сайта ВКонтакте, предварительно обработав их функцией actives.

Что ещё хотелось бы добавить. То что если в объекте будет больше тысячи лайков, тогда таймер timerLikes для сбора всех лайков с одного объекта запустит цикл for. Это значит, что если в объекте предположим 9000 (девять тысяч) лайков, а с одного запроса можно взять не больше тысячи, то тогда циклом for, будет сделано ещё восемь запросов, для того что бы взять все девять тысяч. И пока будут делаться вот эти восемь запросов, программу опять же немного подклинит.
Конечно можно было бы глобальным массивам tLikes задать ещё и переменную offset, для того что бы таймер timerLikes перезапускал бы себя и в таких случаях, но оставим это для следующих программ, а пока что достаточно и этого.

Просто вся эта схема с таймером timerLikes была представлена для примера. Для того что бы те кто не знает, увидели как это делается. Ну и конечно для удобства, потому что как было сказано выше, на сбор лайков уходит больше времени чем на остальные функции, которые собирают информацию. Удобно когда программу можно в любой момент приостановить, а потом продолжить с того места где остановили, ну и так далее.

Следующим шагом немного рассмотрим поочерёдность событий, которые происходят в программе при сборе информации с сайта ВКонтакте.
В предыдущих статьях мы остановились на том, что функцией photos была собрана информация за фотографии с аккаунта Павла Дурова. После того как это было сделано, в папке temp/log программа сохранила два файла:
- Файл photos_getAllikes.txt, который содержит в себе список идентификаторов фотографий в которых есть хоть один лайк.
- Файл photos_AllCommentsLikes.txt, который содержит в себе список идентификаторов комментариев фотографий в которых есть хоть один лайк.

Дальше следим за ходом событий.
1. После того когда функция photos заканчивает свою работу, она запускает таймер timerPause и через глобальную переменную genvar.timerPause задаёт ему параметр: photosLikes. Этот параметр указывает на то, что ведётся сбор лайков по фотографиям.
2. После этого таймер timerPause по очереди перебирает все файлы которые находятся в папке temp/log. Первым происходит поиск файла photos_getAllikes.txt, после того когда этот файл найден, таймер timerPause запускает функцию funcLikes, передавая ей все необходимые параметры.
3. В свою очередь функция funcLikes запускает таймер timerLikes, точно так же передавая ему все необходимые параметры, которые обозначены в массивах tLikes.
4. После того когда таймер timerLikes полностью обработает весь заданный массив с идентификаторами объектов, данные для которых были взяты с файла photos_getAllikes.txt, в таймере timerLikes файл photos_getAllikes.txt удаляется за ненадобностью и запускается функция saveLikes, которая сохраняет полученные данные во временную папку аккаунта нашей базы с сайта ВКонтакте, предварительно обрабатывая их функцией actives.
5. После этого функция saveLikes опять запускает таймер timerPause и через глобальную переменную genvar.timerPause задаёт ему тот же параметр: photosLikes.
6. После этого таймер timerPause опять по очереди перебирает все файлы которые находятся в папке temp/log. Первым происходит поиск файла photos_getAllikes.txt, а так как этого файла уже нет, то вторым идёт поиск файла photos_AllCommentsLikes.txt, после того когда этот файл найден, запускается всё по новой, только уже с данными, которые содержит в себе файл photos_AllCommentsLikes.txt.
7. Ну и в конце, когда таймер timerPause с заданным параметром photosLikes не находит в папке temp/log ни одного файла связанного с фотографиями, тогда таймер будет запускать уже следующее действие, допустим сбор информации по новостям. Только это ещё не прописано.

Ну и дальше смотрим на скриншот программы написанной на Visual Studio, который был сделан во время сбора программой лайкнувших пользователей:
скачать лайки вк
Обращаем внимание на предпоследнюю строчку: LIKES (7887493), которая показывает что все фотографии в аккаунте Павла Дурова лайкнуло семь миллионов восемьсот восемьдесят семь тысяч четыреста девяносто три пользователя. Соответственно программа сохранила всех этих пользователей в списках во временной папке, куда собиралась информация по аккаунту Павла дурова. То есть уже в нашей базе с сайта ВКонтакте. По времени видно что все лайки с фотографий Павла Дурова собирались 38 минут.
Смотрим на адреса файлов, в которых были сохранены списки всех этих пользователей:
GENRES/Accounts/id1/2020-02-20_002158/photos/uslikes.txt
GENRES/Accounts/id1/2020-02-20_002158/photos/uslikes1.txt
GENRES/Accounts/id1/2020-02-20_002158/photos/uslikes2.txt
GENRES/Accounts/id1/2020-02-20_002158/photos/uslikes3.txt
Конечно же все пользователи в этих файлах распределены по активности, то есть пропущены через функцию actives.

И далее обратим внимание на последнюю строчку, а именно цифру 83014. Скриншот был сделан в тот момент, когда программа собирала лайки со всех комментариев, со всех фотографий Павла Дурова. Количество всех лайков, можно было посмотреть открыв файл photos_AllCommentsLikes.txt, в котором был список всех идентификаторов этих комментариев. И полное их количество было: 84835 (восемьдесят четыре тысячи восемьсот тридцать пять) лайков.
И в программе вот эта цифра постоянно уменьшается на единицу, то есть постоянно отнимается минус один. И отнимание происходит со скоростью примерно где-то от десяти до двадцати раз в секунду. То есть это скорость запросов программы, которые делает таймер timerLikes. Со стороны это как бы напоминает секундомер, который очень быстро отсчитывает назад заданное количество времени.
В это время если нажать кнопку STOP, то сбор лайков прекратился бы. А потом при нажатии на кнопку START, был бы продолжен с того места где был остановлен.

И теперь смотрим скриншот с этой же программы после того, когда сбор лайков с комментариев был закончен:
Последняя строчка: LIKES COMMENTS (189987), говорит о том, что общее количество пользователей лайкнувших все комментарии Павла Дурова по фотографиям, сто восемьдесят девять тысяч девятьсот восемьдесят семь пользователей. По времени это проделалось где-то за два часа. Что примерно совпадает с нашими расчётами десять тысяч запросов за 16,66 минут. Конечно плюс минус, но примерно совпадает.
Все лайкнувшие комментарии пользователи поместились в один файл и путь к этому файлу получается вот такой:
GENRES/Accounts/id1/2020-02-20_002158/photos/comments/uslikes.txt
Все эти пользователи были пропущены через функцию actives и распределены по активности. Вот первые десять пользователей из этого файла:
3086 : 137301896
2209 : 100276107
2010 : 131662841
1791 : 315044464
697 : 119942563
656 : 377877233
599 : 334119622
384 : 250943247
364 : 148058154
336 : 305013868
И ещё одно небольшое замечание, которое возникло именно как раз тогда, когда собирались все лайкнувшие пользователи с комментариев фотографий Павла Дурова. Так как лайков на комментариях не очень много, то ответы с информацией, которые приходят с сайта ВКонтакте, по объёму не очень большие и скорость запросов и ответов иногда возрастает до двадцати раз в секунду, а иногда даже больше.
Так вот, именно в этот момент появилась новая ошибка, которая раньше нам ещё не встречалась: Rate limit reached, что в переводе значит: Достигнут предел скорости.
Сначала при сборе информации было пять access token (токенов) и эта ошибка возникла. Потом было добавлено ещё три access token (токена), то есть в сумме их стало восемь и через каждый запрос соответственно они менялись, но эта ошибка всё равно появлялась. Вот полный лог этой ошибки, смотрим один из примеров:
2020.02.20 03:12:35
https://api.vk.com/method/likes.getList?type=photo_comment&owner_id=1&item_id=637012&count=1000&access_token=******&v=5.102
{"error":{"error_code":29,"error_msg":"Rate limit reached","request_params":[{"key":"type","value":"photo_comment"},{"key":"owner_id","value":"1"},{"key":"item_id","value":"637012"},{"key":"count","value":"1000"},{"key":"v","value":"5.102"},{"key":"method","value":"likes.getList"},{"key":"oauth","value":"1"}]}}
Сначала время, потом запрос на ВК и ответ с сайта ВКонтакте.
Возникает эта ошибка на какие-то определённые access token (токены), но так как они через каждый запрос меняются, то это очевидно ситуацию и спасает.
Ошибка эта появлялась кратковременно и на общее время сбора информации, она практически не повлияла. И переживать за качество сбора информации тоже нет причин, так как эта ошибка не внесена в исключения и функция resHtml при появлении такой ошибки делает повторный запрос с теми же параметрами и с другим access token (токеном) получает нужный ответ с сайта ВКонтакте.
Ну а те access token (токены), которые выдают эту ошибку через какое-то время приходят в норму и включаются в общую работу.
Чем-то эта ошибка похожа на: Too many requests per second, что в переводе: Слишком много запросов в секунду. Но очевидно Rate limit reached, это уже тогда, когда действительно скорость зашкаливает.
Программе написанной на Devel Studio, такая ошибка не грозит, так как скорость запросов у этой программы, намного меньше чем у программы написанной на Visual Studio. По крайней мере имеются в виду программы, которые написаны в нашем варианте.
Ну а насчёт программы написанной на Visual Studio, тут можно сказать только то, что она своей скоростью запросов даже удивляет и конечно же приятно удивляет. Потому что при сборе информации с таких известных социальных сетей как сайт ВКонтакте, скорость при работе очень и очень важна.
Вот такое небольшое маленькое явление, скажем так, которое имеет место быть и о котором конечно же стоило упомянуть.

Исходник программы написанной на Visual Studio infgo.ru_vs_test.zip.
И исходник программы написанной на Devel Studio infgo.ru_ds_test.zip
Пароль в архивах infgo.ru
В этих исходниках есть всё, включая так же и сами коды программ, которые можно посмотреть в обычном текстовом редакторе.

Следующим шагом в написании программы по сбору информации с аккаунтов сайта ВКонтакте, будет уже сбор новостей.
Программы
infgo.ru