회사가 서울대 안에 있다보니 점심 때가 되면 서울대 식당으로 식사를 하러 가곤 한다. 그 때마다 드는 생각은 어디로 먹으러 가지? 와 오늘의 메뉴는 무엇이지? 이다. 어느 식당에서 무슨 메뉴를 제공하고 있는지에 대해서는 서울대 생활협동조합 홈페이지에 가면 볼 수 있다. 즐겨찾기에 등록해 놓고 사용하다 보니, 이번에는 이 메뉴들을 RSS로 받아봤으면 좋겠다는 생각이 들었다. 웹페이지를 가져와서 메뉴만 쏙 빼내서 RSS로 보내면 되니 아주 간단할 것 같다. 그런데 막상 해 보려고 아주 간단하지만은 않다. 프로그램을 만들어서 호스팅 할 수 있는 웹서버에 올려야 하고, 도메인도 구해야 한다. 이런 것들이 구글 앱 엔진을 이용하면 아주 간단해진다는 이야기를 들었다.
구글 앱 엔진을 이용하면 도메인과 호스팅을 걱정하지 않아도 된다. 프로그램을 개발하는데만 신경을 쓰면 된다. 개발 환경도 잘 갖추어 놓고 있어서 개발하기도 쉽다. 개발한 내용을 배포하는 것도 아주 쉽다. 게다가 구글에서 제공하는 인프라스트럭쳐를 사용할 수도 있다. 다만 현재는 파이선만을 사용해야 하고, 미국에 호스팅되는 관계로 그다지 빠르지는 않다. 그래도 서울대 식당 메뉴를 RSS로 받아보기 서비스를 만드는 데는 딱 좋을 것 같다.
우선 구글 앱 엔진에 로그인을 하고 애플리케인션을 하나 신청한다. 첫 번째 애플리케이션을 만들 때 SMS를 이용해서 인증을 하는데 전화번호가 010-222-3333 이면 82102223333으로 입력하면 문자가 날라온다. 파이선 2.6을 설치하고 Google App Engine SDK 도 설치한다. Getting Started:Python 문서를 따라하다 보면 아주 손쉽게 helloWorld 서비스를 만들 수 있다.
개발하기
적당한 위치에 디렉토리를 만들고 애플리케이션 이름을 붙여준다. 애플리 케이션 이름을 snulunch라고 하자. 그리고 그 디렉토리에 snulunch.py 와 app.yaml 파일을 만든 후 서버를 실행시킨다.
- dev_appserver.py snulunch
서버를 실행시킨 후 localhost:8080 에 접속하면 결과를 확인할 수 있다. snulunch.py 파일을 수정하면 수정된 내용이 서버를 재시작하지 않아도 곧바로 반영된다. 개발을 마친 후에는 서버에 올리기 위해 다음 명령을 수행한다.
- appcfg.py update snulunch
첫 번째 실행할 때만 계정정보를 물어본다. 계정정보가 맞다면 업로드를 수행한다. 이것으로 끝이다. 인상적으로 쉽다. http://snulunch.appspot.com/ 에서 결과를 확인할 수 있다.
The Webapp Framework
이제 sunlunch.py를 만드는 일만 남았다. 웹서비스를 개발에 있어서 프레임웍을 이용하는 것이 굉장히 효과적이다. 구글 앱 앤진은 Djano같은 파이선을 이용하는 모든 웹 프레임웍을 지원한다고 한다. 그리고 자체적으로 webapp framework도 지원한다. 여기서는 간단하게 webapp 프레임웍을 이용하면 충분할 것 같다.
- from google.appengine.ext import webapp
- import wsgiref.handlers
- import urllib
- from BeautifulSoup import BeautifulSoup
- from time import strftime
- class MenuRss(webapp.RequestHandler):
- def get(self):
- self.response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8'
- date = self.request.get('date').encode("utf-8")
- if(not date) : date = strftime("%Y-%m-%d")
- url = "http://snulunch.appspot.com/menu?date=" + date
- body = urllib.urlopen("http://www.snuco.com/Comuser/restaurant/menu_01.asp?date=" + date).read()
- soup = BeautifulSoup(body)
- menus = str(soup.findAll(cellspacing="1")[0])
- body = urllib.urlopen("http://www.snuco.com/Comuser/restaurant/menu_02.asp?date=" + date).read()
- soup = BeautifulSoup(body)
- menus += str(soup.findAll(cellspacing="1")[0])
- xml = """<?xml version="1.0" encoding="UTF-8"?>
- <rss version="2.0">
- <channel>
- <language>ko-KR</language>
- <title>[SNU] Today's Menu</title>
- <description>menus of restaurants in Seoul National University</description>
- <link>http://snulunch.appspot.com</link>
- <item>
- <title>Menus on %s</title>
- <description><![CDATA[
- """ % (date)
- xml += menus
- xml += """]]>
- </description>
- <pubDate>%s</pubDate>
- <link>%s</link>
- <guid>%s</guid>
- </item>
- </channel>
- </rss>
- """ % (strftime("%Y-%m-%d %H:%M:%S"), url, url)
- self.response.out.write(xml)
- class Menu(webapp.RequestHandler):
- def get(self):
- date = self.request.get('date')
- if(not date) : date = strftime("%Y-%m-%d")
- self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
- body = urllib.urlopen("http://www.snuco.com/Comuser/restaurant/menu_01.asp?date=" + date).read()
- soup = BeautifulSoup(body)
- menus = str(soup.findAll(cellspacing="1")[0])
- body = urllib.urlopen("http://www.snuco.com/Comuser/restaurant/menu_02.asp?date=" + date).read()
- soup = BeautifulSoup(body)
- menus += str(soup.findAll(cellspacing="1")[0])
- self.response.out.write(menus)
- application = webapp.WSGIApplication([
- ('/', Menu),
- ('/menu.rss', MenuRss),
- ('/menu', Menu)
- ], debug=True)
- def main():
- wsgiref.handlers.CGIHandler().run(application)
- if __name__ == '__main__':
- main()
프레임웍이 직관적이고 간단해서 그다지 어렵지 않다. 간단한 설명을 하자면 webapp.WSGIApplication 를 생성하면서 라우팅에 대해서 적어준다. "/"요청은 는 Menu 클래스에 맵핑된다. 그리고 HTTP method가 Menu 클래스의 method와 연결된다. 그래서 GET "/" 요청은 Menu.get 메소드를 호출하게 된다.
HTTP 요청의 파라미터는 self.request.get('PARAM_NAME') 를 통해서 가져올 수 있다.
HTTP header 를 self.response.headers["HEADER_NAME"] = VALUE 를 이용해 설정할 수 있다.
HTTP body 를 self.response.out.write() 를 이용해 채울 수 있다.
이 작업을 하면서 덤으로 파이선과 RSS에 대해서 몇 가지 알게 됬다.
- urllib 를 이용해서 간단하게 url에 해당하는 HTML 문서를 가져올 수 있다.
- BeautifulSoup를 이용해서 손쉽게 HTML 문서를 파싱할 수 있다.
- RSS 문서의 description 안의 HTML 코드는 <![CDATA[ ... ]]> 로 감싸야 제대로 표현된다.
이제 다 됬다. 오늘의 서울대 식당 메뉴를 RSS로 받고 싶다면 http://snulunch.appspot.com/menu.rss 를 리더에 추가하면 된다.
사용해 보니
어려운 점은 역시 파이선이 익숙하지 않다는 것이다. 그것만 제외한다면 개발환경은 충분히 좋았고, 배포하기도 편했다. 덤으로 훌륭한 통계도 보여준다.
'그 밖에..' 카테고리의 다른 글
| RED5 설치와 데모 애플리케이션들 (0) | 2009/04/07 |
|---|---|
| SSH Turneling (0) | 2009/03/24 |
| Google APP Engine 사용하기 (1) | 2009/03/07 |
| NetBeans 유용한 팁들 몇 개 (0) | 2009/02/12 |
| 파이어 폭스 부가기능 Poster - HTTP 요청을 내맘대로. (2) | 2009/02/10 |
| [firefox] profile 이용하기 (0) | 2008/09/04 |