Граємося з VK API та Python, частина 3: а ви любите єнотів?

8 хв. читання

Добридень, пані та панове, з вами знову 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('https://web.archive.org/web/20230327094403/http://bash.im/random')
        doc = html.document_fromstring(r.text)
        bash = '\
'.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> на \ , ну й надіслати отриманий текст у відповідь. Поправимо цикл перевірки повідомлень, замінивши заглушку на вже готову функцію:

        ...
        if "~bash~" in message['body']:
            bash(message['user_id'])
        ...

Можете запустити й упевнитися, що все працює. Але є одне не. Якщо хтось в колективному чаті напише ~bash~, то цитата відправиться до нього в особисті повідомлення, а не в чат. Треба пофіксити.

def bash(id, mode='u'):
    try:
        r = req.get('https://web.archive.org/web/20230327094403/http://bash.im/random')
        doc = html.document_fromstring(r.text)
        bash = '\
'.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 цього посту, як ви бачите в кінці є ідентифікатор посту. Тобто, щоб отримати випадковий пост потрібно замість ідентифікатора підставити випадкове число від 1 до 287 (на даний момент).

def cgra(id, mode='u'):
    try:
        r = req.get('https://web.archive.org/web/20230327094403/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('https://web.archive.org/web/20230327094403/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}\
\
http://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'])
        ...

Як і зазвичай ви можете знайти повний код в цьому репозитарії. В коментарях можете висловлювати свої думки про додавання боту функціональності. Хто знає, можливо, саме ваша ідея мені сподобається і буде описана в наступних статтях.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 4.7K
Приєднався: 10 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація