Using VK Streaming API with Telegram Notification

Vkontakte launched the Streaming API, a tool for obtaining public data from VKontakte for the given keywords.
VK itself sends new suitable content as it appears. Thus, you can get interesting records without joining dozens of groups, immediately after publication.
Let's write a bot for a telegram with notification of entries in the VK.
Receive news
First you need to create an application in VK and take the service key from the settings

. The WebSocket protocol is used to transfer data. We use the "websocket" library.
import websocket
Before connecting, use the streaming.getServerUrl method. As a result, the method returns the URL for further requests in the endpoint (string) field and the access key in the key (string) field.
Get url and key
def get_streaming_server_key(token):
request_url = "https://api.vk.com/method/streaming.getServerUrl?access_token={}&v=5.64".format(token)
r = requests.get(request_url)
data = r.json()
return {"server":data["response"]["endpoint"],"key":data["response"]["key"]}
Listening to the server
def listen_stream():
websocket.enableTrace(True)
ws = websocket.WebSocketApp("wss://{}/stream?key={} ".format(stream["server"], stream["key"]),
on_message=on_message,
on_error=on_error,
on_close=on_close)
ws.on_open = on_open
ws.run_forever()
def on_message(ws, message):
print(">>>> receive message:", message)
def on_error(ws, error):
print(">>>> error thead:",error)
def on_close(ws):
print(">>>> close thead")
def on_open(ws):
print(">>>> open thead")
stream = get_streaming_server_key(my_servise_token)
listen_stream()
After starting, the following should appear in the console
- request header - GET / stream? Key = e6290ba04916a314c398c331f60224d012fabeb1 HTTP / 1.1
Upgrade: websocket
Connection: Upgrade
Host: streaming.vk.com
Origin: streaming.vk.com
Sec-WebSocket-Key: vG40A5bwbPaVBS + DLBOyog =
Sec : 13
- - response header - HTTP / 1.1 101 Switching Protocols
Server: Apache
Date: Thu, 20 Jul 2017 22:06:55 GMT
Connection: upgrade
Upgrade: websocket
Sec-WebSocket-Accept: QRJNqD8K7vWNMcQesYKo64q8MfA =
- >>>> open thead
send: b "\ x8a \ x80d ') \ x90"
send: b' \ x8a \ x80 \ xfcmp \ xe6 '
send: b' \ x8a \ x80s \ x9f6 {'
send: b' \ x8a \ x80 \ xc9 \ xfa . \ xd4 '
send: b'\ x8a \ x80fU <\ xed '
send: b '\ x8a \ x80 \ xc6Ji \ x19'
send: b '\ x8a \ x80 \ xd2D \ x08!'
Work with rules
Addendum
HTTP POST Method
Content Type application / json
Request URL https: // {endpoint} / rules? Key = {key}
def set_my_rules(value):
rule_params = {"rule":{"value":value,"tag":'tag_'+str(random.randint(11111, 99999))}}
headers = {'content-type': 'application/json'}
r = requests.post("https://{}/rules?key={}".format(stream["server"], stream["key"]), data=json.dumps(rule_params), headers=headers)
data = r.json()
return data['code'] == 200
Getting
HTTP GET method
Request URL https: // {endpoint} / rules? Key = {key}
def get_my_rules():
r = requests.get("https://{}/rules?key={}".format(stream["server"], stream["key"]))
data = r.json()
if data['code'] != 200:
return False
return data['rules']
Removal
HTTP Method DELETE
Content Type application / json
Request URL https: // {endpoint} / rules? Key = {key}
def del_my_rules(tag):
headers = {'content-type': 'application/json'}
rule_params = {"tag":tag}
r = requests.delete("https://{}/rules?key={}".format(stream["server"], stream["key"]), data=json.dumps(rule_params), headers=headers)
data = r.json()
return data['code'] == 200
Trying to get the news.
stream = get_streaming_server_key(my_servise_token)
set_my_rules('кот')
listen_stream()
The following should appear in the console
send: b '\ x8a \ x80 \ xc9 \ xfa. \ xd4'
send: b '\ x8a \ x80fU <\ xed'
send: b '\ x8a \ x80 \ xc6Ji \ x19'
send: b '\ x8a \ x80 \ xd2D \ x08! '
{"Code": 100, "event": {"event_type": "post", "event_id": {"post_owner_id": - 35708825, "post_id": 4560}, "event_url": " vk.com/wall- 35708825_4560 "," text ":" vk.com/small.dolly
The cat disappeared. In the city of Elektrostal on Zagonova street in the area of 16 schools. Young boy, 2 years castrated. The usual gray color with stripes. There is a white spot on the chin and chest. Large cat about 7 kg. Lost on June 27. If someone saw him, please inform 89250506596 or 89251527466. We love him very much and want him to return home "," creation_time ": 1498942995," tags ": [" test_cats "]," author ": {" id ": - 35708825}}} - our news
Telegram
We use the telebot library.
import telebot
TELEGRAM_API_TOKEN = '3277332...' # токен выдаваемый при создании бота
bot = telebot.TeleBot(TELEGRAM_API_TOKEN)
Bot start
def _send(msg):
markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True)
markup.add('Мои интересы', 'Очистить список интересов', 'Добавить')
msg = bot.send_message(chatID, msg, reply_markup=markup) # шлем текст с вариантами ответа
bot.register_next_step_handler(msg, process_step) # устанавливаем обработчик для наших ответов
# обработчик для 'help', 'start'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
global chatID
chatID = message.chat.id
hello_test = 'Привет, %s! Я бот использующий VK Streaming API!' % message.from_user.first_name
_send(hello_test)
# обработчик для наших ответов
def process_step(message):
if message.text == 'Мои интересы':
_send(get_rules_list())
if message.text == 'Очистить список интересов':
_send(clear_rules_list())
if message.text == 'Добавить':
msg = bot.send_message(chatID, "Что добавить?")
bot.register_next_step_handler(msg, add_rule_handler)
Add
if message.text == 'Добавить':
msg = bot.send_message(chatID, "Что добавить?")
bot.register_next_step_handler(msg, add_rule_handler)
.....
def add_rule_handler(message):
new_rule = set_my_rules(message.text)
if new_rule:
_send("Successful")
else:
logging.debug("Error add rules")
_send("Error")
My interests
def get_rules_list():
rules = get_my_rules()
if rules:
return "\n".join([str(rule['value']) for rule in rules])
else:
logging.debug("Error get rules list")
return 'Error'
Clear list of interests
def clear_rules_list():
rules = get_my_rules()
if rules:
for rule in rules:
del_my_rules(rule['tag'])
return "Successful"
else:
logging.debug("Error clear rules list")
return 'Error'
News Submission
def on_message(ws, message):
print(">>>> receive message:", message)
message = json.loads(message)
if not message['code']:
return
if not message['event']['event_type'] or message['event']['event_type'] != 'post':
return # выходим, если запись не отдельный пост
post = message['event']['event_type'] +"\n"+message['event']['text'].replace("
", "\n") +"\n\n"+ message['event']['event_url']
_send_post(post)
We start everything together
For correct operation, sockets must be run in a separate thread.
def listen_stream():
websocket.enableTrace(True)
ws = websocket.WebSocketApp("wss://{}/stream?key={} ".format(stream["server"], stream["key"]),
on_message=on_message,
on_error=on_error,
on_close=on_close)
ws.on_open = on_open
#ws.run_forever()
wst = threading.Thread(target=ws.run_forever)
wst.daemon = True
wst.start()
We launch
if __name__ == '__main__':
try:
chatID = 0
stream = get_streaming_server_key(my_servise_token)
listen_stream()
bot.polling(none_stop=True)
except Exception as e:
logging.exception("error start")
That's all, thanks.
→ Full script code
→ Streaming API docs
→ Telegram API docs
→ Python websocket-client
→ Python TelegramBotAPI