Telegram бот на Python, работа с геолокацией пользователя

Статьи

Telegram бот на Python, работа с геолокацией пользователя

Автор: Рамис, 25 октября 2021

Часть 1. Простой Telegram бот на Python, метод getUpdates

Часть 2. Telegram бот на Python, отправка файлов, встроенная клавиатура

Часть 3. Telegram бот на Python, работа с геолокацией пользователяа

Вот и третья часть, где мы продолжим создавать телеграм бота с помощью Python и библиотеки requests. Сегодня вы узнаете как работать с геолокацией пользователя, и как с помощью бесплатного "API геокодера" определить адрес по координатам.

Функционал бота будем выглядеть следующим образом: Пользователь нажимает кнопку в боте и отправляет свою геолокацию. А в ответ к нему бот пишет, в каком городе он находится.

Это часть добавлена по просьбе одно из читателей сайта ramziv.com :)

просьбе одно из читателей сайта ramziv.com

Код телеграм бота

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

Прошу вас обратить внимание на функцию run, я добавил новое условие, так как бот прекращал работу ошибкой, если вместо текста отправить ему файл, картинку или геолокацию. Данный код будет работать на Python 3.8 и выше.

#https://ramziv.com/blog/29
import requests
import time
import json

TOKEN = 'ТОКЕН'
URL = 'https://api.telegram.org/bot'

def get_updates(offset=0):
    result = requests.get(f'{URL}{TOKEN}/getUpdates?offset={offset}').json()
    return result['result']

def send_message(chat_id, text):
    requests.get(f'{URL}{TOKEN}/sendMessage?chat_id={chat_id}&text={text}')

def reply_keyboard(chat_id, text):
    reply_markup ={ "keyboard": [["Привет", "Hello"]], "resize_keyboard": True, "one_time_keyboard": True}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

def check_message(chat_id, message):
    if message.lower() in ['привет', 'hello']:
        send_message(chat_id, 'Привет :)')
    else:
        reply_keyboard(chat_id, 'Я не понимаю тебя :(')

def run():
    update_id = get_updates()[-1]['update_id'] # Сохраняем ID последнего отправленного сообщения боту
    while True:
        time.sleep(2)
        messages = get_updates(update_id) # Получаем обновления
        for message in messages:
            # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение
            if update_id < message['update_id']:
                update_id = message['update_id']# Сохраняем ID последнего отправленного сообщения боту
                if (user_message := message['message'].get('text')): # Проверим, есть ли текст в сообщении
                    check_message(message['message']['chat']['id'], user_message) # Отвечаем

if __name__ == '__main__':
    run()

Геолокация пользователя

Что бы получить геолокацию пользователя, добавим в нашу клавиатуру новую кнопку с текстом "Где я нахожусь" и укажем ключ request_location со значением True.

#https://ramziv.com/blog/29
def reply_keyboard(chat_id, text):
    reply_markup ={ "keyboard": [["Привет", "Hello"], [{"request_location":True, "text":"Где я нахожусь"}]], "resize_keyboard": True, "one_time_keyboard": True}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

Так же добавим новое условие в функцию run, что бы проверить, что вместо текста в сообщение была отправлена геолокация. Если условие истина, выведем на экран сообщение с координатами пользователя.

#https://ramziv.com/blog/29
def run():
    update_id = get_updates()[-1]['update_id'] # Сохраняем ID последнего отправленного сообщения боту
    while True:
        time.sleep(2)
        messages = get_updates(update_id) # Получаем обновления
        for message in messages:
            # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение
            if update_id < message['update_id']:
                update_id = message['update_id']# Сохраняем ID последнего отправленного сообщения боту
                if (user_message := message['message'].get('text')): # Проверим, есть ли текст в сообщении
                    check_message(message['message']['chat']['id'], user_message) # Отвечаем
                if (user_location := message['message'].get('location')): # Проверим, если ли location в сообщении 
                    print(user_location)

Запустим, и проверим нашего бота.

Если нажать кнопку "Где я нахожусь", всплывает push сообщения, где телеграм спрашивает разрешение на отправку геолокации боту.

Телеграм бот на Python

Нажимаем "Ок", и видим что в консоли появилось сообщение с координатами пользователя.

{'latitude': 54.602916, 'longitude': 53.699995}

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

API геокодер

просьбе одно из читателей сайта ramziv.com

LocationIQ API: позволяет определять координаты и получать сведения об объекте по его адресу (прямое геокодирование) и наоборот, определять адрес объекта по его координатам (обратное геокодирование). Сервис предлагает бесплатный план, где разрешено делать 5000 запросов в день, с 2 запросами в секунду.

Зарегистрируемся, и получим токен.

Проверим как работает API, откроем в новой вкладке ссылку заменив токен и ранее полученные координаты пользователя.

https://eu1.locationiq.com/v1/reverse.php?key=<TOKEN>&lat=<LATITUDE>&lon=<LONGITUDE>&format=json

В ответ мы получим JSON, где указанно все о переданных координатах.

LocationIQ JSON

Теперь осталось повторить все на Python. Создадим функцию geocoder которая будет принимать координаты, и возвращать текст 'Твое местоположение: + адрес из API геокодера'.

#https://ramziv.com/blog/29
def geocoder(latitude, longitude):
    token = 'pk.токен'
    headers = {"Accept-Language": "ru"}
    address = requests.get(f'https://eu1.locationiq.com/v1/reverse.php?key={token}&lat={latitude}&lon={longitude}&format=json', headers=headers).json()
    return f'Твое местоположение: {address.get("display_name")}'

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

Полный код.

#https://ramziv.com/blog/29
import requests
import time
import json

TOKEN = 'ТОКЕН'
URL = 'https://api.telegram.org/bot'

def get_updates(offset=0):
    result = requests.get(f'{URL}{TOKEN}/getUpdates?offset={offset}').json()
    return result['result']

def send_message(chat_id, text):
    requests.get(f'{URL}{TOKEN}/sendMessage?chat_id={chat_id}&text={text}')

def reply_keyboard(chat_id, text):
    reply_markup ={ "keyboard": [["Привет", "Hello"], [{"request_location":True, "text":"Где я нахожусь"}]], "resize_keyboard": True, "one_time_keyboard": True}
    data = {'chat_id': chat_id, 'text': text, 'reply_markup': json.dumps(reply_markup)}
    requests.post(f'{URL}{TOKEN}/sendMessage', data=data)

def check_message(chat_id, message):
    if message.lower() in ['привет', 'hello']:
        send_message(chat_id, 'Привет :)')
    else:
        reply_keyboard(chat_id, 'Я не понимаю тебя :(')

def geocoder(latitude, longitude):
    token = 'pk.токен'
    headers = {"Accept-Language": "ru"}
    address = requests.get(f'https://eu1.locationiq.com/v1/reverse.php?key={token}&lat={latitude}&lon={longitude}&format=json', headers=headers).json()
    return f'Твое местоположение: {address.get("display_name")}'

def run():
    update_id = get_updates()[-1]['update_id'] # Присваиваем ID последнего отправленного сообщения боту
    while True:
        time.sleep(2)
        messages = get_updates(update_id) # Получаем обновления
        for message in messages:
            # Если в обновлении есть ID больше чем ID последнего сообщения, значит пришло новое сообщение
            if update_id < message['update_id']:
                update_id = message['update_id']# Присваиваем ID последнего отправленного сообщения боту
                if (user_message := message['message'].get('text')): # Проверим, есть ли текст в сообщении
                    check_message(message['message']['chat']['id'], user_message) # Отвечаем
                if (user_location := message['message'].get('location')): # Проверим, если ли location в сообщении
                    latitude = user_location['latitude']
                    longitude = user_location['longitude']
                    send_message(message['message']['chat']['id'], geocoder(latitude, longitude))

if __name__ == '__main__':
    run()

Проверим как работает.

Телеграм бот Python

Ответ с местоположением выглядит смешно :), но это сделано для демонстрации. Вы можете в функции geocoder заменить address.get("display_name") на address["address"].get("town") и в ответ получать только название города.

Конец

Теперь вы знаете как работать с геолокацией пользователя. Надеюсь полученный знания помогут вам реализовать, что ни будь интересное в вашем проекте. Если у вас есть пожелания для следующей части, прошу отпишите мне в обратной связи.

Комментарии

Markdown
Войти

Меню

Объявление

Нашли на сайте баг OR ошибку OR фичу? Прошу Вас сообщить мне через обратную связь, или комментарий.

Есть идеи для сайта? Свяжитесь со мной через форму обратной связи. Наш разработчик всегда рад готов добавить что то новое.