Граємося з VK API та Python, частина 3: а ви любите єнотів?
Добридень, пані та панове, з вами знову OlegWock. За вікном чудовий вечір п'ятниці. Чому б не провести його з користю? Пропоную сьогодні написати невеличкого бота-автовідповідача.
Зміст
Одразу хочу сказати, що цей бот буде з себе представляти і які навички вам знадобляться. Бот буде виконувати деякі дії в відповідь на отримане повідомлення. Наприклад, в цьому уроці, ми навчимо його відправляти, у відповідь на команду ~bash~, випадкову цитату з bash.im, а по команді ~cgra~ випадкову статтю з Codeguida. Для написання цього бота, окрім знань пітону та роботи з VK API, потрібні хоча б початкові знання з парсингу. Для парсингу я використовую requests + lxml, ви ж можете використовувати свої улюблені бібліотеки. Також, повинен сказати, що в мене є нездорова пристрасть до XPath'у, тому я інтенсивно використовую його можливості. Ну а зараз час починати.
Перед усім, потрібно написати відловлювання потрібних повідомлень. Отримувати повідомлення ми будемо за допомогою messages.get, використовуючи last_message_id, завдяки чому ми не пропустимо ні одного повідомлення.
import vk
from time import sleep
from lxml import html
import requests as req
login = ''
password = ''
# Авторизація
vkapi = vk.EnterCaptchaAPI('4766382', login, password)
print('Успішно авторизувався')
messages = vkapi.messages.get(count=1)
last = messages['items'][0]['id']
while True:
try:
messages = vkapi.messages.get(last_message_id=last)
except Exception as e:
print(e)
sleep(4)
continue
if not messages['items']: # Якщо нема нових повідомлень
sleep(4)
continue
last = messages['items'][0]['id']
for message in messages['items']:
# Тимчасові заглушки
if "~bash~" in message['body']:
print("Wow. Such bash")
if "~cgra~" in message['body']:
print("Very nice")
sleep(4)
Тепер потрібно написати функції для отримання цитати з башу та статті з Codeguida. Давайте почнемо з башу. Як я вже казав, я великий прихильник XPath, тому не дивуйтеся, якщо його, на вашу думку, тут забагато.
def bash(id):
try:
r = req.get('http://bash.im/random')
doc = html.document_fromstring(r.text)
bash = '\n'.join(doc.xpath('//*[@id="body"]/div[3]/div[@class="text"]/text()'))
vkapi.messages.send(user_id=id, message=bash)
except Exception as e:
print(e)
Тут магія зберігається в 4 стрічці. За допомогою XPath ми дістаємо текст з контейнера div, що містить в собі першу цитату на сторінці. Знайти XPath потрібного елемента можна в інструментах розробника вашого браузера, але потрібно примітити, що майже завжди потрібно "доробляти напилком" до потрібного вам dbukzle. doc.xpath завжди повертає список, в даному випадку? це буде список із абзаців (шматків тексту, розділених <br />), тому його потрібно зібрати, замінивши зникнувші <br /> на \n, ну й надіслати отриманий текст у відповідь. Поправимо цикл перевірки повідомлень, замінивши заглушку на вже готову функцію:
...
if "~bash~" in message['body']:
bash(message['user_id'])
...
Можете запустити й упевнитися, що все працює. Але є одне не. Якщо хтось в колективному чаті напише ~bash~, то цитата відправиться до нього в особисті повідомлення, а не в чат. Треба пофіксити.
def bash(id, mode='u'):
try:
r = req.get('http://bash.im/random')
doc = html.document_fromstring(r.text)
bash = '\n'.join(doc.xpath('//*[@id="body"]/div[3]/div[@class="text"]/text()'))
if mode == 'c':
vkapi.messages.send(chat_id=id, message=bash)
else:
vkapi.messages.send(user_id=id, message=bash)
except Exception as e:
print(e)
....
if "~bash~" in message['body']:
if 'chat_id' in message:
bash(message['chat_id'], 'c')
else:
bash(message['user_id'])
....
А тепер час писати парсер для кодегіди. Давайте візьмемо url останнього посту (http://codeguida.com/post/287/), як ви бачите в кінці є ідентифікатор посту. Тобто, щоб отримати випадковий пост потрібно замість ідентифікатора підставити випадкове число від 1 до 287 (на даний момент).
def cgra(id, mode='u'):
try:
r = req.get('http://codeguida.com/')
doc = html.document_fromstring(r.text)
last_article = doc.xpath('/html/body/div[3]/section/div[1]/div[1]/article[1]/div/a/@href')[0] # адреса останнього посту
last_id = int(last_article.split('/')[-2]) # ID останнього посту
random_id = randint(1, last_id)
r = req.get('http://codeguida.com/post/{}/'.format(random_id))
doc = html.document_fromstring(r.text)
title = doc.xpath('/html/body/div[3]/div[2]/section/h1/text()')[0] # отримуємо заголовок
message = '{0}\n\nhttp://codeguida.com/post/{1}/'.format(title, random_id)
if mode == 'c':
vkapi.messages.send(chat_id=id, message=message)
else:
vkapi.messages.send(user_id=id, message=message)
except Exception as e:
print(e)
Не забудьте прибрати заглушку в циклі перевірки повідомлень. На цьому роботу можна вважати завершеною, все повинно працювати. Але давайте ще додамо допомогу до нашої програми.
def print_help(id, mode='u'):
try:
message = """=== Система \"Єнотик\" ===
Дотсупні команди:
_9989; ~bash~ -- випадкова цитата з bash.im
_9989; ~cgra~ -- випадкова стаття з Codeguida
_9989; ~help~ -- показує цю довідку
Автор: OlegWock, 2015, спеціально для Codeguida"""
if mode == 'c':
vkapi.messages.send(chat_id=id, message=message)
else:
vkapi.messages.send(user_id=id, message=message)
except Exception as e:
print(e)
...
if "~help~" in message['body']:
if 'chat_id' in message:
print_help(message['chat_id'], 'c')
else:
print_help(message['user_id'])
...
Як і зазвичай ви можете знайти повний код в цьому репозитарії. В коментарях можете висловлювати свої думки про додавання боту функціональності. Хто знає, можливо, саме ваша ідея мені сподобається і буде описана в наступних статтях.
1558 9


Коментарі:
-6
Lev Lukomsky
вести розробницький блог українською - патріотично, а бавитись з окупантською мережею — ні. незарах
2
andreykko
-2
Роман Федунишин
Lev Lukomsky, підтримую
1
OlegWock
Ви колись грали в тетріс?
1
siriniok
Добре, що тут кожного "патріота" можна мінуснути.
0
Lev Lukomsky
siriniok, мінуснути можна, але без розумних аргументів, бо їх немає.
OlegWock, тетріс грав, ну і можу зараз пограти - це грошей російському б’юджету не принесе. На відміну від вк, вк - немаленька контора, яка має нехілі обороти, і платить податки в кацапську казну, а та ті гроші тратить на зброю, яка бомбить наших хлопців в окопах.
Може ти вважаєш це все несерйозно, ну вважай, але тоді ми ніколи не виліземо з цього болота.
0
OlegWock
0
OlegWock
Lev Lukomsky,
"тетріс грав" -- фу сепаратист. А якщо по справі, то жду ваших альтернатив одній з найбільших та найзручніших платформ
1
cody_page
Потрібно знати межу між нормальним патріотизмом, та фанатизмом!
0
denysdovhan
cody_page, ту вже не фанатизмом, а шовінізмом попахує.
0
Костя Третяк
Триндець! Україномовні українці замінусували свого, який "сказав щось проти кацапні", ще й додумались "шовіністом" обізвати. Ви взагалі не забули мізки свої включити?!
Припустимо навіть, що це перегиб зі сторони коментатора, але вам не здається що привід є так глибоко ненавидіти кацапню, хіба ні? Думаю можна було просто нереагувати на такі коментарі, якщо вам аж така прискіпливість не подобається. Але щоб вже починали заступатись за тих, хто... короче якщо до вас не дійшло до цих пір, то сумніваюсь, що вам дійде після мого коментаря...
0
OlegWock
Костя Третяк, якщо сумніваєтесь, что навіщо писали?
0
Костя Третяк
OlegWock, ви хоч самі зрозуміли що написали?
0
OlegWock
Костя Третяк, це у вас слід спитати. Тим паче, думаю, тема вже закрита.
0
kostyandrew