JavaRush /Java Blog /Random-TL /Lumilikha kami ng isang simpleng bot ng panahon para sa T...
Philip J.
Antas
Днепр

Lumilikha kami ng isang simpleng bot ng panahon para sa Telegram sa ilang gabi

Nai-publish sa grupo
Kamusta kayong lahat! Ang paksa ng paglikha ng mga bot para sa Telegrams ay medyo na-hackney, at maraming mga gabay ang naisulat (halimbawa, ito ) . Samakatuwid, mas mabuting tingnan nating mabuti ang pagtatrabaho sa ilang third-party na API, dahil isa itong kritikal na kasanayan para sa anumang web developer. Sasabihin ko kaagad na ang application ay hindi itinakda upang magbigay ng pinaka-functional at kapaki-pakinabang na forecast; walang saysay na makipagkumpitensya sa mga site ng panahon; mahalagang matutunan kung paano magtrabaho sa mga malalayong koneksyon at pag-parse ng data gamit ang Java. Kaya, alamin muna natin kung ano ang kailangan natin. Ang aming aplikasyon ay mahalagang binubuo ng tatlong lohikal na bahagi:
  • tumanggap ng mensahe mula sa user
  • iproseso ang mensahe, at, kung ito ay isang wastong utos, maghanda ng data para sa tugon. Sa aming kaso, maghanda ng taya ng panahon kung ang gumagamit ay pumasok sa tamang lungsod
  • magpadala ng handa na impormasyon sa gumagamit sa chat
Первый и третий пункт довольно прост, и касается только работы с Telegram API, желающие могут изучить ссылку, оставленную выше. Мы же заострим внимание на втором пункте. API используют тогда, когда одни разработчики хотят предоставить доступ к своим данным другим разработчика. Возьмём, к примеру, Вконтакте. У каждого есть список друзей, он хранится где-то в базе данных на serverах ВК. Предположим, что Howой-то программист решил создать игру в шашки с друзьями. Whatбы его приложение работало правильно, программа должна уметь получать список друзей любого игрока. Для этого программист находит documentацию к ВК API, и смотрит, Howой request нужно сделать, чтобы это список получить. Этот request называется HTTP-requestом. А два самых распространённых HTTP-requestа — это GET и POST. Про них в сети тоже достаточно, останавливать не буду. Для наших целей, а именно получения данных прогноза погоды будет достаточно простого GET-requestа. Если обратиться с GET requestом к обычному веб-serverу, он, зачастую, вернёт html-code, который браузер преобразует в удобную для пользователя page, применив стor, скрипты и пр. Если же мы обращаемся с таким requestом к API serverу, в ответ обычно возвращаются только сырые данные без стилей и скриптов. В окне браузера это выглядит примерно так: Создаём простой погодный бот для Telegram за несколько вечеров - 1Эти данные предназначены не для людей, а для других программ, поэтому ничего лишнего, кроме самой информации в таких pageх нет. Сырые данные чаще всего пересылают по одному из двух стандартов: JSON or XML. У каждого свои плюсы и минусы, однако, важно разбираться в обоих. JSON вы уже видели на скрине выше, а ХМL выглядит вот так: Создаём простой погодный бот для Telegram за несколько вечеров - 2После недолгого поиска, был найден англоязычный проект Open Weather Map, который отдаёт данные бесплатно, если не делать больше 50 requestов в minutesу. Для нас этого вполне достаточно, регистрируемся, получаем уникальный токен(code) по которому server будет знать, что мы не самозванцы, а прorчные будущие разработчики. Заходим на page с API-documentацией (тыц), и выясняем, что прогноз на 5 дней по любому городу можно получить, если отправить request вида.
https://api.openweathermap.org/data/2.5/forecast?q=(город)&APPID=(уникальный токен, полученный при регистрации)
Можно посмотреть How ответ на такой request выглядит в браузере тыц Мы уже выяснor, что, по сути, нужно просто перейти по правильной ссылке и server выдаст нужные данные. Осталось научиться это делать средствами Java. Простой GET request на Java выглядит так:
//создаём строку со ссылкой на нужную page,
//я тут её склеиваю из заранее определённых констант, меняя только сам город
String urlString = API_CALL_TEMPLATE + city + API_KEY_TEMPLATE;
//создаём an object который будет содержать ссылку
URL urlObject = new URL(urlString);
//создаём соединение, используя an object
HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
//выбираем тип requestа (GET)
connection.setRequestMethod("GET");
//тут мы указываем, данные о себе, что мы можем принять всё то,
//что примет и любой современный браузер
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
//В начало ответа server всегда вставляет число, по которому можно судить, прошло ли всё хорошо.
//200 - значит OK
int responseCode = connection.getResponseCode();
//на несуществующий город or город с опечаткой, server выдаст code ответа 404,
//бросаем на него исключение, чтобы обработать на уровне повыше и предложить
//пользователю ввести город заново
if (responseCode == 404) {
     throw new IllegalArgumentException();
}
// создаём поток, вычитываем все строки, и склеиваем в одну большую строку,
//которую будем потом обрабатывать в других методах
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
     response.append(inputLine);
}
in.close();
return response.toString();
Если request был корректным, а server - доступным, мы получим простыню данных, в которой полезная информация перемешана с той, которая сейчас не нужна. Whatбы удобно извлекать из JSON и XML нужные данные, под Java написано тонны библиотек на любой вкус. Так How я предпочёл JSON, для его обработки выбрал весьма популярную библиотеку под названием Jackson. Она, кстати немного изучается на JavaRush на Howих-то высоких уровнях. Для обработки больших объёмов JSON-данных важно понимать структуру documentа. На помощь приходят полезные сайты вроде этого . Слева у нас оригинальный JSON, справа - структурированный: Создаём простой погодный бот для Telegram за несколько вечеров - 3 Видно что ответ состоит из 5 JSON-an objectов высшего уровня, 2 из которых сложные и являются узлами для следующих ветвей. Интересующие нас данные хранятся в узле list. Внутри list - массив из 38 JSON-строк, в каждой описана погода в определённое время. То есть это такая себе древовидная структура, где есть корень, ветви, веточки и даже листья :) А на узлах How раз и проходит разветвление. К счастью, Jackson умеет представлять любой валидный JSON в виде дерева. Таким образом, зная How называется нужный нам атрибут(например, температура воздуха), и на Howом уровне дерева он находится, достать его не составит особых проблем. Для начала я извлёк все строчки из массива "list" и добавил их в отдельный список. Я, грубо говоря, порезал простыню с данными на куски, каждый из которых - это отдельный прогноз. Маленькие части проще держать в голове и оперировать ими.
//JsonNode - это один из узлов в древовидной иерархии, от которого идут ветви
//получаем узел, который называется "list"
JsonNode arrNode = new ObjectMapper().readTree(data).get("list");
//если это действительно массив узлов
if (arrNode.isArray()) {
//выполняем для каждого узла, который содержится в массиве
      for (final JsonNode objNode : arrNode) {
//в атрибуте "dt_txt" каждого маленького узла хранилось время прогноза, я отобрал данные за 9 утра и 6 вечера
                String forecastTime = objNode.get("dt_txt").toString();
                if (forecastTime.contains("09:00") || forecastTime.contains("18:00")) {
                weatherList.add(objNode.toString());
            }
      }
}
Так мы получor список строк, в котором каждая строка представляет собой JSON-сводку погоды в определённое время. Осталось извлечь желаемое и отформатировать. Если у нас есть такая строка:
"main":{"temp":261.45,"temp_min":259.086,"temp_max":261.45,"pressure":1023.48,"sea_level":1045.39,"grnd_level":1023.48,"humidity":79,"temp_kf":2.37}
то, это узел под названием "main". Whatбы получить из него любые данные, к примеру уровень моря, достаточно такого codeа:
ObjectMapper objectMapper = new ObjectMapper();
//line - это наша JSON-строка
mainNode = objectMapper.readTree(line).get("main");
String seaLevel = mainNode.get("sea_level");
Jackson позволяет сразу представлять данные в числовом формате:
double seaLevel = mainNode.get("sea_level").asDouble();
Теперь мы можем извлекать любые данные из прогноза, и осталось только их склеить, How пожелается, и отправить пользователю в Telegram. Полный исходный code у меня на гитхабе, а вот попробовать бота в действии можно по ссылке, либо найдя @denifoBot в поиске Телеграмм. Название города нужно писать в латинской транслитерации, например "Kyiv" or "Moscow". Спасибо, если осorли до конца, принимаю разумную критику, так How только учусь и нарабатываю простенькие проекты на гитхаб, чтобы конкурировать с голодными талантами из своего города :) Всем пока! P.S Полагаю, что тут могут быть опечатки, поэтому можете всё присылать в личку, ну, or в комментарии, если вы прям очень злые :)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION