И снова Яндекс.Погода для сайта: время суток, направление ветра и прочие параметры

от автора

В продолжении поста о погоде «Яндекс.Погода для сайта в деталях». Прочитав данный пост, я пришел к выводу, что тема еще актуальна, и хотел бы дополнить выше упомянутую статью своими наработками.

Задача

Найти сервис, который отдавал бы данные погоды с прогнозом не менее 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *