?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄 첨부
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄 첨부
Extra Form
라이선스 MIT

안녕하세요?


기상청 중기예보 RSS를 파싱하여 캐러셀 형태로 보여주는 위젯을 만들어보았습니다.


제가 실력이 형편없는 초보자이지만 이렇게 소스를 계속 작성해보고 올리는 이유는 


여기 스포어에 계신 개발자 분들께 여쭤보면서 한 수 배우려는 것이 주된 목적이고,


부수적으로는 제가 올린 스크립트를 제 스스로 보면서 더 분발해서 열심히 공부하려는 취지도 있습니다.


일단 허접한 위젯의 외형은 다음과 같습니다.



캐러설로 보여주는 부분은 Owl Carousel을 사용했습니다.


움짤을 보면 자동 스크롤이 되는 것으로 오해하실 수도 있으나 


그 기능은 활성화하지 않았고 버튼을 클릭해야 스크롤이 되도록 만들었습니다.



일단 아미나를 기준으로 만들었지만 그누보드와는 별개로 작동하고


JQuery를 로드하는 한 줄을 추가하면 독립적으로 실행할 수도 있습니다.

(이건 의도한 것이 아니라 제가 실력이 부족해서 아미나에서 위젯을 설정하는 php 파일을 만들지 못했습니다 ㅠㅠ)



데이터는 기상청 홈페이지의 중기예보 RSS를 이용했습니다. 


아웃도어 활동을 즐기는 분들에게는 오늘의 날씨만큼이나 중기예보가 중요한데요.


아미나에서 작동하는 중기예보 위젯을 찾지 못해서 제가 만들어봤습니다 ㅠㅠ



설명이 길었는데 스크립트는 다음과 같습니다.


Owl Carousel 관련 파일을 건드리지 않기 위해서 이 스크립트에 CSS 스크립트까지 집어넣었습니다 -_-;



<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
?>

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
      <link rel="stylesheet" href="/css/owl.carousel.min.css">
      <link rel="stylesheet" href="/css/owl.theme.default.min.css">
      <script src="/owl.carousel.min.js"></script>
  </head>
</html>


<?php
  header('Content-Type: text/html; charset=utf-8');
  $url = "http://www.weather.go.kr/weather/forecast/mid-term-rss3.jsp?stnId=109";
  // Id - 강원: 105, 충북: 131, 충남: 133, 전북: 146, 전남: 156, 경북:143, 경남: 159, 제주: 184
  $ch = cURL_init();
 
  cURL_setopt($ch, CURLOPT_URL, $url);
  cURL_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 
  $response = cURL_exec($ch);
  cURL_close($ch);

  $rss = simplexml_load_string($response);
 
  $rss_time = $rss->channel->item->title; // 발표시간 출력
  $rss_time = explode('-', $rss_time);
  echo "<strong>", $rss_time[1], "</strong><br />";
 
  $rss_comment = $rss->channel->item->description->header->wf; // 코멘트 출력
  echo $rss_comment, "<br /><br />";
?>


<!-- owl-carousel의 색상을 변경-->
<style>
.owl-theme .owl-controls .owl-page.active span {
    border: 2px solid gray;
}

.owl-theme .owl-controls .owl-page span {
    border: 2px solid gray;
}
</style>

<!--owl-carousel의 옵션 변경-->
<script type="text/javascript">
//<![CDATA[
$(document).ready(function(){
  $('.owl-carousel').owlCarousel({
    loop:true,
    autoWidth:true,
    items:3,
    margin:10,
    navigation:true,
    navigationText : ['<', '>'],
})
});
//]]>
</script>

<!-- carousel에 들어갈 태그-->
<!-- 기상청 RSS가 5일 간은 오전 오후로, 나머지 3일은 오전 오후 구분 없이 예보합니다-->
<div class="owl-carousel owl-theme">
  <div class="item" style="width:200px">
    <?php
        $n=0;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf;
        $when = explode(' ', $when);
        $when = $when[0]; // 날짜만 변수에 넣음
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        echo "AM: ";
        skystatus($n, $rss);
        echo "<br />PM: ";
        skystatus($n+1, $rss);
        echo "<br />";

        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br />";
    ?>
  </div>
  <div class="item" style="width:200px">
    <?php
        $n=2;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf;
        $when = explode(' ', $when);
        $when = $when[0]; // 날짜만 변수에 넣음
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        echo "AM: ";
        skystatus($n, $rss);
        echo "<br />PM: ";
        skystatus($n+1, $rss);
        echo "<br />";
           
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br />";
    ?>
  </div>
  <div class="item" style="width:200px">
    <?php
        $n=4;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf;
        $when = explode(' ', $when);
        $when = $when[0];  // 날짜만 변수에 넣음
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        echo "AM: ";
        skystatus($n, $rss);
        echo "<br />PM: ";
        skystatus($n+1, $rss);
        echo "<br />";
           
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br />";
    ?>
  </div>
  <div class="item" style="width:200px">
    <?php
        $n=6;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf;
        $when = explode(' ', $when);
        $when = $when[0];  // 날짜만 변수에 넣음
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        echo "AM: ";
        skystatus($n, $rss);
        echo "<br />PM: ";
        skystatus($n+1, $rss);
        echo "<br />";
           
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br />";
    ?>
  </div>
  <div class="item" style="width:200px">
    <?php
        $n=8;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf;
        $when = explode(' ', $when);
        $when = $when[0]; // 날짜만 변수에 넣음
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        echo "AM: ";
        skystatus($n, $rss);
        echo "<br />PM: ";
        skystatus($n+1, $rss);
        echo "<br />";
           
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br />";
    ?>
  </div>
  <div class="item" style="width:200px">
    <?php
      $n=10;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf; // 날짜 출력
        $when = explode(' ', $when);
        $when = $when[0];  // 날짜만 변수에 넣음
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        skystatus($n, $rss);
        echo "<br />";
 
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br /><br />";
    ?>
  </div>
  <div class="item" style="width:200px">
    <?php
      $n=11;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf; // 날짜 출력
        $when = explode(' ', $when);
        $when = $when[0];
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        skystatus($n, $rss);
        echo "<br />";
 
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br /><br />";
    ?>
  </div>  
  <div class="item" style="width:200px">
    <?php
      $n=12;
        $when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf; // 날짜 출력
        $when = explode(' ', $when);
        $when = $when[0];
        echo "<strong><font color = 'blue'>", $when, "</font></strong><br />";
        skystatus($n, $rss);
        echo "<br />";
 
        $tmn = $rss->channel->item->description->body->location[0]->data[$n]->tmn; // 온도 출력
        $tmx = $rss->channel->item->description->body->location[0]->data[$n]->tmx;
        echo $tmn, " ~ ", $tmx, "C <br /><br />";
    ?>
  </div>
</div>


<?php
function skystatus($n, $rss) // 구름량에 관한 함수 선언
{
  $sky = $rss->channel->item->description->body->location[0]->data[$n]->wf;
  $sky = iconv("UTF-8", "EUC-KR", $sky);
  if (preg_match('/맑음/', $sky) == 1)
  {
    echo "<img src = 'http://www.weather.go.kr/images/icon/NW/NB01.png'/>";
  }
  elseif (preg_match('/조금/', $sky) == 1)
  {
    echo "<img src = 'http://www.weather.go.kr/images/icon/NW/NB02.png'/>";
  }
  elseif (preg_match('/많음/', $sky) == 1)
  {
    echo "<img src = 'http://www.weather.go.kr/images/icon/NW/NB03.png'/>";
  }
  else
  {
    echo "<img src = 'http://www.weather.go.kr/images/icon/NW/NB04.png'/>";
  }
  $sky = iconv("EUC-KR", "UTF-8", $sky);
  echo $sky;
}
?>

(스크립트를 제대로 긁어서 붙여넣었는데 코드 하이라이터에서 보여줄 때 깨지는 부분이 있네요 ㅜㅜ 부득이 파일로 첨부하였습니다)

widget.php 



제가 이 스크립트를 짜면서 궁금했던 부분이 있어서 좀 여쭤보겠습니다 ㅠㅠ


1. 제가 beautifulsoup에 익숙해져서 그런지 simplexml_load_string으로 


$when = $rss->channel->item->description->body->location[0]->data[$n]->tmEf;


이런 식으로 셀렉터를 길게 나열하는 것이 효율적이지 않다고 느껴지는데요.


더 효율적인 방법이나 더 나은 parser는 없는지 여쭤봅니다. 


차라리 정규식을 바로 사용하는 것이 효율적이었을까요?


아참 simplexml_load_file로 url을 바로 불러오지 않고 cURL로 불러와서 simplexml_load_string로 다시 불러온 것은


제가 사용한 웹호스팅(닷홈 무료) 쪽인지 기상청 쪽인지 모르겠지만 막아놓은 것 같더군요 ㅠㅠ



2. 마지막에 함수 선언해 놓은 부분에서 


$sky = iconv("UTF-8", "EUC-KR", $sky) 로 변수 하나씩 변환하여 정규식으로 비교하고 


다시 $sky = iconv("EUC-KR", "UTF-8", $sky) 로 변환해서 출력해야 


인코딩이 안 깨지고 제대로 비교하고 출력이 되던데요.


원래 이렇게 해야하는 것인지 아니면 제가 인코딩 변환에 대해 잘 몰라서 이런 우회적인 방법을 사용한 것인지 모르겠네요 ㅠㅠ



3. 제가 사용한 무료 웹호스팅 환경에서 Owl Carousel이 매뉴얼대로 완벽하게 작동하지는 않는 것 같구요.


캐러셀의 대상이 되는 div 태그 내에 폰트어썸을 사용하면 캐러셀 전체가 깨지던데요 ㅜㅜ


텍스트를 캐러셀로 더 쉽게 구현할 수 있는 방법이 있을까요?


이미지 파일은 bxslider를 많이 사용하길래 시도해봤는데요. 


이 스크립트처럼 텍스트만 사용하려니 깨져서 보이더군요.



4. <!-- carousel에 들어갈 태그--> 부분을 원래 n이 1씩 증가하는 PHP의 for 문으로 짜보려고 했는데요.


for 문의 내용으로 html인 div 태그가 들어가서 for 문을 사용하지 못하고 


결국 ctrl + c, v 해서 스크립트를 길게 나열하게 되었는데요.


이런 경우에 반복문을 돌릴 수 있는 다른 해결책이 없는지 여쭤봅니다.



여러모로 부족하고 장황한 글을 읽어주신 모든 분께 감사드립니다!


그럼 즐겁고 뜻깊은 9월의 마지막 주말 되시기를 기원합니다 ^^


  • profile
    네모 2018.09.28 20:59
    0.
    5~13 라인에서 이미 html 태그를 닫아버리셨네요. 뭐, 대부분의 브라우저에서 작동은 하니, 일단은 넘어갑시다.

    1.
    jQuery 셀렉터와 비슷한 방식을 사용할 수 있는 라이브러리가 있습니다.
    http://simplehtmldom.sourceforge.net/ 참고하시면 될 것 같습니다.

    2.
    PHP 파일 자체의 인코딩에 문제가 있지 않을까요?
    정규식에 사용된 한글을 저장할 때 EUC-KR로 저장되어, PHP 인터프리터가 해석할 때 인코딩 없이는 오류가 발생하는 것이겠지요.
    UTF-8 형식으로 저장한 뒤 테스트해 보면, iconv 처리 없이도 정상 작동하리라 판단됩니다.

    3.
    그을쎄요... 이 부분은 패스할게요. 둘 다 많이 사용해보지 못해서요.
    다만 호스팅 환경에 따라 차이가 나는건 아닌것 같습니다.

    4.
    <?php for($i = 0; $i < 10; $i++) { ?><div><?php echo $i; ?></div><?php } ?>
    같은 방법으로 작성하시면 됩니다.
  • profile
    이니스프리 2018.09.28 21:24

    입대를 앞두고 바쁘실텐데 네모 님께서 이렇게 댓글을 달아주셔서 정말 감사드립니다!!


    0.

    html 태그를 닫아버리면 안 되는 것이었군요 ㅠㅠ

    아미나 소스를 참고하면서 만들었는데요.

    PHP를 쓰다가 HTML 코드를 쓰고 HTML을 닫아준 후에 다시 PHP를 쓰길래

    저는 그렇게 PHP 시작 전에 HTML을 반드시 닫아줘야 되는 것으로 오해했습니다 ㅜㅜ

    파일의 끝에서 닫아줘야 된다는 말씀이신거죠?

    제가 HTML은 생활코딩 유튜브 강의 들은 것이 전부라서 그런지 기초가 약하네요.

    (강의가 별로라는 의미가 아니라 강의는 이해가 쏙쏙 되게 잘 해주셨는데 제가 연습이 부족했나 보네요 ㅠㅠ)

    더 공부를 열심히 하겠습니다 T.T


    1.

    PHP Simple HTML DOM Parser를 글에서만 접하고 아직 사용해보지 못했는데

    이번 기회에 꼭 사용해보겠습니다 ^^

    감사합니다!!


    2.

    방금 에디터의 환경설정을 확인해보니 인코딩이 '자동인식'으로 되어있네요.

    아무래도 설정상의 문제인 것 같은데 'UTF-8'로 변경하겠습니다 ㅠㅠ


    3.

    미국 유저들이 Owl Carousel 내에 폰트어썸을 잘 사용하고 있던데

    제가 어디에선가 제대로 설정하지 못한 부분이 있는 것 같네요 ㅜㅜ


    4.

    말씀하신 방식으로 for 문 안에 div 태그를 넣어줄 수 있군요!

    제가 미처 그 방법까지 생각을 못했네요 ㅜㅜ


    네모 님 덕분에 많이 배우고 갑니다!!

    번번이 정말 감사합니다 ^-^

  • profile
    네모 2018.09.28 21:37 Files첨부 (1)

    PHP에서 출력되는 값이 없을때는 닫으셔도 됩니다만,

    출력하는 내용이 있다면, HTML 태그 밖에 문자열이 출력되어 문제가 발생합니다.




    거의 대부분의 브라우저에서 HTML 밖의 태그도 출력을 합니다만,

    표준이 아니므로, 해당 코드를 출력하지 않는다고 하여 브라우저가 잘못한 일은 아니라는거죠.

    크롬, FF 등의 브라우저에서, 태그를 닫지 않아도 어느정도 보정이 되는것 처럼,

    브라우저에서 정상적으로 출력을 하기는 해도, 정상적인 코드가 아니므로, 가능하면 출력은 HTML > BODY 안에..!

  • profile
    이니스프리 2018.09.28 21:50
    앗 정말 감사합니다!!
    그림으로 보니깐 이해가 잘 되네요 ^^
    HTML의 body 태그 안에 PHP에서 출력하는 내용까지 담아줘야 되는 것이군요!
    제가 나중에 사이트를 제작할 일이 있으면 꼭 네모 님께 의뢰를 드려야겠네요 ㅎㅎ
    그럼 네모 님께서도 불금 즐겁게 보내세요!
    다시 한 번 진심으로 감사드립니다 (--) (__)
  • profile
    title: 황금 서버 (30일)humit 2018.09.29 15:57
    일단 1에서 simplexml_load_file이 동작하지 않는 이유는 서버에서 allow_fopen_url의 설정 값이 OFF로 되어 있어서 그렇습니다.
    보안상의 문제로 인해 막아놓는 경우가 많으며 이 부분은 직접 호스팅사에 요청을 해서 해제를 하는 방법이 있을 것 같네요.
  • profile
    title: 황금 서버 (30일)humit 2018.09.29 16:01
    그리고 여기에서처럼 단순히 문자열 자체를 비교할 때는 preg_match보다는 strpos를 사용하는 것이 좋습니다.
    http://php.net/manual/kr/function.preg-match.php
    공식 문서에서도 Tip으로 "하나의 문자열이 다른 문자열에 들어있는지 확인하기 위해서 preg_match()를 사용하지 마십시오. 더욱 빠른 strpos()나 strstr()을 사용하십시오."라고 나와있습니다 :)
  • profile
    이니스프리 2018.09.29 16:17
    humit 님께서도 군 복무 중이라 바쁘실텐데 이렇게 허접한 스크립트를 시간 내어 읽어주셔서 정말 감사드립니다!
    여러모로 부족한 스크립트를 올리는 것이 많이 부끄럽지만 humit 님 덕분에 많이 배우게 되네요 ^^

    1. 호스팅 업체측에서 보안상의 이유로 막아놓은 것이었군요.
    제가 연습용으로 닷홈 무료 호스팅을 사용한 것이어서 당장은 큰 불편함이 없지만
    다음에 유료 계정에서 비슷한 문제를 겪으면 말씀해주신대로 해제 요청을 해야겠네요!

    2. 제가 요새 틈틈이 정규식을 공부하다보니 preg_match를 너무 남발한 것 같네요 ㅠㅠ
    이번 주말에 말씀해주신대로 strpos로 수정해보겠습니다!

    그럼 humit 님께서도 좋은 주말 되시고 요새 일교차가 큰데 감기 조심하세요!
    번번이 큰 도움을 주셔서 진심으로 감사드립니다 ^-^
  • profile
    title: 황금 서버 (30일)humit 2018.09.29 16:29
    추가로 1번에서 xpath 함수를 이용하는 방법이 있습니다.
    예제에서처럼 사용한다면 아래와 같이 사용이 가능하겠네요.

    $xml = simplexml_load_string($string);
    $result = $xml->xpath("//description/body/location[1]/data");
  • profile
    이니스프리 2018.09.29 17:06

    XPath() 함수를 이용하면 노드를 보다 쉽게 선택할 수 있군요 ^^

    제가 스크립트를 짜다가 뭔가 이상하다는 느낌이 드는 부분은

    나중에 알고보면 제가 공부가 부족해서 우회적인 방법으로 삽질을 한 경우가 대부분이네요 ㅎㅎ

    프로그래밍 언어의 세계는 저같은 컴맹에게는 정말 심오하네요!

    말씀해주신 XPath()에 대해 공부를 더 하고 스크립트에 반영하여 수정하도록 하겠습니다.

    다시 한 번 진심으로 감사드립니다~

    그럼 humit 님께서도 좋은 주말 되세요!

  • profile
    title: 황금 서버 (30일)humit 2018.09.30 10:21
    네 좋은 코딩하세요~

List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
38 코드 [JS] http를 https로 리디렉션! 3 Hanam09 2018.12.30 674
37 자료 이게 팔릴까 - Xe/라이믹스 에러페이지 [2017-10-04] 3 file title: 열려라 맛스타의 자물쇠TVJ 2017.10.04 671
36 코드 [아미나] 출석 여부를 나타내는 메인화면 위젯 4 file 이니스프리 2018.12.15 666
35 코드 [PHP] 그누보드 자동 게시글 작성 - 일본기상협회의 우리나라 날씨를 크롤링한 후 파파고로 번역하여 글 작성 4 file 이니스프리 2018.11.15 655
34 코드 html 초보가 만든 자소서 4 title: 대한민국 국기gimmepoint 2018.04.21 651
33 코드 Git 저장소에서 자동으로 받아 업데이트하는 쉘 스크립트 5 NoYeah 2017.09.16 650
32 자료 AdBlock 접근 방지 애드온 v0.1 3 file 네모 2017.10.05 648
» 코드 [PHP] 기상청 중기예보를 캐러셀로 보여주는 위젯 (매우 허접합니다 ㅠㅠ) 10 file 이니스프리 2018.09.28 647
30 코드 [Python/Telegram] Studyforus 알림봇 (댓글, 스티커 파싱) 7 file 이니스프리 2020.05.15 644
29 코드 Cmd 에서 서비스 시작 / 종료하기 1 ProjectSE 2018.02.18 644
28 코드 브라우저 언어에 따라 다른 폴더를 사용하는 PHP 코드 4 file 네모 2017.10.10 639
27 자료 Gentelella 레이아웃에 사용가능한 가격 테이블 위젯입니다. 3 file NoYeah 2017.07.03 637
26 코드 [아미나] 게시글을 작성하면 ID와 IP로 필터링하여 자동으로 랜덤 댓글을 남기기 (+랜덤 포인트) 7 file 이니스프리 2018.11.18 634
25 자료 [Bootstrap] xeACE 레이아웃 3 title: 은메달도다 2017.09.17 632
24 코드 [JS]클라이언트에서 Ip를 얻어보자 2 Hanam09 2019.01.21 625
23 자료 경험치 현황 위젯 6 file NoYeah 2017.06.28 622
22 코드 [PHP] 간단한 캐싱 클래스 3 title: 황금 서버 (30일)humit 2018.12.06 605
21 자료 [XE / Rhymix] Bootstrap 패널 위젯 스타일 file title: 은메달도다 2017.08.09 603
20 자료 [1.8a] Bootstrap 'Panel' 위젯 스타일 1 file title: 은메달도다 2017.08.09 602
19 코드 매우 특이한 버그 9 title: 대한민국 국기gimmepoint 2018.06.05 569
Board Pagination Prev 1 2 3 4 Next
/ 4