Задача
Найти сервис, который отдавал бы данные погоды с прогнозом не менее 10 дней с русской локализацией, средними величинами, временами суток и дополнительными параметрами по заданному городу.
Поиски решения
Опробовав разные сервисы отдающие данные погоды, я остановился на Яндекс.Погода, все условия задачи совпадали.
Так как мне нужны были данные по одному городу, первое, что я сделал, это нашел идентификатор (id) города в списке, предоставленном здесь и подставил его в export.yandex.ru/weather-ng/forecasts/<id города>.xml. В итоге я получил xml-файл с данными по погоде выбранного мной города.
Разбор изображений
На втором этапе нужно было получить собственные изображения состояния погоды. В xml-файле этот параметр обозначен как image-v3. Чтобы получить весь список изображений, а так же описание для каждого состояния я набросал небольшой кустарный скрипт, который парсит города из доступного списка и собирает все в два массива на вывод.
// парсер изображений и описания состояний $col = 1; // кол-во дней (до 10, увеличивается время выдачи) $data_file = 'http://weather.yandex.ru/static/cities.xml'; $xml = simplexml_load_file($data_file); foreach ($xml->country as $key => $value) { foreach ($value->city as $key1 => $value1): $out = getWeather($value1["id"], $col); foreach ($out as $day): foreach ($day['weather'] as $weather): $types[(string)$weather['weather_type']] = (string)$weather['image']; // массив описаний состояния с изображением $images[(string)$weather['image']] = (string)$weather['weather_type']; // массив изображений с описанием состояния endforeach; endforeach; endforeach; } foreach($types as $type=>$img): ?><img src="http://yandex.st/weather/1.2.61/i/icons/48x48/<?php echo $img;?>.png" width="48" height="48" /> - <?php echo $type.'<br />'; endforeach; echo '<br><hr><br>'; foreach($images as $img=>$type): ?><img src="http://yandex.st/weather/1.2.61/i/icons/48x48/<?php echo $img;?>.png" width="48" height="48" /> - <?php echo $type.'<br />'; endforeach; /* заполняем массив при помощи функции, первый параметр идентификатор города, другие параметры необязательны - в этом случае используется значения по умолчанию */ function getWeather($city, $col = 10) { $data_file = 'http://export.yandex.ru/weather-ng/forecasts/'.$city.'.xml'; // загружаем файл прогноза погоды для выбранного города $xml = simplexml_load_file($data_file); // загружаем xml файл через simple_xml $out = array(); // массив вывода прогноза $counter = 0 ; // счетчик количества дней, для которых доступен прогноз if($xml->day): foreach($xml->day as $day): if($counter == $col) break; for ($i=0;$i<=3;$i++) { $out[$counter]['weather'][$i]['image'] = $day->day_part[$i]->{'image-v3'}; $out[$counter]['weather'][$i]['weather_type'] = $day->day_part[$i]->weather_type; } $counter++ ; endforeach; endif; return $out ; }
На выходе получаем два массива данных, первый выводит весь список с описанием состояний и картинкой, второй выводит картинки с одним из видов описания состояния. Хочу заметить, что для одного изображения могут использоваться разные типы описаний состояния погоды. Параметр $col в скрипте, указывает на количество дней, который нужно обработать, максимум 10, по умолчанию 1, для уменьшения времени выдачи.
Примечание: скрипт работает довольно долго (особенно на локалхосте), т.к. городов много, поэтому желательно увеличить время выполнения php-скриптов (max_execution_time, max_input_time), а так же максимальный объем памяти скрипта (memory_limit).
bkn_-ra_d — облачно с прояснениями, небольшой дождь (день)
bkn_-ra_n — облачно с прояснениями, небольшой дождь (ночь)
bkn_-sn_d — облачно с прояснениями, небольшой снег (день)
bkn_-sn_n — облачно с прояснениями, небольшой снег (ночь)
bkn_d — переменная облачность (день)
bkn_n — переменная облачность (ночь)
bkn_ra_d — переменная облачность, дождь (день)
bkn_ra_n — переменная облачность, дождь (ночь)
bkn_sn_d — переменная облачность, снег (день)
bkn_sn_n — переменная облачность, снег (ночь)
bl — метель
fg_d — туман
ovc — облачно
ovc_-ra — облачно, временами дождь
ovc_-sn — облачно, временами снег
ovc_ra — облачно, дождь
ovc_sn — облачно, снег
ovc_ts_ra — облачно, дождь, гроза
skc_d — ясно (день)
skc_n — ясно (ночь)
Есть еще дополнительные иконки, но я не нашел где они используются, единственное отличие, это интенсивность осадков.
bkn_+ra_d, bkn_+ra_n, bkn_+sn_d, bkn_+sn_n, ovc_+ra, ovc_+sn
Реализация задачи
После того, как я нашел все изображения, мне оставалось только запрашивать xml-файл с параметрами города и нарисовать выдачу. На сервере я настроил данный скрипт по крону, раз в полчаса, дабы не грузить лишний раз Яндекс:
$city_id = 27612; // id Москвы $url = 'http://export.yandex.ru/weather-ng/forecasts/'.$city_id.'.xml'; $userAgent = 'Googlebot/2.1 (+http://www.google.com/bot.html)'; $xml = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'weather_'.$city_id.'.xml'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, $userAgent); $output = curl_exec($ch); $fh = fopen($xml, 'w'); fwrite($fh, $output); fclose($fh);
Конечно, можно использовать кэширование в скрипте и сохранять в сериализованном виде (как в предыдущем посте), кому как удобней, но я остановился на своём велосипеде.
Далее мне осталось только загружать полученный xml-файл и стилизовать выдачу. Дабы не усложнять и не писать километровые классы, я скомпоную все в один файл.
$city_id = 27612; // id Москвы $xml = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'weather_'.$city_id.'.xml'; if(file_exists($xml)): $data = simplexml_load_file($xml); //грузим ?> <style type="text/css"> .weather{position:relative;border-bottom:1px solid #d5d5d5;padding-bottom:35px;} .weather .date{font-size:13px;font-weight:700;padding-bottom:5px;text-transform:uppercase;border-bottom:1px solid #d5d5d5;margin-top:10px;} .weather .item{background-color:#f0eedc;padding:15px;font-family:Georgia;margin-bottom:20px;} .weather .item table{border:0;width:100%;} .weather .item table td{padding-bottom:15px;width:20%;vertical-align:baseline;padding-right:5px;} .weather .item .day-part td{font-size:18px;} .weather .item .day-temp td{font-size:30px;} .weather .item .day-temp td img{margin-left:5px;} .weather .item .day-param td{font-size:12px;} .weather .item .day-param td p{padding-bottom:3px;} .weather .days{margin-top:35px;border:0;width:100%;} .weather .days td{width:50%;padding-bottom:35px;} .weather .days a{font-family:Georgia;font-size:18px;text-decoration:underline;font-weight:700;} </style> <div class="weather"><?php foreach($data->day as $day):?> <div class="date"><?php echo getDayDate($day['date']);?></div> <div class="item"> <table> <tr class="day-part"> <td>Утром</td> <td>Днем</td> <td>Вечером</td> <td>Ночью</td> </tr> <tr class="day-temp"> <?php for($i = 0;$i < 4;$i++): // т.к. нам не нужны данные day_short и night_short, мы останавливаем проход на 4?> <td><?php echo getTempSign($day->day_part[$i]->{'temperature-data'}->avg);?> °C <img src="" width="48" height="48" /></td><?php endfor;?> </tr> <tr class="day-param"> <?php for($i = 0;$i < 4;$i++): // т.к. нам не нужны данные day_short и night_short, мы останавливаем проход на 4?> <td> <p><strong><?php echo $day->day_part[$i]->weather_type;?></strong></p> <p>ветер: <?php echo getWindDirection($day->day_part[$i]->wind_direction).' '.$day->day_part[$i]->wind_speed;?> м/с</p> <p>влажность: <?php echo $day->day_part[$i]->humidity;?>%</p> <p>давление: <?php echo $day->day_part[$i]->pressure;?> мм рт. ст.</p> </td> <?php endfor;?> </tr> </table> </div><?php endforeach;?> </div><?php endif; // получаем локализованную дату function getDayDate($date) { $date = strtotime($date); $months = array('','января','февраля','марта','апреля','мая','июня','июля','августа','сентября','октября','ноября','декабря'); $days = array('воскресенье','понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'); return $days[date('w', $date)].', '.(int)date('d',$date).' '.$months[date('n', $date)]; } // получаем знак температуры function getTempSign($temp) { $temp = (int)$temp; return $temp > 0 ? '+'.$temp : $temp; } // получаем направления ветра function getWindDirection($wind) { $wind = (string)$wind; $wind_direction = array('s'=>'↑ ю','n'=>'↓ с','w'=>'→ з','e'=>'← в','sw'=>'↗ юз','se'=>'↖ юв','nw'=>'↘ сз','ne'=>'↙ св'); return $wind_direction[$wind]; }
Скрипт выводит 10 дней по временам суток, направление ветра стрелками, как в Яндекс.Погода, так же берет усредненные значения температуры $day->day_part[$i]->{‘temperature-data’}->avg, что дает нам одну цифру вместо двух.
Заключение
С поставленной задачей справились. В статье я хотел немного расширить представление информации сервисом Яндекс.Погода, расписывать все параметры не стал, их полный список можно посмотреть в xml-файле выдачи.
ссылка на оригинал статьи http://habrahabr.ru/post/233243/
Добавить комментарий