hazzus / liker-group-script Goto Github PK
View Code? Open in Web Editor NEWLikes people from group
Likes people from group
Новые сущности и переменные:
black_list_users, Черный список пользователей
black_list_words, Черный список слов
white_list_words, Белый список слов
deep, "глубина прохода", по умолчанию 100
max_white_world_list_liked, "максимальное количество постов со словами из белого списка", по умолчанию 5
like_amount, "количество лайков", по умолчанию 5
like_distance, "расстояние между лайками", вычисляется в процессе работы
min_like_distance, "минимальное расстояния между лайками", по умолчанию 2
likes_delay, "задержка между лайками", по умолчанию 30 секунд
api_get_delay, "задержка между остальными запросами API (получения данных), по умолчанию 0,5с
1)Перед работой получаем список моих друзей (каждый раз при запуске).
2)Получаем очередного пользователя из группы. Проверяем, есть ли он у меня в друзьях, или в черном списке пользователей. Если есть там или там — переходим к следующему пользователю.
3)Посмотреть, есть ли лайк у последнего (не закрепленного, а именно последнего, не знаю, как это в API отображается) поста человека. Если есть — то завершаем работу и переходим к следующему пользователю. Если нет — ставим.
4)Взять из настроек deep, проходим по стене человека, получая его посты, ограничиваясь deep. Если постов меньше, чем deep, собираем все. Если у какого-то поста увидели уже поставленный нами лайк — останавливаемся на этом посте(больше не собираем). Если у поста встретились слова из черного списка из настроек, то не заносим этот пост в таблицу. Если у поста встретились слова из белого списка, то заносим этот пост в отдельную таблицу, но не более max_white_world_list_liked
5)Взять из настроек like_amount. Разделить количество постов в таблице для текущего пользователя на like_amount, получить like_distance. Если оно меньше min_like_distance из настроек, то использовать в качестве like_distance значение min_like_distance.
6)Имея список постов из пункта 2, вычисляем позиции постов в списке так, чтобы между ними было не менее like_distance. Случайным образом сдвигаем позиции на величину like_distance/5, но не менее 1:
Посты 1,2,3,4,5,6,7,8,9,10, like_amount=2, like_distance=10/2=5. Позиции постов 1,2,3,[4],5,6,7,8,9,[10]. Рандомизация позиций на величину 5/5=1: 1,2,3,4,[5],6,7,8,[9],10.
7)Лайкаем посты из позиций в списке и посты из таблицы с постами со словами из белого списка, используя задержку.
В работе используются две разные задержки: между запросами данных, и между лайками.
Список стоп-слов по умолчанию: https://pastebin.com/9Uqc8Xn6
Поддержка маски "*"(любое количество любых символов до следующего пробеоа) в стоп-словах.
На страничке один пост, в логах:
Лайкаю пост 20 пользователя 50789452
Лайкаю пост 20 пользователя 50789452
Лайкаю пост 20 пользователя 50789452
Лайкаю пост 20 пользователя 50789452
Я правильно понимаю, что сейчас скрипт завязан на аккаунт приложения вк, которое создал ты?
Я имею ввиду "https://oauth.vk.com/authorize?client_id=6004708"
Если в процессе работы пропадет сеть, падает. Надо корректно обрабатывать и ждать восстановления связи, не завершая работу
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 387, in _make_request
six.raise_from(e, None)
File "<string>", line 2, in raise_from
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 383, in _make_request
httplib_response = conn.getresponse()
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1331, in getresponse
response.begin()
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 297, in begin
version, status, reason = self._read_status()
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 258, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 1009, in recv_into
return self.read(nbytes, buffer)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 871, in read
return self._sslobj.read(len, buffer)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ssl.py", line 631, in read
v = self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 440, in send
timeout=timeout
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 639, in urlopen
_stacktrace=sys.exc_info()[2])
File "/usr/local/lib/python3.6/site-packages/urllib3/util/retry.py", line 357, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/usr/local/lib/python3.6/site-packages/urllib3/packages/six.py", line 686, in reraise
raise value
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 601, in urlopen
chunked=chunked)
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 389, in _make_request
self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
File "/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 309, in _raise_timeout
raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value)
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='api.vk.com', port=443): Read timed out. (read timeout=10)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "main.py", line 141, in <module>
work()
File "main.py", line 130, in work
like(u_id, info.likes_amount)
File "main.py", line 64, in like
info.api.likes.add(type='post', owner_id=user_id, item_id=p[u'id'], v=info.V)
File "/usr/local/lib/python3.6/site-packages/vk/api.py", line 173, in __call__
return self._api._session.make_request(self)
File "/usr/local/lib/python3.6/site-packages/vk/api.py", line 67, in make_request
response = self.send_api_request(method_request, captcha_response=captcha_response)
File "/usr/local/lib/python3.6/site-packages/vk/api.py", line 115, in send_api_request
response = self.requests_session.post(url, method_args, timeout=timeout)
File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 555, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "/usr/local/lib/python3.6/site-packages/vk/utils.py", line 78, in request
response = super(LoggingSession, self).request(method, url, **kwargs)
File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 508, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python3.6/site-packages/requests/sessions.py", line 618, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python3.6/site-packages/requests/adapters.py", line 521, in send
raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host='api.vk.com', port=443): Read timed out. (read timeout=10)
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](23:12):
UPD: а еще он после этого что-то сделал с токеном, и пришлось его получать заново.
[vvzvlad@MBP](23:12): python3 main.py
Токен неверный!
Токена нет, или он неверный, сейчас будет регистрация
ВНИМАНИЕ. Через 6 секунд откроется сайт аутентификации, не закрывайте вкладку после разрешения доступа
Продолжает ставить лайки, несмотря на ошибку. Надо обрабатывать любые ситуация, отличные от корректного кода завершения, а не обрабатывать выборочно несколько ошибок. Лучше упасть, что делать вид что хорошо, но глючить.
Конкретно по этой ошибке — надо повторять попытки лайка этого поста через час в цикле, пока не вк не вернет корректный статус завершения.
9. Flood control. request_params = {'oauth': '1', 'method': 'likes.add', 'type': 'post', 'owner_id': '6350057', 'item_id': '3775', 'v': '5.73'}
Лайкаю пост 14846 пользователя 6361769
9. Flood control. request_params = {'oauth': '1', 'method': 'likes.add', 'type': 'post', 'owner_id': '6361769', 'item_id': '14846', 'v': '5.73'}
Лайкаю пост 14936 пользователя 6361769
9. Flood control. request_params = {'oauth': '1', 'method': 'likes.add', 'type': 'post', 'owner_id': '6361769', 'item_id': '14936', 'v': '5.73'}
Лайкаю пост 14933 пользователя 6361769
9. Flood control. request_params = {'oauth': '1', 'method': 'likes.add', 'type': 'post', 'owner_id': '6361769', 'item_id': '14933', 'v': '5.73'}
Неправильно работает. "init" должен создавать, либо обнулять конфигурацию. Всю конфигурацию, включая токен. "update token" должен только обновлять токен.
Т.е. в init надо добавить получение токена первичное, чтобы не запускать еще и "update token" при первой настройке
При первом запуске открыл страницу сайта, но сразу же закончил работу, не дав вставить токен. Со второго раза сработало.
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:50): python3 main.py
Токена нет, или он неверный, сейчас будет регистрация
ВНИМАНИЕ. Через 6 секунд откроется сайт аутентификации, не закрывайте вкладку после разрешения доступа
Введите ссылку/поле адреса открывшегося сайта:
Неверный токен(не найден). Запустите заново и разрешите доступ аутентификации
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:50): python3 main.py
Токена нет, или он неверный, сейчас будет регистрация
ВНИМАНИЕ. Через 6 секунд откроется сайт аутентификации, не закрывайте вкладку после разрешения доступа
Введите ссылку/поле адреса открывшегося сайта: [вставил токен]
Нужно реализовать универсальный обработчик капчи, который может построить запрос заново, основываясь на ответе с ошибкой от предыдущего запроса, потребовавшего капчу. Это освободит код от большого числа повторяющихся фрагментов, но придется вызывать eval()
. TODO есть в коде
Добавить в get_information_from_file информацию о том, сколько уже лайкнуто, а в лог выполнения — о том, сколько человек из какого количества в группе обработано:
Лайкаю пост 3882 пользователя 50959866 (230 из 858, 26% группы обработано)
Запускаю продолжение процесса (обработано 230 пользователей)
Процесс реконфигурирования должен заменять и токен, даже если он валидный. Смысл в том, что init — способ заменить конфигурацию, в том числе и если мы хотим перейти на другого пользователя.
Однако, если у нас истек срок действия токена, то не надо думать, что пользователь захочет обновить и остальные параметры, скорее всего он захочет обновить только токен.
Т.е. такого быть не должно:
[vvzvlad@MBP](03:31): python3 main.py init
Token expired!
Starting auth process..
After 6 seconds, the authentication site will open, do not close the tab after allowing access
Paste link to open page: https://oauth.vk.com/blank.html#access_token=...
Token is okay
Variables are ok. Do you want to reconfigure them? (Y/n):
Configure variables:
Надо сделать так, чтобы init стирал все и конфигурировал заново, ничего не спрашиваю, а отдельный метод update_token — обновлял бы только токен.
Сделать для отладки режим(для #8 пригодится), в котором он принимает из командной строки (main.py one_people https://vk.com/id126292373) адрес пользователя и проходится по его страничке.
Если несложно, то в случае, если он будет принимать произвольное количество пользователей, будет еще лучше.
При прерывании в процессе настройки некрасиво падает. Можно KeyboardInterrupt обработать корректно?
Max likes on user page("inf" for infinity): ^CTraceback (most recent call last):
File "main.py", line 144, in <module>
info = WorkInformation()
File "/Users/vvzvlad/Downloads/тест/information.py", line 28, in __init__
self.get_information_from_user()
File "/Users/vvzvlad/Downloads/тест/information.py", line 111, in get_information_from_user
self.likes_amount = input('Max likes on user page("inf" for infinity): ')
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "main.py", line 153, in <module>
if info is not None:
NameError: name 'info' is not defined
Сейчас файл настроек такого вида
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:54): cat variables.log
5
2.0
test_group
2
Не очень понятно, что за переменные, а для из изменения надо удалять файл заново, и запускать инициализацию. Хочется:
1)Сделать человекочитаемый файл настроек, например JSON, чтобы было понятно, что там за параметры и поправить их ручками. Можно и ini-формат("delay=5"), но лучше JSON.
2)Сменить расширение на cfg, так как там не логи, а настройки
3)Сделать первую инициализацию не автоматической, а отдельной командой. Что-то вроде:
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:54): python3 main.py
Не могу начать работу: нет файла настроек, необходима первичная инициализация, выполните "main.py init"
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:58): python3 main.py init
[процесс логина и настройки]
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:58): python3 main.py
[нормальная работа]
[~/Documents/Проекты/liker-group-script][master]
[vvzvlad@MBP](21:58): python3 main.py init
Если вы продолжите, старый файл настроек будет удален после конца инициализации.
[процесс логина и настройки]
Смысл в том, что не надо смешивать бизнес-логику и интерактивные конфигураторы. Нормальная работа скрипта — это запуск его без параметров, и в случае каких-либо проблем(например, поврежденный или отсутствующий файл конфигурации), он должен о них сказать и упасть, а не висеть вечно с вопросом "давайте начнем настройку". Потому что он может быть запущен не на пользовательском терминале, а супервизором, и консоли, а тем более ввода пользователя там может не быть вообще, только перенос сообщений из STDOUT/STDERROR в логи. А так получится, что де-юре, с точки зрения супервизора, скрипт штатно работает(не падает), а де-факто он функции не выполняет, потому что ждет ответа пользователя.
Поэтому интерактивный конфигуратор — совершенно отдельная фича, которая крутая, но должна запускаться отдельной командой, в случае, если пользователь уверен, что он хочет запустить именно конфигуратор.
Ну и с точки зрения разных уровней, хорошо, если старая конфигурация будет стираться инициализацией, а не удалением файла, это делает интерфейс взаимодействия с программой единым — с помощью команд, а не смешивает команды и действия с файловой системой.
Если с помощью API можно несложно получить из номера пользователя текстовой ник пользователя(https://vk.com/vvzvlad), то стоит в консоль выводить их, нагляднее будет. Если это нетривиально, то некритично.
А что будет, если wb.open(site) и open_image(error.captcha_img) не смогут отработать? Например, он запускается в ssh-сессии или вообще без консоли.
Надо обработать и сделать fail-safe: показывать линк на страничку и капчу в консоли
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.