Как отслеживать полярное сияние с помощью кода на Python? Инструкция для новичков
Продолжаем разбираться в том, как почувствовать себя айтишником и самостоятельно спрогнозировать появление полярного сияния.
Привет! Это снова Александр, технический писатель в Selectel. Это вторая часть статьи о прогнозировании полярных сияний. В этот раз расскажу об автоматизации оценки состояния магнитосферы Земли с помощью Python и написании Telegram-бота, который будет присылать мне готовый прогноз по нажатию кнопки.
В первой статье я объяснил природу полярных сияний. Для понимания кода она не нужна, поэтому в этот раз мы не будем отвлекаться на выбросы корональной массы, свободные электроны и вот это все.
Используйте навигацию, если не хотите читать текст полностью:
Где брать данные
Большинство показателей собираются на Земле. Например, данные о радиопотоке от Солнца фиксирует обсерватория Национального исследовательского совета Канады. А Kp-индекс — это среднее значение К-индексов, зафиксированных в 13 геомагнитных обсерваториях, расположенных между 44 и 60 градусами северной и южной геомагнитных широт.
Тем не менее, что бы ни фиксировалось на Земле, нам нужны данные и из космоса. Допустим, на Солнце только что произошла вспышка, направленная точно на Землю. Через три-четыре дня (в зависимости от скорости потока) солнечные частицы достигнут первой орбитальной точки Лагранжа (L1) примерно в 1,5 млн км от Земли. Это такая точка между нашей планетой и Солнцем, в которой силы гравитации двух космических тел уравновешивают друг друга. Если туда поместить какой-нибудь объект, он будет оставаться почти неподвижным относительно Земли и двигаться вместе с ней вокруг звезды.
Собственно, лучшее, что туда можно поместить, — исследовательский спутник. Нам повезло: в точке Лагранжа находится аппарат DSCOVR от NASA и NOAA. Он передает на Землю важные данные о погоде в космосе.
Кстати, есть пять точек Лагранжа в системе Земля-Солнце.
NOAA собирает у себя данные с DSCOVR и исследовательского оборудования на Земле. То, что интересно нам, собрано на сайте управления в разделе Aurora Dashboard.
Более того, у NOAA есть свое мобильное приложение Aurora Forecast с красивой визуализацией. Там можно посмотреть как готовый прогноз, так и отдельные параметры, хотя почему-то не все. Так зачем вообще это все, если есть удобное приложение? Считаю вопрос риторическим. Это маленький веселый pet-проект.
Сбор данных для краткосрочного прогноза
Как я сказал в самом начале, это мой первый опыт работы с Python. Используя обрывки знаний с Хабра, Stack Overflow, YouTube и других источников, я написал код, который делает ровно то, что мне нужно. Но настоящий Python-разработчик сказал, что в таком виде показывать код никому нельзя. Проблема тут в том, что объяснить происходящее далее я могу только на том, что написал сам. А облагороженную версию от коллеги оставлю ниже.
Облагороженный код, который мы далее будем рассматривать по частям:
Первая мысль — подключиться к API NOAA и написать Telegram-бота, который будет по команде ходить на сайт и забирать данные. В целом, ничего сложного. В Академии Selectel описан подобный пример с ботом, который собирает данные и присылает прогноз погоды для любого города.
Но API NOAA подойдет как раз для прогноза погоды на Земле. Все-таки это управление океанических и атмосферных исследований. Центр прогнозирования космической погоды NOAA свой API не предлагает. Значит, перейдем к другим способам. Похоже, это приключение на 20 минут.
Парсинг с помощью Selenium
Итак, нам нужно собрать данные о погоде в космосе. Сайт NOAA динамический, то есть нужные параметры магнитосферы и космоса там регулярно обновляются. Скорость солнечного ветра, Bz и Bt — каждую минуту, сила магнитных бурь и реальный Kp — каждые три часа, F 10.7 cm и прогноз Kp на три дня — раз в сутки.
Получается, обойтись библиотекой BeautifulSoup не выйдет. Она поможет вытащить со страницы статический HTML-код, но не меняющиеся данные. А нужны нам именно они.
Очевидное решение — использовать библиотеку Selenium. Устанавливаем ее и webdriver_manager в терминале:
Следом импортируем пакеты и объявляем переменные:
Большинство данных будем забирать со страницы центра прогнозирования космической погоды NOAA. Там есть все, кроме реального и прогнозного Kp-индекса, но эту проблему мы решим чуть позже. А пока спарсим скорость солнечного ветра, Bt, Bz, F 10.7 cm и силу магнитной бури.
Первые четыре можно получить одной командой, поскольку все они в HTML-коде страницы находятся внутри id "summary". Удобно, но Selenium в таком случае выдаст результат одной строкой с той же пунктуацией, что на странице.
Мне это не нравится. Соберем все по отдельности и запишем каждый показатель с новой строки в текстовый файл:
Как видите, у каждого элемента есть свой id и только с одним что-то пошло не так. Это сила магнитной бури. В HTML-коде, конечно, есть id нужного элемента — "noaa_scale_info_effect". Но Selenium почему-то не может его достать. Так я пришел к идее спарсить показатель через XPATH. Почему нет? Копируем его из кода страницы — "/html/body/div[4]/section/div/div/div/div/section[1]/div/div/div[1]/div[4]/div[1]/div/div[2]/div[4]/div[1]". Здесь важно, что сила магнитной бури представлена в нескольких местах. Есть максимальная за прошедшие сутки, последняя зафиксированная и три прогнозных на ближайшие три дня. Нас интересует тот показатель, что зафиксирован на планете за последние три часа — Latest Observed.
Поскольку сила магнитной бури и Kp-индекс хорошо соотносятся друг с другом, на этом сбор данных можно было бы и закончить. Но я решил достать оба показателя. Забегая вперед, скажу, что это опциональное решение. Индекс я буду использовать, просто чтобы точнее отслеживать интенсивность бури. Например, уровню G3 обычно соответствуют Kp-индексы 6,67, 7,00 и 7,33. Таким образом, отслеживание Kp позволит судить, усиливается или слабеет буря. Но не забывайте, о чем я писал выше: иногда корреляция двух показателей отключается и при достаточно высоком Kp уровень G остается на нуле.
Итак, на основной странице Kp-индекс есть в интерактивном дашборде, но оттуда данные не достать. Зато они собраны на другой странице этого же сайта, не самой очевидной. Я не придумал ничего лучше, чем загрузить содержимое json-файла в новый текстовый документ, найти в нем все дробные числа и записать последнее в уже имеющийся файл с остальными параметрами. Это и есть самый поздний зафиксированный Kp-индекс. В коде это выглядит так:
Удлиняет ли это код? Да. Замедляет ли в итоге время ответа бота? Наверное. Так нужно ли это делать? Необязательно, но ради большей информативности можно.
Оценка показателей
Теперь у нас есть текстовый файл, в котором собраны нужные данные. Классно? Классно. Но в текущем виде файл "parameters" не очень информативен. А ведь его содержимое мы и будем потом отправлять в мессенджер.
Путем нехитрых манипуляций можно сделать его куда более понятным. Просто чуть пофиксим запись данных от Selenium в текстовый файл:
Благодаря этому мы получим уже гораздо более содержательный текст:
Правда, первый же человек, которому я показал такое сообщение от бота в Telegram, спросил меня: «Так, ну а сияние-то где будет?». Кажется, приключение на 20 минут выходит из-под контроля.
Расчет времени
Добавим для ясности три строки.
В первой строке на основании данных о скорости потока рассчитаем время его прибытия на Землю.
Во второй — покажем, к северу от какой широты возможно появление сияния при актуальном состоянии магнитосферы.
В третьей — дадим финальную оценку вероятности появления авроры, основываясь на ориентации межпланетного магнитного поля и силе магнитной бури.
Как мы помним со школы, время = расстояние / скорость. Скорость потока солнечных частиц нам известна — ее мы получили от Selenium. Расстояние — тоже. Это около 1,5 млн км от Земли до спутника DSCOVR, который и фиксирует скорость солнечного ветра. Конечно, цифра постоянно варьируется, но в масштабах космоса этим можно пренебречь (как и временем, которое потребуется сигналу, чтобы добраться от спутника до Земли).
Сперва зададим две константы:
Затем, добавим формулу с округлением до одного знака после запятой:
Добавим новую строку:
Почему я не написал текст по-русски? Из-за падежей. Мне не хочется получать сообщение с текстом «50 минуты» или «51 минут». Наиболее простым решением счел запись на английском. Ну и раз так, дальше тоже буду писать по-английски.
Здесь считаю уместным небольшое пояснение. Все важные для прогноза показатели собираются на Земле. То есть если мы видим, например, Kp = 7,33, то он уже есть. Так зачем рассчитывать время? Оно показывает, как скоро на магнитосферу начнет воздействовать солнечный ветер, только что зафиксированный спутником DSCOVR. Если видим, что его скорость падает, весьма вероятно (но не гарантировано) уменьшение активности магнитосферы. И наоборот. А время показывает, когда произойдет это изменение.
Расчет координат
Следующий шаг — добавить информацию о том, к северу от какой широты вероятно наблюдение сияния при имеющейся магнитной буре. Здесь я воспользовался функцией vars(), чтобы чрезмерно не раздувать код. Я хочу добавить строку «Location: north to X° when Bz<0», в которой Х подбирался бы в зависимости от записанной ранее силы магнитной бури. Уточнение «when Bz<0» просто будет напоминать, что даже при геомагнитном шторме межпланетное магнитное поле должно быть ориентировано на юг. Иначе чуда не случится.
Возникает проблема. При поиске "Storm = G" будут находиться "Storm = G1" и так далее. Проблема изящно решается добавлением пробела в конце строки при записи element5.text и location_vars.
Уточню, что прогнозирование места для наблюдений на основании оценки магнитосферы — это лишь определение широты, к северу от которой может возникнуть сияние. Чтобы найти наиболее удобную конкретную локацию, нужно выбрать пространство с безоблачным темным небом и без высоких объектов на горизонте. Здесь-то и помогут сервисы с прогнозом погоды, например тот же Windy.
Оценка вероятности сияния
Итак, у нас уже есть легкочитаемая информация о том, где в теории можно увидеть сияние. Но пока нет очевидного ответа на вопрос, а возникнет ли оно вообще при имеющихся условиях и какова будет его видимость. Чтобы дать оценку, нужно учесть величину Bz.
Наиболее простым вариантом я счел использование регулярных выражений. Так можно однозначно отличить, скажем, -23 от -2, 2, 3 и 23. При этом найти простое решение с функцией vars(), как это было выше, у меня не получилось. Хотя уверен, что оно есть. Как бы то ни было, вот результат:
Итак, выше описаны четыре условия, от которых зависит добавление еще одной строки.
В файле есть отрицательное однозначное число — добавляем строку «Low chance to see aurora 😾». Отрицательным числом здесь может быть только значение Bz. И если оно не ниже -9, ждать яркого сияния не стоит при любой буре.
В файле есть отрицательное число в диапазоне от -10 до -19 — добавляем строку «Good chance to see aurora 😺».
В файле есть отрицательное число от -20 до -100 — добавляем строку «WOW! High chance to see aurora! 😺». Как показывает практика, при Bz ниже -20 сияние точно появится и будет хорошо различимо на темном небе.
В файле не найдено отрицательных чисел. Что ж, прямо сейчас сияния точно не будет. А при отсутствии магнитных бурь (Storm: G) можно смело ложиться спать.
В целом здесь можно сделать более подробную градацию в зависимости от значения Bz. Но я решил, что и так достаточно. Число -100 не является каким-то сакральным. Чисто теоретически оно может быть и ниже, но шансы на это крайне малы. Даже Bz = -50 — чрезвычайно редкое явление.
После всего описанного выше мы получаем уже такой удобный файл:
Сбор данных для трехдневного прогноза
Казалось бы, что вот теперь-то точно можно двигаться дальше. Но нет. Сейчас можно получить актуальные данные, которых хватит для прогноза плюс-минус на три часа. Но ночную поездку за город я предпочитаю планировать хотя бы за сутки.
Выше я упомянул, что NOAA дает трехдневный прогноз геомагнитной активности планеты. Он выражается как в Kp-индексе, так и в оценке силы предстоящих магнитных бурь. Можно собирать и то, и другое, но прогноз Kp более информативен. Он формируется на каждые три часа в течение следующих трех суток. Очень удобно.
Данные о прогнозе Kp-индекса на три дня я собрал примерно так же, как уже зафиксированный Kp. Только этот прогноз лежит на другой странице. Загружаем все содержимое в отдельный файл:
Эти строки я не добавляю в код сразу. Я использую их чуть позже и добавлю в код бота.
Итак. Мы собрали все данные и дали им необходимую оценку. Пора переходить к написанию Telegram-бота, чтобы получать прогноз в мессенджере по нажатию кнопки.
Написание Telegram-бота
Первым делом открываем Telegram, находим @BotFather и отправляем ему команду /newbot. Далее придумываем будущему боту имя и username. Итогом всех манипуляций будет уникальный токен. Обязательно его сохраните и постарайтесь не потерять. Токен нужен, чтобы управлять ботом.
Теперь переходим к написанию кода. Снова начинаем с установки библиотеки. Я использовал pyTelegramBotAPI:
Импортируем пакеты. На этом шаге вместо "TOKEN" указываем токен, полученный от @BotFather.
Настроим приветствие. По команде /start будут появляться две reply-кнопки. Одна для получения прогноза на основе актуального состояния магнитосферы, другая — для трехдневного прогноза Kp-индекса.
Следующий шаг — настройка действий бота в ответ на нажатие кнопок. Начнем со сценария, в котором мы хотим получить оценку текущих показателей.
Здесь все просто: нажатие кнопки "Актуальные параметры" запускает скрипт с Selenium, записанный в файле aurora.py. Тот в свою очередь записывает текстовый файл, а бот отправляет его содержимое в ответ.
Почти то же самое делаем со второй кнопкой. Только при ее нажатии бот собирает данные о прогнозе Kp-индекса на три дня. Вот здесь и пригодился тот небольшой кусочек кода из раздела о сборе трехдневных показателей.
Все строки из документа с прогнозом нам не так уж и нужны. На мой взгляд, чтобы отсеять лишнее, но сохранить информативность, хватит строк с 16 по 25. Не забываем, что индексация в Python начинается с 0, поэтому указываем диапазон [15:25]. Бот читает эти строки и отправляет их одним сообщением в ответ на нажатие кнопки.
Как и в предыдущем случае, заботливо собранный код отредактировал мой коллега. Результат ниже.
Теперь все работает так, как задумано. Остался последний шаг.
Деплой бота в облако
Telegram-бота нужно поселить на облачный сервер. Так он будет работать постоянно, а не только при запуске кода на компьютере. Казалось бы, ну уж этот-то процесс описан миллион раз во всех возможных вариациях. Но нет.
Сервер с Ubuntu
Обычно деплой Telegram-бота на облачный сервер и его запуск выглядят просто. Нужно создать сервер, подключиться через терминал по SSH, установить необходимые пакеты, завести виртуальное окружение, клонировать репозиторий и запустить бота. Но не в этом случае.
После запуска бота на сервере оказалось, что работает только кнопка для вызова прогноза Kp-индекса на три дня. А вот на нажатие кнопки для запроса актуального состояния магнитосферы бот не реагирует. Повторюсь, что локально все работает прекрасно. Ошибок сервер тоже не выдает.
Смотрим логи:
Как видим, Selenium не хочет работать. Оказывается, такая проблема встречается довольно часто — эта библиотека без нареканий запускается локально, но на сервере начинает капризничать. Вопрос уже поднимался на Stack Overflow. Есть три возможных решения.
Первое решение (правильное) — пофиксить код, опираясь на документацию Selenium, и соответствующим образом донастроить сервер. Плюс такого подхода — возможность нормально запустить бота в облаке. Хотя реализация потребует некоторого количества времени и усилий.
Второе решение — оставить все как есть и запускать код локально. Плюс — все будет работать вообще бесплатно. Можно вечером запустить код на ноутбуке и уехать ловить сияние, отслеживая параметры в Telegram. Минус — остановка кода приведет к остановке бота. А я хочу поделиться ботом с друзьями и знакомыми. Будет странно, если они смогут им пользоваться, только когда мне удобно.
Третье решение — арендовать сервер не на Ubuntu, а на Windows. Плюсы — это самый быстрый и простой способ добиться результата. Не потребуются никакие доработки. С другой стороны, сервер на Windows дороже сервера на Ubuntu, а его ресурсы даже в минимальной комплектации могут быть избыточны для простого Telegram-бота, Google Chrome и IDE (одно ядро, 2 ГБ RAM и 32 ГБ SSD). Хотя если есть другие проекты, для которых нужен Windows Server, решение может оказаться вполне рабочим.
Сервер с Windows
Вероятно, в ближайшее время я все же пойду правильным путем: немного перепишу код и донастрою облачный сервер с Ubuntu. А пока добавим еще немного костылей.
Переходим в панель управления, открываем раздел Облачная платформа → Серверы. Нажимаем на кнопку Создать сервер. В поле Источник выбираем Windows и подходящую версию ОС (в моем случае Windows Server 2019 Standard).
Минимальной конфигурации хватит с запасом. По умолчанию SSH-ключ не требуется, т. к. подключаться мы будем по RDP.
Как только статус сервера сменится на ACTIVE, можно открыть Подключение к удаленному рабочему столу на компьютере. Данные для входа доступны в панели управления. Публичный IP-адрес можно посмотреть на вкладке Порты, а логин и пароль — на вкладке Консоль.
После подключения нужно выполнить несколько простых операций.
1. Нажмите Пуск и откройте Server Manager.
2. Перейдите во вкладку Local Server. Найдите справа строку IE Enhanced Security Configuration, переключите настройки на Off и нажмите кнопку ОК.
3. Скачайте и установите Google Chrome и любой IDE (в моем случае PyCharm).
4. Скопируйте файлы .py в проект и запустите код.
На этом подключение можно разорвать, бот продолжит работать. При необходимости вы можете доработать бота, добавить асинхронности в функции и обработчики исключений, которые могут возникать, например, из-за проблем с сайтом NOAA.
UPD: делаем то же самое без Selenium
Спустя несколько дней после публикации статьи получил совет с Хабра — обратить внимание на страницу на сайте NOAA. Там собраны ссылки на файлы json, в которых аккумулируются все нужные данные (и ненужные тоже). Это избавляет от необходимости использовать Selenium и позволяет уложить весь проект в один файл.
Правда, из нескольких json придется отсеять все лишнее, но в целом в этом нет ничего сложного. Вот что получилось в итоге:
И вот такой код уже легко можно запустить на облачном сервере с Ubuntu без дополнительных манипуляций и настроек. Описанный апдейт, безусловно, имеет очевидные преимущества. Во-первых, это дешевле за счет ОС. Во-вторых, бот теперь отвечает значительно быстрее, поскольку не парсит данные через Selenium. Единственный обнаруженный минус — скорость солнечного ветра записывается в файл json раз в три минуты, а не раз в минуту, как на сайте. Но будем честны — это не критично. Приятный бонус — во время доработки кода я нашел и исправил несколько ошибок.
Как арендовать сервер и какой выбрать
Наш Telegram-бот не требует больших вычислительных мощностей, поэтому нас устроит облачный сервер в минимальной конфигурации. Чтобы арендовать его, перейдите в панель управления, выберите раздел Облачная платформа и нажмите на кнопку Создать сервер.
Далее необходимо настроить конфигурацию. В поле Источник выберите Ubuntu. Как я сказал, большие мощности нам не нужны, поэтому в разделе Конфигурация переключитесь на вкладку Shared и задайте настройки, как на скриншоте ниже:
- доля vCPU — 10%,
- RAM — 512 МБ,
- Диск — 5 ГБ.
Не забудьте также создать и добавить SSH-ключ. О том, что это такое и как этим пользоваться, можно прочитать в документации Selectel.
Как задеплоить бота на сервер
Вот теперь точно последний шаг. Подключаемся к серверу по SSH и проводим нехитрую настройку. Чтобы не перегружать никого деталями, я просто приведу список команд, которые нужно поочередно ввести в терминале:
- sudo apt update,
- sudo apt upgrade,
- sudo apt --reinstall install python3-pip -y,
- sudo apt install nodejs,
- sudo apt install npm,
- npm install pm2 -g,
- pip install virtualenv,
- mkdir <название папки> (создаем папку на сервере, внутри которой будет жить бот),
- cd <название папки>,
- virtualenv venv.
В этом месте нужно поместить файл с ботом на сервер. Это можно сделать разными путями. Например, если вы предварительно загрузили проект на GitHub, можно просто клонировать его на сервер командой git clone. Либо можно воспользоваться одной из бесплатных утилит, скажем, WinSCP. Она интуитивно понятно, весь процесс выглядит как обычное копирование папок и файлов на компьютере.
После того, как файл .py с ботом размещен на сервере, остается еще несколько шагов. Продолжаем вводить команды в терминале:
- source venv/bin/activate,
- pip install -r requirements.txt,
- pm2 start <название файла с ботом>.py --interpreter=python3
Вы могли заметить, что в предпоследней команде появился какой-то requirements.txt. Крайне полезная штука, кстати. Это файл с зависимостями проекта. Прочитав его, сервер поймет, какие версии библиотек нужно использовать в проекте. Это поможет избежать неожиданных ошибок. Чтобы создать файл в IDE, после написания кода введите команду в его терминале:
Файл появится на компьютере в директории проекта. Просто скопируйте его вместе с основным файлом на сервер.
Если в какой-то момент потребуется остановить выполнение кода, введите в консоли сервера или в терминале команду:
Весь код, представленный в статье, рабочий. Если захотите воспроизвести описанный опыт, просто скопируйте его, замените TOKEN и повторите все шаги по аренде сервера и деплою проекта.
Немного о тонкостях наблюдений
Увы, идеальные условия бывают далеко не всегда. И в большинстве случаев сияние на небе будет вообще едва различимо невооруженным глазом. Мы увидим какую-то белесую пелену, похожую на туман, а вовсе не то, что нам показывают на картинках.
По своему опыту могу сказать, что для наблюдения полярных сияний на широте Санкт-Петербурга Kp-индекс должен достичь хотя бы 5 баллов (отметки слабой магнитной бури G1). В этом случае будет видна та самая едва различимая и слегка мерцающая пелена. Но если вооружиться камерой, пусть даже в смартфоне, на выдержке от 10 секунд вполне получится снять яркое зеленое свечение с выраженными фиолетовыми акцентами. При тех же параметрах, скажем, в Мурманске (68°58’ северной широты) видимость авроры будет намного лучше.
Советую запастись терпением. Капризное межпланетное магнитное поле может внезапно развернуться и несколько часов «смотреть» на север, не давая разгореться авроре. Выезжая за город для наблюдений, стоит рассчитывать, что провести там придется не меньше 2-3 часов. Есть смысл прихватить с собой горячий чай или кофе в термосе и тепло одеться, потому что вы точно не поедете за сиянием жаркой июльской ночью.
Также заранее подумайте, куда именно вы поедете для наблюдений. Так вы спланируете время на дорогу, сможете подобрать место без городской засветки и избежите необходимости внезапно штурмовать бездорожье. Например, мои любимые места под Петербургом — Первый северный форт в Кронштадте, окрестности Лебяжьего пляжа на южном берегу Финского залива и Осиновецкий маяк на Ладожском озере. До всех этих локаций можно относительно быстро добраться из любой точки города на любом автомобиле. Если благоприятные условия прогнозируются на выходные, можно отправиться с ночевкой на север Ленобласти, а еще лучше — в Карелию.
Доводилось ли вам видеть полярное сияние? Делитесь фотографиями, лайфхаками и опытом в комментариях. А если остались вопросы, задавайте.
Статья интересна, но жаль, что не повторю инструкцию. Просто не смогу увидеть полярное сияние(
Рады, что вам понравилось! Уверены, когда-нибудь вы его увидите ❤️🦖
А цена сервера на скрине - это в день?
Александр, здравствуйте! Цена указана за месяц)
Также в панели управления можно посмотреть стоимость за час и день: my.selectel.ru
для жителей лен области полезно будет!