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

22 травня 2015 20:59 OlegWock 1558 15

Добридень, пані та панове, з вами знову 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

Схожі матеріали:

Коментарі:

Lev Lukomsky

24 Тра 2015 00:59

вести розробницький блог українською - патріотично, а бавитись з окупантською мережею — ні. незарах

andreykko

24 Тра 2015 18:57

Роман Федунишин

24 Тра 2015 22:20

Lev Lukomsky, підтримую

OlegWock

25 Тра 2015 16:22

Ви колись грали в тетріс?

siriniok

26 Тра 2015 04:39

Добре, що тут кожного "патріота" можна мінуснути.

Lev Lukomsky

27 Тра 2015 13:05

siriniok, мінуснути можна, але без розумних аргументів, бо їх немає.

OlegWock, тетріс грав, ну і можу зараз пограти - це грошей російському б’юджету не принесе. На відміну від вк, вк - немаленька контора, яка має нехілі обороти, і платить податки в кацапську казну, а та ті гроші тратить на зброю, яка бомбить наших хлопців в окопах.
Може ти вважаєш це все несерйозно, ну вважай, але тоді ми ніколи не виліземо з цього болота.

OlegWock

28 Тра 2015 14:10
Цей коментар прихований автором

OlegWock

28 Тра 2015 14:11

Lev Lukomsky,
"тетріс грав" -- фу сепаратист. А якщо по справі, то жду ваших альтернатив одній з найбільших та найзручніших платформ

cody_page

10 Чер 2015 19:55

Потрібно знати межу між нормальним патріотизмом, та фанатизмом!

denysdovhan

13 Чер 2015 01:03

cody_page, ту вже не фанатизмом, а шовінізмом попахує.

Костя Третяк

13 Чер 2015 05:03

Триндець! Україномовні українці замінусували свого, який "сказав щось проти кацапні", ще й додумались "шовіністом" обізвати. Ви взагалі не забули мізки свої включити?!

Припустимо навіть, що це перегиб зі сторони коментатора, але вам не здається що привід є так глибоко ненавидіти кацапню, хіба ні? Думаю можна було просто нереагувати на такі коментарі, якщо вам аж така прискіпливість не подобається. Але щоб вже починали заступатись за тих, хто... короче якщо до вас не дійшло до цих пір, то сумніваюсь, що вам дійде після мого коментаря...

OlegWock

13 Чер 2015 23:02

Костя Третяк, якщо сумніваєтесь, что навіщо писали?

Костя Третяк

13 Чер 2015 23:34

OlegWock, ви хоч самі зрозуміли що написали?

OlegWock

13 Чер 2015 23:59

Костя Третяк, це у вас слід спитати. Тим паче, думаю, тема вже закрита.

kostyandrew

25 Вер 2015 16:55
Цей коментар прихований автором
Авторизуйтесь, щоб залишити коментар.