На Хабре есть интересная статья о том, как энтузиасты делают погоду. Энтузиасты делают, а мы воспользуемся плодами их трудов — получим эту самую погоду от OpenWeatherMap.org скриптом на Python'е.

Для получения доступа к сервису погоды придется пройти несложную процедуру регистрации на сайте OpenWeatherMap.org. Сформируем и отправим запрос, разберем ответный пакет в формате JSON, и получим текущую температуру с описанием состояния погоды.



Зарегистрироваться на openweathermap.org совсем несложно, а остальное сделать будет ещё проще.

Регистрация нужна для получения идентифицирующей пользователя строки App Id, состоящей из набора букв и цифр (похоже — только из шестнадцатеричных цифр). Такого вида:
«6d8e495ca73d5bbc1d6bf8ebd52c4». После регистрации нужно зайти в личный кабинет и взять App Id, который там называется «API key».

Формирование строки запроса


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

http://api.openweathermap.org/data/2.5/find?q=Petersburg&type=like&APPID=6d8e495ca73d5bbc1d6bf8ebd52c4

В запросе нужно указать нужный город (вместо «Petersburg») и свой App Id (вместо «6d8e495ca73d5bbc1d6bf8ebd52c4». Можно уточнить запрос, указав идентификатор страны после названия города через запятую. Например, так:

http://api.openweathermap.org/data/2.5/find?q=Petersburg,RU&type=like&APPID=6d8e495ca73d5bbc1d6bf8ebd52c4

Собственно запросная строка будет сформирована самой библиотекой requests в функции get, которую используем для отправки запроса:

requests.get("http://api.openweathermap.org/data/2.5/find",
                 params={'q': s_city, 'type': 'like', 'units': 'metric', 'APPID': appid})


Проверка наличия в базе информации о нужном населенном пункте


План такой. В ответ на сформированный запрос получаем пакет в формате JSON. Разбираем пакет и получаем нужные значения по названиям полей.

import requests
s_city = "Petersburg,RU"
city_id = 0
appid = "буквенно-цифровой APPID"
try:
    res = requests.get("http://api.openweathermap.org/data/2.5/find",
                 params={'q': s_city, 'type': 'like', 'units': 'metric', 'APPID': appid})
    data = res.json()
    cities = ["{} ({})".format(d['name'], d['sys']['country'])
              for d in data['list']]
    print("city:", cities)
    city_id = data['list'][0]['id']
    print('city_id=', city_id)
except Exception as e:
    print("Exception (find):", e)
    pass

Запомним числовой идентификатор города city_id для последующего запроса, потому что поставщики сервиса рекомендовали делать запрос не по имени, а по идентификатору.
В ответе может оказаться несколько городов, соответствующих нашему запросу. Кстати, если в запросе указать “Moscow” и убрать страну из строки приведенного в примере запроса, то гарантированно получим несколько строк в списке cities:
city: ['Moscow (RU)', 'Moscow (US)', 'Moscow (US)']

Получение информации о текущей погоде


Осталось только получить искомую информацию о погоде. Если нас не интересуют имперские единицы измерения, то в запросе указываем, что желаем получить метрические единицы: «units=metric». Если описание погоды нужно получить на русском, то указываем «lang=ru».

try:
    res = requests.get("http://api.openweathermap.org/data/2.5/weather",
                 params={'id': city_id, 'units': 'metric', 'lang': 'ru', 'APPID': appid})
    data = res.json()
    print("conditions:", data['weather'][0]['description'])
    print("temp:", data['main']['temp'])
    print("temp_min:", data['main']['temp_min'])
    print("temp_max:", data['main']['temp_max'])
except Exception as e:
    print("Exception (weather):", e)
    pass

Если верить сервису, сейчас (14.11.2016 в 23:20) в Москве:
conditions: небольшой снег
temp: -5.25
temp_min: -6
temp_max: -5

Прогноз на 5 дней


    try:
        res = requests.get("http://api.openweathermap.org/data/2.5/forecast",
                           params={'id': city_id, 'units': 'metric', 'lang': 'ru', 'APPID': appid})
        data = res.json()
        for i in data['list']:
            print( i['dt_txt'], '{0:+3.0f}'.format(i['main']['temp']), i['weather'][0]['description'] )
    except Exception as e:
        print("Exception (forecast):", e)
        pass

Получим такой вывод:
2016-11-24 15:00 -1 7 м/с ЮЗ пасмурно
2016-11-24 18:00 +2 7 м/с З легкий дождь
2016-11-24 21:00 +2 7 м/с З легкий дождь
2016-11-25 00:00 -0 7 м/с З ясно
2016-11-25 03:00 +0 7 м/с З небольшой снегопад
2016-11-25 06:00 -0 6 м/с СЗ слегка облачно
...

Скачать owm-request.py. Чтобы этот скрипт заработал, нужно в первой строке ввести Ваш «API key», полученный при регистрации на OpenWeatherMap.org.
Командная строка, например, такая:
$python owm-request.py Moscow,RU

На сайте OpenWeatherMap есть ещё масса интересного — получение информации по географическим координатам, архив погоды, информация с конкретных метеостанций. Описание всех доступных сервисов можно посмотреть здесь http://openweathermap.org/api
Для работы на Python'е с OpenWeatherMap существует специализированная библиотека pyowm.

Помимо OpenWeatherMap есть другие сайты, предоставляющие аналогичную информацию. Например, WorldWeatherOnline. Доступные API можно посмотреть здесь. Регистрация нужна. Есть библиотека на Python'е: pywwo.

Отдельное спасибо JetBrains за PyCharm.
Поделиться с друзьями
-->

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


  1. argz
    15.11.2016 01:44

    Я делал такое же, только погоду с прогнозом у меня запрашивал stm32 и выводил результат на небольшой дисплей


    1. Yanovets
      15.11.2016 08:29

      А сервис погоды был этот же — openweathermap.org?


  1. romangoward
    15.11.2016 02:24
    +12

    Планирует ли автор выложить полный исходный код приложения на гитхаб? Будут ли рассматриваться пулл-рекввесты сообщества? Готовы ли юнит-тесты для полноценной интеграции?
    Нужные десктопные уведомления, где интерефейс доступа? Или это бэкенд? А какие базы данных поддерживаются? Очень нужна %database_name%!!1


    Как и обещал — всё очень просто.

    Рассматривает ли автор возможность миграции на более производительную платформу разработки?
    Есть готовые наработки для bash :-P


     #!/bin/bash
    
    set -euf -o pipefail
    
    API_KEY="mew"
    LOCATION="Petersburg,RU"
    
    exec 99<> /dev/tcp/api.openweathermap.org/80
    
    echo -e "GET /data/2.5/find?q=${LOCATION}&type=like&APPID=${API_KEY} HTTP/1.1\r\nhost: api.openweathermap.org\r\nConnection: close\r\n\r\n" >&99
    
    HTTP_ANSWER_WITH_HEADERS=`cat <&99`
    
    JSON_OUTPUT=${HTTP_ANSWER_WITH_HEADERS#*POST}
    
    WEATHER_DESC=`echo $JSON_OUTPUT | jq '.list[0].weather[0].description'`
    
    notify-send "It's ${WEATHER_DESC} at ${LOCATION}"


    1. Yanovets
      15.11.2016 09:34
      +1

      Проверил — Ваш скрипт работает. Пришлось, правда, поставить утилитку jq, которой у меня не оказалось. И заработало. Спасибо за вклад в дело получения метео. Только я не вполне понял Ваши вопросы насчёт юнит-тестов, бэкэнда и пр. Я то зашёл в эту тему из python'а. Узнал, что есть такой сервис OpenWeatherMap, удалось получить текущую температуру, которая на удивление соответствовала окружающей меня действительности. В python'е нашлась хорошая библиотека requests, которая позволила не только запрос сделать, а ещё и распарсить JSON-формат. Подумал, что кому-нибудь ещё может быть интересно, что 1) существует такой общественный сервис, в который каждый желающий может выложить собственную метео-информацию о погоде (идея сама по себе интересная); 2) сервисом OpenWeatherMap можно воспользоваться для получения разного вида информации (в том числе на bash'е), и это достаточно просто делается; 3) примитивный, но работающий код на python'е. И ещё подумал, что, может, кому-нить это может быть интересно, поэтому этим всем я решил поделиться. Где-то есть прокол в моих соображениях?


      1. kAIST
        15.11.2016 12:37
        +3

        Я думаю romangoward сарказмирует. А причина сарказма, это банальная статья из разряда практически hello world. Получение прогноза погоды, это наверное то, что делал почти каждый, изучая программирование (раньше в вебе информер прогноза погоды висел почти на всех сайтах).


  1. prostofilya
    15.11.2016 04:50
    +1

    Библиотечка есть


    1. Yanovets
      15.11.2016 09:35
      +1

      Спасибо! Интересно будет попробовать.


      1. Yanovets
        15.11.2016 11:16
        -2

        Ура! Карма вернулась! Теперь смог плюсик Вам поставить за библиотеку pyowm :)


  1. Nikobraz
    15.11.2016 09:00
    +6

    curl wttr.in


    1. Yanovets
      15.11.2016 11:28
      -1

      Прикольная штука. Спасибо! В Linux'е в командной строке нужно исполнить
      $curl wttr.in
      И в терминалке появится красивая картинка, показывающая погоду в Питере. Вот такого вида.


  1. djhox
    15.11.2016 09:36
    +1

    http://trytoguide.me/post/12 — тот же openweather, только по координатам


    1. Yanovets
      15.11.2016 11:40
      -1

      Вот спасибо! По ссылке есть код на python'е! Используются две библиотеки urllib и json. И я тоже сначала этот вариант использовал. Но потом нашел более симпатичную альтернативу — библиотеку requests. И ещё подробно описан процесс регистрации. Ну, и недостаток моего кода решён — сделан перевод на русский текстов с описанием погоды. Хотя, думаю, красивее было бы использовать не if'ы, а dictionary для этой цели. Спасибо за полезный вклад!


  1. Malemute
    15.11.2016 10:48
    +1

    На онлайн-курсах teamtreehouse.com есть интересный — и достаточно компактный — учебный проект под Андроид, там прогноз погоды на основе API к сайту forecast.io
    Там прогноз на неделю, и по часам на ближайшие сутки с половиной.
    Я его делал в немного расширенном виде — прикрутил еще геолокацию, чтобы показывать погоду в текущей точке. На своем телефоне сам пользовался. А вот чего не знаю — это какой источник данных точнее. Forecast.io — скажем так, на четверку с минусом. А как насчет openweathermap.org?


    1. Yanovets
      15.11.2016 11:11
      -2

      Интересно будет посмотреть Вашу реализацию с forecast.io. Спасибо! Насчёт точности openweathermap — не знаю. Судя по статье от 2012 года, на российской территории станций маловато, поэтому и с точностью должны быть проблемы. Вряд ли за 4 года ситуация кардинальным образом изменилась. А вот западнее — насчёт Европы — точность должна быть лучше. Там с метео-станциями всё очень неплохо.


  1. torrie
    15.11.2016 13:30
    +3

    Шёл 2016ый. Люди начали пользоваться api.


    1. Yanovets
      15.11.2016 14:04

      Шёл 2016-й. А некоторые люди всё ещё только учатся ходить.
      Вы умеете api? Это очень хорошо! Так научите меня тому, что Вы умеете. Чему я научился, тем и делюсь. Много материала, где есть общие идеи, намёки, а мне, который учится ходить, хотелось бы поподробнее, с объяснением деталей. Это вот я, как для себя и написал. Или, как если бы я это сыну объяснял. По-моему такой стиль изложения вполне имеет право на жизнь.


  1. KorP
    15.11.2016 13:34
    +1

    По-моему вы не очень поняли что хабр это всё-таки не личный бложик и поделки уровня hello world всё-таки тут не нужны. Ну а если вы сами учитесь (складывается такое впечатление по камментам) — это то же не самое лучше место.


  1. respe-t
    15.11.2016 14:04

    Вопрос чуть в сторону от темы статьи:
    можно ли на этом сайте узнать, какая была погода в конкретный день в определенном городе (например, в Москве год назад 15.11.2015)?


    1. Yanovets
      15.11.2016 14:19

      Там есть такая штука: http://openweathermap.org/history
      Только эта информация платная. «Historical data is available for 1 month previous in Starter account ($40), for 1 year previous in Medium accounts ($180), and is 5 and more year previous in Advanced accounts ($470)». Если нужна информация годичной давности, то подписка стоит $180 в месяц.


      1. respe-t
        15.11.2016 14:45

        Спасибо!


  1. Zagrebelion
    16.11.2016 07:02
    +1

    Каждый раз, когда url для requests.get собираетcя конкатенацией (ну или форматированием) строки, где-то умирает зайчонок.

    requests.get(«http://api.openweathermap.org/data/2.5/weather», params={'app_id': app_id, 'q':'Moscow,RU', 'units':'metric'})

    Пожалуйста, пожалейте зайчих.


    1. Yanovets
      16.11.2016 12:15

      Спасибо за дельное замечание. Исправлено. Так что о животных можете не волноваться )


  1. asd111
    16.11.2016 10:22
    +1

    Чтобы ответ приходил на русском добавьте lang=ru
    к строке запроса.


    1. Yanovets
      16.11.2016 10:34

      Спасибо, asd111! Действительно, в ответ на запрос «weather» пришёл description на русском: «небольшой снегопад»! Что, кстати, полностью соответствует действительности — за окошком идет снег (в Питере).


  1. don_dimus
    16.11.2016 10:36

    Когда я изучал Питон на Степике (курс Python: основы и применение), в качестве примера работы с API в уроке 3.6 (ссылка:https://stepik.org/lesson/API-24476/step/2?course=Python-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D1%8B-%D0%B8-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5&unit=6781 ), как раз рассматривался пример получения данных из OpenWeatherMap.org.
    Ничто не ново под луной… (с)