Создание основы для работы бота будет состоять из следующих этапов:


  1. Создание бота в ВК
  2. Генерирование API- ключа
  3. Создание программы бота через LongPoolVK

Для кого эта статья?


Статья рассчитана для начинающих программистов. Метод работы программы очень прост и любой, кто умеет разбираться в синтаксисе Питона и немного знающий ООП сможет его реализовать для своих нужд. Но в принципе даже не зная никаких принципов ООП, думаю можно научиться добавлять простые функции или хотя бы в крайнем случае использовать готовые исходники из GitHub.

Что есть в этой статье?


Создание основы бота. После этого его можно будет запрограммировать как-угодно. Автоматизировать какую-то рутину или использовать как собеседник.

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

Добавление функции передачи погоды. Научим бота говорить нам погоду.

Создание бота в ВК


Начнем мы с создания бота, а именно группу в ВК.

Для это нужно зайти в «группы» > «создать сообщество».

Выберите любой тип сообщества и введите название, тематику группы.

На открывшейся странице настроек, выберите «Работа с API»

Далее, необходимо создать API-ключ.

Затем выберите нужные вам параметры с доступом для вашего API-ключа.

Скорее всего, вам придётся подтверждать действие в ВК с помощью мобильного телефона. Затем скопируйте полученный API-ключ где-нибудь в файл. Он нам еще понадобится.

Затем нужно разрешить сообщения. Для этого переходим в «сообщения» и включаем их.

Приступим к программной части бота


Мы не будем реализовывать его через запросы к ВК, а если быть точнее, просто используем библиотеку VkLongPool, которая сделает это за нас.

Для этого необходима библиотека vk_api. Установим его через pip:

python -m pip install vk_api

Но лично я работаю с виртуальным окружением Anaconda. С этим зачастую возникают проблемы при первой работе. Обычно проблема в том, что система не распознают команду «python». А решается эта проблема путем добавления его в PATH.

Приступим к самому коду:

Импортируем нужные модули:

import vk_api
from vk_api.longpoll import VkLongPoll, VkEventType

Затем код:

def write_msg(user_id, message):
    vk.method('messages.send', {'user_id': user_id, 'message': message})

# API-ключ созданный ранее
token = "6a9c267cd469388709a9e9acaddbe0aa81a0abbf12239b3e597a31729ffbddb9c88e80a443554c918b8f7"

# Авторизуемся как сообщество
vk = vk_api.VkApi(token=token)

# Работа с сообщениями
longpoll = VkLongPoll(vk)

# Основной цикл
for event in longpoll.listen():

    # Если пришло новое сообщение
    if event.type == VkEventType.MESSAGE_NEW:
    
        # Если оно имеет метку для меня( то есть бота)
        if event.to_me:
        
            # Сообщение от пользователя
            request = event.text
            
            # Каменная логика ответа
            if request == "привет":
                write_msg(event.user_id, "Хай")
            elif request == "пока":
                write_msg(event.user_id, "Пока((")
            else:
                write_msg(event.user_id, "Не поняла вашего ответа...")

Функция write_msg получает id пользователя ВК <user_id>, которому оно отправит сообщение и собственно само сообщение .

def write_msg(user_id, message):
    vk.method('messages.send', {'user_id': user_id, 'message': message})

Авторизовавшись как сообщество и настроив longpool:

# API-ключ созданный ранее
token = "6a9c267cd469388709a9e9acaddbe0aa81a0abbf12239b3e597a31729ffbddb9c88e80a443554c918b8f7"

# Авторизуемся как сообщество
vk = vk_api.VkApi(token=token)

# Работа с сообщениями
longpoll = VkLongPoll(vk)
Войдем в основной цикл:

# Основной цикл
for event in longpoll.listen():

В нем мы циклически будем проверять на наличие event-ов. А получить тип event-а сможем с помощью event.type.

После этого получив сообщение от пользователя сможем отправить ему соответствующее письмо с помощью уже созданной функции write_msg.

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

Листинг кода в GH

Теперь приступим к более реальному программированию


Создадим класс VkBot в файле vk_bot.py, который будет служить нам ботом.

class VkBot:

    def __init__(self, user_id):
    
        print("Создан объект бота!")
        self._USER_ID = user_id
        self._USERNAME = self._get_user_name_from_vk_id(user_id)
        
        self._COMMANDS = ["ПРИВЕТ", "ПОГОДА", "ВРЕМЯ", "ПОКА"]

И добавим туда метод с помощью которого можно получить имя пользователя через vk id.

def _get_user_name_from_vk_id(self, user_id):
    request = requests.get("https://vk.com/id"+str(user_id))
    bs = bs4.BeautifulSoup(request.text, "html.parser")
    
    user_name = self._clean_all_tag_from_str(bs.findAll("title")[0])
    
    return user_name.split()[0]

Это делается с помощью beatifulsoup4.

Устанавливаем если его нет:
python -m pip install bs4
На него есть достаточное количество статей, которые стоит изучить. С помощью него же создадим еще несколько методов:

# Получение времени:
def _get_time(self):
    request = requests.get("https://my-calend.ru/date-and-time-today")
    b = bs4.BeautifulSoup(request.text, "html.parser")
    return self._clean_all_tag_from_str(str(b.select(".page")[0].findAll("h2")[1])).split()[1]

# Получение погоды
def _get_weather(city: str = "санкт-петербург") -> list:
    request = requests.get("https://sinoptik.com.ru/погода-" + city)
    b = bs4.BeautifulSoup(request.text, "html.parser")
    
    p3 = b.select('.temperature .p3')
    weather1 = p3[0].getText()
    p4 = b.select('.temperature .p4')
    weather2 = p4[0].getText()
    p5 = b.select('.temperature .p5')
    weather3 = p5[0].getText()
    p6 = b.select('.temperature .p6')
    weather4 = p6[0].getText()
    result = ''
    result = result + ('Утром :' + weather1 + ' ' + weather2) + '\n'
    result = result + ('Днём :' + weather3 + ' ' + weather4) + '\n'
    temp = b.select('.rSide .description')
    weather = temp[0].getText()
    result = result + weather.strip()
    
    return result
    
 # Метод для очистки от ненужных тэгов
 
@staticmethod
def _clean_all_tag_from_str(string_line):
    """
    Очистка строки stringLine от тэгов и их содержимых
    :param string_line: Очищаемая строка
    :return: очищенная строка
    """
    result = ""
    not_skip = True
    for i in list(string_line):
        if not_skip:
            if i == "<":
                not_skip = False
            else:
                result += i
        else:
            if i == ">":
                not_skip = True
    
    return result

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

С помощью этих методов мы сможем получить время и погоду. Эти методы вырезаны из моего основного проекта бота. Следует организовать их в отдельных пакетах и классах, применяя наследование. Но ради примера работы, я решил вместить все это в один класс бота, что конечно плохо.

Создадим основной метод new_message, который будет обрабатывать сообщение пользователя и возвращать ответ:

def new_message(self, message):

    # Привет
    if message.upper() == self._COMMANDS[0]:
        return f"Привет-привет, {self._USERNAME}!"
    
    # Погода
    elif message.upper() == self._COMMANDS[1]:
        return self._get_weather()
    
    # Время
    elif message.upper() == self._COMMANDS[2]:
        return self._get_time()
    
    # Пока
    elif message.upper() == self._COMMANDS[3]:
        return f"Пока-пока, {self._USERNAME}!"
    
    else:
        return "Не понимаю о чем вы..."

Теперь вернемся к запускаемому файлу:

Импортируем класс нашего бота:

from vk_bot import VkBot

Изменим основной наш цикл:

print("Server started")
for event in longpoll.listen():
    if event.type == VkEventType.MESSAGE_NEW:
        if event.to_me:
        
            print('New message:')
            print(f'For me by: {event.user_id}', end='')
            
            bot = VkBot(event.user_id)
            write_msg(event.user_id, bot.new_message(event.text))
            
            print('Text: ', event.text)

То есть теперь мы будем передавать полученное сообщение объекту бота, который вернет нам нужный ответ.

Это усложнение программы просто необходимо, если вы хотите дальше улучшить функционал бота:

Создайте отдельные пакеты и классы для каждой функции _get_time и _get_weather. Организуйте наследование с общего класса. И каждую новую функцию определяйте в отдельных классах, лучше всего, конечно, еще и разделить на пакеты.

Добавьте словарь с ключом идентификатора пользователя и значением объекта бота. Таким образом, не придется каждый раз в цикле создавать объект бота. К тому же, это обеспечит пользование несколькими пользователями сразу в сложных конструкциях.

Таким образом, выбрав хорошую архитектуру кода, вы сможете создать многофункционального бота.

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

Вы же можете редактировать бота под себя.

Бот из статьи

Основной проект бота (улучшенный) на GH

Буду рад вашим идеям. По любым вопросам пишите.

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


  1. python273
    26.10.2018 02:31

    from vk_api.longpoll import VkLongPoll, VkEventType

    Для ботов сейчас есть отдельный лонгпул:
    https://vk.com/dev.php?method=bots_longpoll
    https://github.com/python273/vk_api/blob/master/examples/bot_longpoll.py


    _get_user_name_from_vk_id

    Имя пользователя лучше получать через API


    _get_time

    Наверное будет проще использовать datetime