Pogoda na stronie www

23 czerwca 2010

Skryptów PHP do pobierania informacji o pogodzie widziałem kilka. Większość to straszne kobyły, część nie działa, inna część działa błędnie lub mało wydajnie. Znowu przyszło mi pisać coś swojego...

Z pogodą na stronie jest jeden podstawowy problem: trzeba skądś pobrać dane. Są trzy wyjścia:

  • Wstawić na stronę gotową "wklejkę", która jest odpowiedzialna za wyświetlenie pogody (i przy okazji linka do źródła, logo innego serwisu itp.).
  • Parsować jakąś stronę www i "na chama" wyciągać z niej informacje o pogodzie (np. z pogoda.onet.pl).
  • Parsować ogólnodostępne źródło, najczęściej jakiś RSS

Pierwszym sposobem zajmować się nie będziemy wcale. Po to piszemy własny skrypt żeby wyświetlić pogodę dokładnie tak jak chcemy, bez zbędnych linków, obrazków itd. a nie tak jak ktoś nam nakaże.

Drugi sposób ma swoje zalety i wady.
Nasze rodzime serwisy informacyjne mają bogatą bazę polskich miejscowości. Każdy znajdzie tam swoją miejscowość lub inną, bardzo blisko położoną swojej. Dodatkowo najczęściej udostępniają bardzo wiele informacji pogodowych.
Przejdźmy do wad. Po pierwsze, nasze (znaczy polskie) serwisy nie udostępniają informacji o pogodzie w jakimś otwartym standardzie np. RSS. Musimy na własną rękę parsować wybraną witrynę. Gdy na stronie coś się zmieni to w najlepszym przypadku nasza pogoda nagle przestanie działać. W najgorszym, zaczną się u nas wyświetlać jakieś bzdury co w skrajnym przypadku rozwali nam cały serwis...
Druga wada jest powiązana z pierwszą. Skoro musimy parsować stronę to zwyczajnie kradniemy dane. I nie pomoże nawet informacja u nas na stronie skąd pobieramy pogodę. Jeżeli ktoś nie udostępnił RSS, XML czy innego ustrojstwa to znaczy, że nie chce nam czegoś dać, koniec kropka.

I nareszcie przechodzimy do trzeciego sposobu. Zagraniczne serwisy o pogodzie są bardziej liberalne od polskich i najczęściej każde miasto ma swój kanał RSS, który możemy spokojnie pobierać. Mamy dużo większą pewność, że nie będziemy musieli raz na kilka miesięcy zmieniać swoich skryptów w skutek zmian w strukturze pliku nad którym pracujemy. Nie obejdzie się jednak bez wad. Baza miejscowości jest przeważnie dużo skromniejsza niż byśmy tego oczekiwali. Jednak na własnym przykładzie przetestowałem, że nie jest to aż taki duży problem. Dla Tomaszowa Mazowieckiego na jednej ze stron wyświetlam pogodę z kanału Łodzi (jakieś 45km odległości licząc od środka jednego miasta do środka drugiego) i zawsze jest wyjątkowo aktualna :)
Udostępniono tylko kilka podstawowych informacji o pogodzie ale tu również praktyka pokazuje, że to jest wystarczające. Pamiętaj, że pogoda na Twojej stronie to tylko dodatek a nie główny element. Jeżeli jest inaczej to musisz podpisać umowę z odpowiednimi instytucjami o udostępnienie danych pogodowych a nie myśleć o pobieraniu tego wszystkiego od innych...

Przejdźmy do konkretów. Rok temu stanąłem przed problemem wyświetlania pogody na stronie www. Dzisiaj udostępniam skrypt :) Zdecydowałem się skorzystać z serwisu weather.yahoo.com i po dziś dzień nie miałem okazji pożałować tego wyboru. Poniżej zamieszczam prostą klasę PHP5 z której korzystam:

PHP:
  1. <?php
  2.  
  3. class yahoo_weather {
  4.  
  5.   public $city_code;
  6.   protected $weather;
  7.  
  8.   public function __construct($city_code) {
  9.     $this->city_code = $city_code;
  10.   }
  11.  
  12.   public function get($get_channel = NULL) {
  13.  
  14.     if(empty($this->weather)) {
  15.  
  16.       try {
  17.         $xml = @new SimpleXMLElement('http://weather.yahooapis.com/forecastrss?w='. $this->city_code .'&u=c', NULL, TRUE);
  18.       } catch (Exception $e) {
  19.         return FALSE;
  20.       }
  21.  
  22.       $xml->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
  23.  
  24.       $wind       = $xml->xpath('//channel/yweather:wind');
  25.       $atmosphere = $xml->xpath('//channel/yweather:atmosphere');
  26.       $astronomy  = $xml->xpath('//channel/yweather:astronomy');
  27.       $condition  = $xml->xpath('//channel/item/yweather:condition');
  28.       $forecast   = $xml->xpath('//channel/item/yweather:forecast');
  29.  
  30.       $this->weather = array(
  31.         'wind'       => array(
  32.           'chill'      => "{$wind[0]['chill']}",
  33.           'direction'  => "{$wind[0]['direction']}",
  34.           'speed'      => "{$wind[0]['speed']}",
  35.           ),
  36.         'atmosphere' => array(
  37.           'humidity'   => "{$atmosphere[0]['humidity']}",
  38.           'visibility' => "{$atmosphere[0]['visibility']}",
  39.           'pressure'   => "{$atmosphere[0]['pressure']}",
  40.           'rising'     => "{$atmosphere[0]['rising']}",
  41.         ),
  42.         'astronomy'  => array(
  43.           'sunrise'    => "{$astronomy[0]['sunrise']}",
  44.           'sunset'     => "{$astronomy[0]['sunset']}",
  45.         ),
  46.         'condition'  => array(
  47.           'text'       => "{$condition[0]['text']}",
  48.           'code'       => "{$condition[0]['code']}",
  49.           'temp'       => "{$condition[0]['temp']}",
  50.           'date'       => "{$condition[0]['date']}",
  51.         ),
  52.         'forecast'   => array(
  53.           'today'      => array(
  54.             'day'        => "{$forecast[0]['day']}",
  55.             'date'       => "{$forecast[0]['date']}",
  56.             'low'        => "{$forecast[0]['low']}",
  57.             'high'       => "{$forecast[0]['high']}",
  58.             'text'       => "{$forecast[0]['text']}",
  59.             'code'       => "{$forecast[0]['code']}",
  60.           ),
  61.           'tomorrow'   => array(
  62.             'day'        => "{$forecast[1]['day']}",
  63.             'date'       => "{$forecast[1]['date']}",
  64.             'low'        => "{$forecast[1]['low']}",
  65.             'high'       => "{$forecast[1]['high']}",
  66.             'text'       => "{$forecast[1]['text']}",
  67.             'code'       => "{$forecast[1]['code']}",
  68.           )
  69.         )
  70.       );
  71.  
  72.       $xml = NULL;
  73.     }
  74.  
  75.     if($get_channel == NULL) {
  76.       return $this->weather;
  77.     }
  78.     else {
  79.       return $this->weather[$get_channel];
  80.     }
  81.   }
  82. }

Użycie skryptu wygląda następująco (pobieramy kanał http://weather.yahooapis.com/forecastrss?w=505120&u=c):

PHP:
  1. $yahoo_weather = new yahoo_weather('505120');
  2. $weather = $yahoo_weather->get();

I od teraz w zmiennej $weather mamy piękną tablicę ze wszystkimi informacjami o pogodzie. Dodatkowo możemy dokonać pewnych przekształceń (według własnych upodobań):

PHP:
  1. $weather['wind']['speed'] = round($weather['wind']['speed'], 1);
  2.  
  3. $weather['astronomy']['sunrise'] = substr($weather['astronomy']['sunrise'], 0, -3);
  4.  
  5. $sunset = explode(':', substr($weather['astronomy']['sunset'], 0, -3));
  6. $sunset[0] += 12;
  7.  
  8. $weather['astronomy']['sunset'] = $sunset[0] .':'. $sunset[1];

Specjalny kod miejscowości, który przekazujemy do klasy musimy znaleźć sami. Wchodzimy na weather.yahoo.com, odszukujemy miasto, które nam najbardziej odpowiada i klikamy w prawym górnym roku na pomarańczową ikonkę RSS. W adresie na jaki zostaniemy przekierowani w parametrze "p" odnajdziemy interesujący nas kod. Właśnie wyczytałem w dokumentacji, że w adresie RSS zamiast parametru "p" (który został uznany za przestarzały) należy używać parametru "w" podając tzw. kod WOEID. Problem w tym, że gdy odnajdzie się stronę z pogodą dla wybranej miejscowości to sami linkują ikonkę RSS pod adres z parametrem "p". Kod, którego potrzebujemy jest w adresie strony z pogodą dla miasta. Dla Łodzi adres to http://weather.yahoo.com/poland/lodz/%EF%BF%BD%EF%BF%BDd%EF%BF%BD-505120/ z czego interesują nas ostatnie cyferki czyli 505120. Oto nasz kod (wcześniej PLXX0014). Poprawiłem klasę, jest już przygotowana do nowego standardu.

Klasa jest prosta i nie będę jej omawiał :) Na jej podstawie można napisać parser pogody z innego serwisu niż weather.yahoo.com lub np. nauczyć się jak pobierać i parsować dokumenty RSS, Atom, XML itp.

Skąd wziąć ikony pogody? Ten problem powtarza się bardzo często, ładne ikony to nieodzowny element prognozy pogody na każdej stronie www. Tu nie pomogą nam nawet zagraniczne serwisy. Nie chcą udostępniać swoich ikon bo to dla nich dodatkowy ruch na łączach i serwerach. A jak chcą to są dodatkowe obostrzenia, konieczność wyświetlania ich logo itp. Z tego powodu moja klasa nie wyciąga adresu do ikony aktualnej pogody mimo, że taki jest podawany (chociaż nie tak otwarcie jak reszta danych). Na szczęście w internecie jest sporo ikon, często darmowych (przynajmniej dla zastosowań niekomercyjnych), którymi możemy na swojej stronie zobrazować pogodę. Tu pojawia się zaleta wyboru weather.yahoo.com. Ich RSS udostępnia kod warunków pogody np. w chwili gdy to piszę jest częściowe zachmurzenie w nocy czemu powinna odpowiadać ikona księżyca za lekkimi chmurkami i takim warunkom przypisano kod 33. Wiele gotowych pakietów ikon uwzględnia te kody przez co sami już nie musimy sprawdzać wszystkich kodów i samemu ich przypisywać do odpowiednich ikon. Wystarczy wyświetlić ikonę 33.png :)

Nie możesz znaleźć ikon dla siebie? Moim faworytem są te ikony. Są już przystosowane do kodów z weather.yahoo.com. Co więcej, ich autorem jest nasz rodak ;) Ikony są darmowe do zastosowań niekomercyjnych a za wykorzystanie w komercyjnym projekcie trzeba zapłacić 200zł (tak było rok temu, teraz nie wiem). Warte tych pieniędzy.

W ekstremalnej sytuacji można ściągnąć ikony weather.yahoo.com na własny serwer. Chyba się nie pogniewają... :)

Na koniec pamiętaj aby wynik powyższej klasy zapisywać jakoś do cache (np. korzystając z dobrodziejstw crona). Niedopuszczalne jest pobieranie informacji o pogodzie za każdym razem gdy musimy je wyświetlić u siebie na stronie. To spowodowałoby bardzo duży wzrost transferu, niepotrzebne obciążenie maszyny i opóźnienie w wyświetlaniu się naszej witryny. Osobiście ściągam pogodę raz na godzinę.

PS
Zachęcam do zapoznania się z dokumentacją RSS, którą można znaleźć pod tym adresem developer.yahoo.com/weather.

PS 2
A może jednak jakiś polski serwis udostępnia w prostej postaci i za darmo informacje o pogodzie? Poproszę o linki w komentarzach :)

Dodaj komentarz

20 odpowiedzi dla tego wpisu

  1. SpeX napisał:

    Wygląda iż pogodynka na podstawie pisemnej zgody udostępnia pogodę. Ale nie wiem jak wygląda pozyskanie takiej zgody.

  2. MariuszT napisał:

    Oni udostępniają tzw. widget z ich logo itd. i raczej tylko na coś takiego może liczyć zwykły Kowalski :)

  3. info napisał:

    Wojewódzkie sanepidy mają swoje stacje meteo. Ja na swoją stronę dostaję dane właśnie od nich. Zapytałem, zgodzili się (z podaniem źródła).

  4. Kamil napisał:

    Wp udostępnia RSS z pogodą ;> http://rss.wp.pl/s,pogoda,inde.....;_ticrsn=3

    Nie chciało mi się czytać regulaminu i nie wiem jak z wykorzystaniem tych informacji.

  5. MariuszT napisał:

    Faktycznie, nie wiedziałem o tym. Może przeoczyłem a może jak kiedyś sprawdzałem to jeszcze nie było. I RSS można wyciągnąć dla każdego miasta, nie tylko dla tych kilkunastu na liście. Trzeba tylko podmienić ID miasta.

    I wszystko byłoby pięknie gdyby nie jeden problem. RSS udostępnia dane tylko w postaci kodu HTML, nie ma żadnych danych w XML. A więc i tak trzeba parsować samemu. Jedyna pociecha, że mniejszy plik i mniejsza szansa na pomyłkę. Ale to jednak nadal nie to na czym webmasterom zależy najbardziej…

    PS
    Kamil, prowadzisz fajnego bloga :) Poczytam sobie trochę.

  6. Kamil napisał:

    Dziękuję Mariusz za miłe słowo :)

    Co do samej pogody dorzucę jeszcze jeden link, który może okazać się przydatny:
    http://www.programmableweb.com.....at=Weather

    Kilka alternatywnych usług sieciowych dla wspomnianego Yahoo Weather :-)

  7. SpeX napisał:

    A jak z poprawnością tych pogód? W szczególności tych zachodnich?

  8. MariuszT napisał:

    Od roku zerkam na wyniki dla Tomaszowa Maz. (dane pobierane dla Łodzi) i najczęściej zgadza się to z tym co mam za oknem. Nie wiem jak jest z innymi miastami czy krajami.

  9. Michał napisał:

    Nagnę trochę i przy okazji spytam się czy używasz GZIP. Zastanawiam się czy się opłaca implementować to w moim cms, bo z transferem krucho :)

    Pozdrawiam

  10. MariuszT napisał:

    Używam. Implementacja to chwila a przynosi zyski.

  11. Zaciekawiony napisał:

    A skąd taka pewnośc ze jak ktoś udostępnia RSS’y to zezwala na ich obróbkę i wykorzystanie!!?? To wzbudza kontrowersjie prawne w naszym karaju.

  12. MariuszT napisał:

    Nie zezwala. To chyba oczywiste. Pisząc o RSS skupiłem się na łatwości pobierania i obróbki takich danych bo artykuł miał być przede wszystkim o technicznych aspektach problemu. Natomiast sprawa zezwoleń, licencji itp. to osobny temat. Mam nadzieję, że każdy ma dość rozumu i wie, że trzeba mieć jakieś pozwolenie/zgodę na wykorzystanie czegokolwiek co jest w internecie.

  13. Fixer napisał:

    Polecam gotowy skrypt PP2XML
    http://pp2xml.ogloszenia.devtown.net/

  14. KaRo napisał:

    Czy byłbyś zainteresowany pomocą w opracowaniu pasującego do mojej strony serwisu pogodowego?
    Mieszkam całkiem blisko ” . Kod, którego potrzebujemy jest w adresie strony z pogodą dla Łodzi ”
    Niestety jestem totalnym laikiem informatycznym,ratuje mnie prosty sposób wstawienia kodu na stronę. Więc jak?
    Pozdrawiam serdecznie

  15. MariuszT napisał:

    Ale tu nie ma co opracowywać :) Masz podany gotowy kod PHP, wystarczy na weather.yahoo.com znaleźć swoje miasto, skopiować jego kod z adresu i wstawić wszystko do siebie.

  16. KaRo napisał:

    Hej wstawic do siebie mówisz?????
    Ale gdzie ? Do skryptu?
    Do jakiego katalogu miałabym to wstawić?
    Wszystko to dla mnie tabularaza ,nie będę umiała tego zrobić…
    No nic dzięki

  17. MariuszT napisał:

    Przykro mi, ten artykuł jest przeznaczony dla programistów.

  18. kolo napisał:

    szkoda tylko , że jest tak mało miast i lokalizacji na Yahoo Weather, nie ma Łowicza…

  19. kolo napisał:

    jaki parametr odpowiada za dodatkowy opis do ciśnienia:
    „1,015.92 mb [and steady]” ?

  20. MariuszT napisał:

    Kolo, niestety, miast jest niewiele.

    Ciśnienie jest w $weather['astronomy']['pressure'].

Odpowiedz



Podobne wpisy: