Как-то меня осенила мысль: «Зачем на работе постоянно прятать вкладку браузера с ВК от начальства, если можно ее замаскировать?»

И несмотря на то, что моему начальству в целом пофиг на социальные сети во время работы, через несколько минут проблема была решена довольно интересным способом, о котором я сейчас вам и расскажу.

Нам понадобятся:

  • Стандартные Python модули: os, sys, json, urllib2
  • Модуль для авторизации из этой статьи

Писать код мы будем собственно для Python версии 2.7, но при желании его можно оптимизировать и до третьей версии. Для нетерпеливых сразу дам ссылку на GitHub.

Итак, начнем


Первое и самое главное, что нам понадобится, это получить токен. Пример получения:

import vk_auth
app_id = "4925055"
access_token = vk_auth.auth(YOUR_LOGIN, YOUR_PASSWORD, app_id, "offline,messages")[0]

Предполагается, что выше указанный модуль авторизации лежит в одной директории с нашим скриптом и называется vk_auth.py

Теперь у нас есть токен и мы даже можем сделать какой-нибудь запрос. Давайте для примера получим JSON из 10 наших последних диалогов, преобразуем его в словарь и красиво выведем на экран:

import urllib2
import json
import vk_auth
app_id = "4925055"
login = raw_input(u"Enter your login: ")
password = raw_input(u"Enter your pass: ")

access_token = vk_auth.auth(login, password, app_id, "offline,messages")[0]
dialogs = json.loads(urllib2.urlopen("https://api.vk.com/method/messages.getDialogs?count=10&access_token=%s&v=5.33" % (access_token)).read().decode("utf-8"))
layer = ""
for item in reversed(dialogs["response"]["items"]):
	user = json.loads(urllib2.urlopen("https://api.vk.com/method/users.get?user_id=%s&fields=contacts,online&access_token%s&v=5.8" % (item["message"]["user_id"],access_token)).read().decode("utf-8"))["response"][0];
	if (user["online"] == 1):
		user["online"] = "online"
	else:
		user["online"] = "offline"
	layer+= "%s %s [%s] (%s):\n" % (user["first_name"], user["last_name"], user["online"], item["message"]["user_id"])
	layer+= "%s \n" % item["message"]["body"]
	layer+= "--------------------------------------------\n"

print (layer)

Теперь мы можем при запуске скрипта ввести свои данные для авторизации и получить список из 10 последних диалогов с пометкой в виде имени собеседника и его статусом.

Но ведь хотелось бы иметь возможность читать сообщения внутри конкретного диалога и отправлять сообщения. Хорошо, для этого мы создадим класс Connect, в котором опишем 3 метода для взаимодействия с API (получение диалогов, получение сообщений из диалога, отправка сообщения в рамках выбранного диалога) и метод-контроллер для возможности управлять вышеупомянутым функционалом.

Собственно весь код:

import os
import sys
import json
import urllib2
import vk_auth

os.system("clear")

app_id = "4925055"
login = raw_input(u"Enter your login: ")
password = raw_input(u"Enter your pass: ")

class Connect:
	def __init__(self,app_id,login,password):
		self.access_token = vk_auth.auth(login, password, app_id, "offline,messages")[0]
		print(self.access_token)
		self.layer = ""
		self.uid = ""
		self.section = ""

	def dialog(self, uid=False):
		if uid != self.uid and uid:
			self.uid = uid
		self.layer = ""
		self.section = "dialog"
		dialog = json.loads(urllib2.urlopen("https://api.vk.com/method/messages.getHistory?count=20&user_id=%s&access_token=%s&v=5.33" % (self.uid, self.access_token)).read().decode("utf-8"))
		for item in reversed(dialog["response"]["items"]):
			user = json.loads(urllib2.urlopen("https://api.vk.com/method/users.get?user_id=%s&fields=contacts&access_token%s&v=5.8" % (item["from_id"],self.access_token)).read().decode("utf-8"))["response"][0];
			self.layer+= "%s %s (%s):\n" % (user["first_name"], user["last_name"], item["user_id"])
			self.layer+= "%s \n" % item["body"]
			self.layer+= "-------------------------------------------- \n"

	def dialogs(self):
		self.layer = ""
		self.section = "dialogs"
		dialogs = json.loads(urllib2.urlopen("https://api.vk.com/method/messages.getDialogs?count=10&access_token=%s&v=5.33" % (self.access_token)).read().decode("utf-8"))
		for item in reversed(dialogs["response"]["items"]):
			user = json.loads(urllib2.urlopen("https://api.vk.com/method/users.get?user_id=%s&fields=contacts,online&access_token%s&v=5.8" % (item["message"]["user_id"],self.access_token)).read().decode("utf-8"))["response"][0];
			if (user["online"] == 1):
				user["online"] = "online"
			else:
				user["online"] = "offline"
			self.layer+= "%s %s [%s] (%s):\n" % (user["first_name"], user["last_name"], user["online"], item["message"]["user_id"])
			self.layer+= "%s \n" % item["message"]["body"]
			self.layer+= "--------------------------------------------\n"	

	def send(self, message):
		message = urllib2.quote(message).encode('utf8')
		dialog = json.loads(urllib2.urlopen("https://api.vk.com/method/messages.send?user_id=%s&message=%s&access_token=%s&v=5.33" % (self.uid, message, self.access_token)).read().decode("utf-8"))
		self.controll("r")

	def controll(self, input):
		print ("====LOADING====")
		if input == "d":
			self.dialogs()
		elif input == "exit":
			os.system("clear")
			sys.exit(0)
		elif input == "":
			self.layer = ""
		elif self.section == "dialogs":
			if input == "r":
				self.dialogs()
			else:
				self.dialog(input)
		elif self.section == "dialog":
			if input == "r":
				self.dialog()
			else:
				self.send(input)
		os.system("clear")
		print (self.layer)
		self.controll("%s" % raw_input("Enter command: \n"))


vk = Connect(app_id,login,password)
vk.controll("")

Итак, как это работает:

1. Мы вводим свой логин и пароль, которые сохраняются в переменные login и password соотвественно;
2. Создается объект класса Connect, в инициализирующий метод которого передаются логин, пароль и id приложение ВК;
3. В методе инициализации происходит получение токена и сохранение его в локальной переменной класса;
4. Происходит вызов метода controll класса Connect с параметром пустой строки, который очищает экран консоли;
5. Далее скрипт ждет нашей команды.

Команды таковы:

  • загрузка и отображение последних 10 диалогов осуществляется указанием «d»
  • обновление текущего раздела — «r»
  • пустая строка — очищает экран, чтобы никто не увидел ничего лишнего :)
  • для перехода к конкретному диалогу указываем ID нужного юзера
  • находясь внутри диалога, любой текст, не равный «r», «d», «» будет отправлен юзеру


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

Дублирую ссылку на GitHub.

Спасибо за внимание!

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


  1. grieverrr
    12.11.2015 11:13
    +14

    еще один изучил апи


    1. Andrey_Perelygin
      12.11.2015 12:12

      Это по-вашему плохо?


  1. sefus
    12.11.2015 11:41
    +5

    lynx m.vk.com
    


    1. Andrey_Perelygin
      12.11.2015 12:10
      -9

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


      1. HaruAtari
        12.11.2015 12:16
        +6

        Это вы не понимаете, что свой велосипед априори хуже готового, проверенного решения.


      1. grieverrr
        12.11.2015 12:18
        +9

        Данная статья несет в себе в первую очередь
        очередную нечитаемую порцию говнокода


  1. Crandel
    12.11.2015 13:11

    Советую приукрасить немного код, вынести урлы и другие данные в константы, использовать str.format() вместо устаревшего % ну и в этом же роде. На хабре много статей, как оптимизировать Python код


    1. Andrey_Perelygin
      12.11.2015 13:21
      +1

      Благодарю за совет. Займусь этим, как дойдут руки до переделки всего этого под 3 Python


  1. AleksandrFox
    12.11.2015 15:56

    я давно использую связку pidgin + openfire + vkxmpp. все работает. причем это дело настроено на VPS и у меня доступ имеется с разных устройств. удобно.


    1. Andrey_Perelygin
      12.11.2015 16:31

      Ну если брать трафик ВК и перегонять его в XMPP, то я лично в качестве клиента предпочту Finch. Имхо он удобнее


  1. Deffe
    12.11.2015 18:58
    +2

    Есть же готовая либа для питона тыц


  1. istui
    12.11.2015 19:22
    +4

    Идея неплохая, но на Хабре сообществом предполагается определенный уровень статей. Вы бы доработали решение, сделали вывод графики (как вариант-в отдельное окно + псевдографика для превью), табы для разных диалогов (псевдооконный интерфейс по типу и в стилистике mc, проще было бы маскировать), плеер в фоне — и после этого опубликовали коротенькую заметку со ссылкой и интересными кодовыми решениями. Уверен, ее бы ждал очень теплый прием.

    Надеюсь, у вас все получится!


    1. Andrey_Perelygin
      13.11.2015 14:06

      Собственно это мой дебют на хабре, так что да, учиться есть куда.
      Принял Ваши идеи — определенно нужно реализовать.
      Спасибо.


  1. robux
    13.11.2015 10:07

    Благодарю за статью. Наконец-то я увидел практикующего программиста, а не пафосного аналитика-пустомелю!
    Ну а на аналитиков спокойней реагируйте — ведь на 1 программиста приходится 999 аналитиков.

    По моему убеждению, такие статьи и представляют наибольшую ценность.


    1. Andrey_Perelygin
      13.11.2015 16:55

      Благодарю.