?

단축키

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 코드 파이선 셸에서 실행하면...? 3 제르엘 2018.07.22 609
37 코드 [Python] 모 정부기관 사이트 파싱 후 PC 통신처럼 열람하고 싶은 게시글 번호를 입력하면 내용을 보여주는 소스 (허접) 4 이니스프리 2018.09.14 754
36 코드 [오토핫키] 특정 사이트에 대한 ping 테스트 결과를 실행시간과 함께 로그 파일로 저장하는 스크립트 2 이니스프리 2018.09.22 2102
35 코드 [오토핫키] 구글 드라이브의 공유링크를 이미지 호스팅을 위한 다이렉트 링크로 바꿔주는 스크립트 10 file 이니스프리 2018.09.25 1777
» 코드 [PHP] 기상청 중기예보를 캐러셀로 보여주는 위젯 (매우 허접합니다 ㅠㅠ) 10 file 이니스프리 2018.09.28 756
33 코드 [오토핫키] 브라우저를 열어 지난번과 동일한 폴더에 MZK를 다운받고 압축을 네이티브로 해제하는 스크립트 file 이니스프리 2018.10.20 928
32 코드 [PHP] 기상청 RSS 시간별 예보 위젯 - cache 적용(?) 9 file 이니스프리 2018.10.28 1003
31 코드 [PHP] 그누보드 자동 게시글 작성 - 일본기상협회의 우리나라 날씨를 크롤링한 후 파파고로 번역하여 글 작성 4 file 이니스프리 2018.11.15 842
30 코드 [아미나] 게시글을 작성하면 ID와 IP로 필터링하여 자동으로 랜덤 댓글을 남기기 (+랜덤 포인트) 7 file 이니스프리 2018.11.18 811
29 코드 [Python] 텔레그램을 이용한 게시판 새 글 알림봇 7 이니스프리 2018.12.02 4029
28 코드 [PHP] 간단한 캐싱 클래스 3 title: 황금 서버 (30일)humit 2018.12.06 882
27 코드 [아미나] 출석 여부를 나타내는 메인화면 위젯 4 file 이니스프리 2018.12.15 810
26 코드 [아미나] 네이트 실시간 검색어 순위 위젯 (아미나 캐시 적용) 3 file 이니스프리 2018.12.18 1134
25 코드 [PHP] 이미지를 원하는 크기(원본비율 유지)로 리사이즈 하여 출력 (원본 이미지는 수정하지 않습니다) 6 이니스프리 2018.12.20 8016
24 코드 [JS] http를 https로 리디렉션! 3 Hanam09 2018.12.30 883
23 코드 [JS]클라이언트에서 Ip를 얻어보자 2 Hanam09 2019.01.21 807
22 코드 [Python] 선택한 파일을 Dropbox API를 이용하여 업로드하고 공유링크를 받아서 이미지 호스팅 용도로 URL을 변환하기 1 file 이니스프리 2019.07.02 1190
21 코드 [Python] Selenium을 이용하여 특정 element를 캡처하는 스크립트 2 file 이니스프리 2019.07.03 6168
20 코드 [PHP/Javascript] 아미나에 자동으로 게시글을 생성하고 Ajax로 전송하여 결과를 표시하기 2 file 이니스프리 2019.07.09 963
19 코드 [Python] 네이버 모바일 이미지 검색에서의 이미지 파일을 멀티스레드로 다운받고 1개의 파일로 병합 11 file 이니스프리 2019.07.12 1557
Board Pagination Prev 1 2 3 4 Next
/ 4