• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Статья Получение фото/видео дня NASA, публикация в канал Телеграмм с помощью Python

Космос всегда интересовал человечество. И когда люди изобрели мощные телескопы, а потом еще и вывели их на орбиту, стало появляться множество снимков самых различных явлений. Будь то марсоход или метеор сгорающий в атмосфере. У NASA есть свой сайт, на котором агентство публикует фото дня. Не всегда это фото и не всегда космоса. Однако, для всех желающих есть специальный API, с помощью которого можно получить это фото. Давайте используем для получения фото Python.

b716ab41a7fe451ad77adf1fa39f5da8.jpg



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

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


Что потребуется?

Для получения фото с помощью API NASA установим библиотеку nasapy. Она имеет зависимость, которую не подтягивает автоматически, а именно: pandas, поэтому, нужно будет установить и ее. Чтобы работал бот установим библиотеку aiogram. А для запуска переводчика нам потребуется аж три библиотеки. Это: selenium bs4 lxml. С помощью selenium будем запускать браузер, искать поле перевода, вставлять в него текст и забирать html страницы. С помощью bs4 и lxml будем парсить полученный код и забирать из него переведенный текст. Для установки всего этого добра пишем в терминале:

pip install aiogram nasapy selenium bs4 lxml pandas

Про переводчика DeepL я писал вот в этой статье. Однако, полный модуль нам не нужен, поэтому мы слегка сократим код и изменим XPath поля ввода. Так как по старому пути поле больше не находиться.

Также, нужно будет получить токен API NASA. Дается он бесплатно, нужно только зарегистрироваться вот на этой . Здесь жмете кнопку «Generate API key», заполняете форму и получаете ключ, который продублируется вам на почту, указанную при регистрации.

Еще нужно создать бота телеграмм в BotFather. Подробнее об этом можно почитать тут. Также, если вы планируете публиковать в канал, нужно его создать и назначить администратором созданного бота. А также получить id-канала, который будет равен короткой ссылке канала, с добавлением собаки: @ссылка_на_канал.

Теперь давайте импортируем в модуль все необходимые библиотеки:

Python:
import time
from datetime import datetime

import nasapy
from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hlink, hspoiler, text

from config import token, id_channel, nasa_key
from deep import browser_get_html

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


Получение фото дня

Создадим функцию nasa_image(date). На вход она будет принимать дату, за которую нужно получить снимок. В ответе может прийти ссылка на видео, не всегда это будет фото. Но это не особо важно. Библиотека nasapy позволяет получить фото и за более поздние даты, для этого ей нужно передать ту дату, фото из которой вы хотите получить. Но в данном случае, так как фото дня является единственным, мы будем получать его каждый день и публиковать в канал.

Объявим переменную и передадим в нее экземпляр класса Nasa, в который передадим API-ключ полученный ранее. Затем запустим функцию picture_of_the_day, куда передадим дату, за которую нам нужно получить фото, а также параметр, означающий, что изображение нам нужно в HD качестве.

В ответе прилетает json, который содержит дату, описание, тип контента, версию сервиса, заголовок, а также ссылку на просмотр видео или загрузку фото. Из всего этого заберем ссылку, описание и заголовок. Описание тут же передадим в функцию-переводчик для перевода, после чего возвратим из функции все, что получили: ссылку, описание и заголовок.

Python:
    nasa = nasapy.Nasa(key=nasa_key)
    apod = nasa.picture_of_the_day(date=date, hd=True)
    url = apod['url']
    text_ex = apod['explanation']
    explanation = browser_get_html(text_ex)
    title = apod['title']
    return url, explanation, title

Python:
def nasa_image(date):
    """
    Создаем экземпляр класса Nasa, в который передаем
    текущую дату и параметр для получения фото в высоком
    разрешении.
    Забираем из полученных данных ссылку, описание и заголовок.
    Запускаем модуль перевода текста с помощью переводчика Deep_L,
    передаем ему описание, получаем в ответ перевод.
    :param date: Текущая дата, для получения изображения/видео.
    :return: Возвращаем ссылку, описание, заголовок.
    """
    nasa = nasapy.Nasa(key=nasa_key)
    apod = nasa.picture_of_the_day(date=date, hd=True)
    url = apod['url']
    text_ex = apod['explanation']
    explanation = browser_get_html(text_ex)
    title = apod['title']
    return url, explanation, title


Бот для отправки полученных данных

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

Python:
bot = Bot(token=token, parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot)

Создадим асинхронную функцию start, в которой укажем, что сообщения, которые мы будем пересылать являются типом Message, и, обернем все это декоратором диспетчера, который будет прослушивать прилетающие сообщения. В данном случае, у нас оно только одно, это команда для запуска бота – «/start».

Python:
@dp.message_handler(commands="start")
async def start(message: types.Message):

Двигаемся дальше. Создадим бесконечный цикл. В нем будем получать текущую дату, которая нужна для получения фото, после чего запускаем функцию получения, и, когда данные уже будут получены, пересылаем их боту, с указанием переслать в канал, id которого указано в параметрах. Затем указываем сообщение, которое отформатируем разметкой.

После того, как сообщение будет передано, засыпаем на 24 часа.

Python:
    while True:
        date_now = datetime.today().strftime('%Y-%m-%d')
        url, explanation, title = nasa_image(date_now)
        await bot.send_message(id_channel, f'{hbold(date_now)}\n\n{hlink(title, url)}\n\n{text(explanation)}\n\n')
        time.sleep(86400)

И запускаем бота на выполнение.

Python:
if __name__ == "__main__":
    executor.start_polling(dp)

Python:
"""
Модуль для получения изображения/видео дня с сайта NASA.
Публикация с помощью бота полученных данных в созданный
для этого канал. Требует установки библиотек aiogram и nasapy,
а также selenium bs4 lxml pandas
pip install aiogram nasapy selenium bs4 lxml pandas
"""

import time
from datetime import datetime

import nasapy
from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hlink, hspoiler, text

from config import token, id_channel, nasa_key
from deep import browser_get_html

bot = Bot(token=token, parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot)


def nasa_image(date):
    """
    Создаем экземпляр класса Nasa, в который передаем
    текущую дату и параметр для получения фото в высоком
    разрешении.
    Забираем из полученных данных ссылку, описание и заголовок.
    Запускаем модуль перевода текста с помощью переводчика Deep_L,
    передаем ему описание, получаем в ответ перевод.
    :param date: Текущая дата, для получения изображения/видео.
    :return: Возвращаем ссылку, описание, заголовок.
    """
    nasa = nasapy.Nasa(key=nasa_key)
    apod = nasa.picture_of_the_day(date=date, hd=True)
    url = apod['url']
    text_ex = apod['explanation']
    explanation = browser_get_html(text_ex)
    title = apod['title']
    return url, explanation, title


@dp.message_handler(commands="start")
async def start(message: types.Message):
    """
    При запуске бота получаем сообщение. Запускаем функцию.
    В функции запускаем бесконечный цикл, в котором будем
    получать текущую дату, а затем отправлять ее в функцию
    получения изображения или видео. Из функции возвращается
    ссылка на изображение/видео, описание, заголовок.
    Отправляем сообщение боту, который пересылает его в
    созданный канал, администратором которого он является.
    После чего засыпаем на 24 часа.
    :param message: Сообщение для запуска бота "/start".
    """
    while True:
        date_now = datetime.today().strftime('%Y-%m-%d')
        url, explanation, title = nasa_image(date_now)
        await bot.send_message(id_channel, f'{hbold(date_now)}\n\n{hlink(title, url)}\n\n{text(explanation)}\n\n')
        time.sleep(86400)


if __name__ == "__main__":
    """
    Запускаем бота. Передаем в функцию
    объект диспетчера, который создан ранее
    и содержит, в свою очередь объект бота,
    в котором передается токен и задается режим
    отображения сообщений.
    """
    executor.start_polling(dp)


Перевод описания к фото/видео

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

Для начала создадим модуль переводчика. Я назвал его deep.py. Импортируем в него нужные для работы библиотеки:

Python:
import os.path
from platform import system
from time import sleep

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service

Создадим функцию browser_get_html(path_text). На вход она получаем текст для перевода. Зададим опции, с помощью которых браузер будет запускаться в «безголовом» режиме, а также объявим переменную browser, чтобы ее видно было во всей функции.

Python:
    options = Options()
    options.headless = True
    browser = None

Проверяем какая операционная система запущена на компьютере пользователя. В зависимости от этого в создаваемый объект браузера передаем путь к драйверу.

Python:
    if system() == "Windows":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver.exe')))
    elif system() == "Linux":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver')))

Теперь идем на страницу переводчика, засыпаем на две секунды, чтобы дать ей прогрузиться. Ищем поле, в которое нужно вставить текст для перевода. Затем ждем еще 10 секунд, чтобы перевод успел закончиться. После этого получаем код html, который передаем в библиотеку BeautifulSoup для парсинга. Здесь ищем переведенный текст, забираем его и закрываем браузер.

После этого возвращаем переведенный текст из фукнции.

Python:
    browser.get('https://www.deepl.com/translator')
    sleep(2)
    field = browser.find_element(By.XPATH, '//*[@id="panelTranslateText"]/div[2]/section[1]/div[3]/div[2]/textarea')
    field.send_keys(path_text.strip())

    sleep(10)
    html = browser.page_source
    soup = BeautifulSoup(html, 'lxml')
    translation = soup.find('div', id='target-dummydiv')

    browser.close()
    browser.quit()

    return translation.text

Python:
"""
Модуль для парсинга перевода с помощью онлайн-переводчика
Deep_L. Получает тест, запускает браузер, парсит перевод
и возвращает его из функции.
"""

import os.path
from platform import system
from time import sleep

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service


def browser_get_html(path_text):
    """
    Принимает текст для перевода. Устанавливает опции
    браузера в безголовый режим, создает экземпляр класса
    Firefox. Определяет, какая операционная система у пользователя
    в данный момент. В зависимости от этого подгружает нужный
    веб-драйвер.
    Переходи по ссылке, ищет поле для перевода, вставляет текст,
    ждет 10 секунд для получения полного перевода. Забирает код со
    страницы браузера, парсит перевод, закрывает браузер.
    :param path_text: Текст для перевода.
    :return: Возвращает переведенный текст.
    """
    options = Options()
    options.headless = True
    browser = None

    if system() == "Windows":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver.exe')))
    elif system() == "Linux":
        browser = webdriver.Firefox(options=options, service=Service(log_path=os.devnull,
                                                                     executable_path=os.path.join(os.getcwd(),
                                                                                                  'geckodriver',
                                                                                                  'geckodriver')))

    browser.get('https://www.deepl.com/translator')
    sleep(2)
    field = browser.find_element(By.XPATH, '//*[@id="panelTranslateText"]/div[2]/section[1]/div[3]/div[2]/textarea')
    field.send_keys(path_text.strip())

    sleep(10)
    html = browser.page_source
    soup = BeautifulSoup(html, 'lxml')
    translation = soup.find('div', id='target-dummydiv')

    browser.close()
    browser.quit()

    return translation.text

Вот в принципе и все. Бот и переводчик готовы. Вот для примера изображение, которое он запостил на момент написания статьи:

screenshot1.png

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

А на этом, пожалуй, все.

Спасибо за внимание. Надеюсь, данная информация была для вас полезна
 

Вложения

  • bot_nasa.zip
    3 КБ · Просмотры: 155

vov76

One Level
13.07.2019
2
1
BIT
0
Моим друзьям астрономам это однозначно понравится. Спасибо тебе огромное!
 
  • Нравится
Реакции: Johan Van
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!